implement delta update for erc20

This commit is contained in:
Michele Balistreri 2023-10-26 20:38:34 +09:00
parent 7f32cb5d2f
commit 9064c90b72
No known key found for this signature in database
GPG Key ID: E9567DA33A4F791A
4 changed files with 125 additions and 6 deletions

View File

@ -32,7 +32,7 @@ static app_err_t updater_database_update(uint8_t* data, size_t len) {
return ERR_DATA; return ERR_DATA;
} }
if (eth_db_update((fs_entry_t *) data, len - SIG_LEN) != ERR_OK) { if (eth_db_update(data, len - SIG_LEN) != ERR_OK) {
ui_info(LSTR(INFO_ERROR_TITLE), LSTR(INFO_DB_UPDATE_ERROR), 1); ui_info(LSTR(INFO_ERROR_TITLE), LSTR(INFO_DB_UPDATE_ERROR), 1);
return ERR_DATA; return ERR_DATA;
} else { } else {

View File

@ -11,7 +11,8 @@ typedef enum {
ERR_HW, ERR_HW,
ERR_UNSUPPORTED, ERR_UNSUPPORTED,
ERR_NEED_MORE_DATA, ERR_NEED_MORE_DATA,
ERR_FULL ERR_FULL,
ERR_VERSION
} app_err_t; } app_err_t;
#endif #endif

View File

@ -4,6 +4,7 @@
#define FS_CHAIN_MAGIC 0x4348 #define FS_CHAIN_MAGIC 0x4348
#define FS_ERC20_MAGIC 0x3020 #define FS_ERC20_MAGIC 0x3020
#define FS_VERSION_MAGIC 0x4532 #define FS_VERSION_MAGIC 0x4532
#define FS_DELTA_MAGIC 0x444c
#define ERC20_NET_LEN 24 #define ERC20_NET_LEN 24
@ -24,6 +25,20 @@ struct __attribute__((packed)) version_desc {
uint32_t version; uint32_t version;
}; };
struct __attribute__((packed)) delta_desc {
uint16_t magic;
uint32_t old_version;
uint16_t erase_chain_len;
uint16_t erase_token_len;
uint8_t data[];
};
struct delta_erase_ctx {
uint8_t* erase_chain;
uint8_t* erase_token;
uint16_t erase_chain_len;
uint16_t erase_token_len;
};
fs_action_t _eth_db_match_chain(void* ctx, fs_entry_t* entry) { fs_action_t _eth_db_match_chain(void* ctx, fs_entry_t* entry) {
if (entry->magic != FS_CHAIN_MAGIC) { if (entry->magic != FS_CHAIN_MAGIC) {
@ -66,6 +81,57 @@ fs_action_t _eth_db_match_all(void* ctx, fs_entry_t* entry) {
return ((entry->magic == FS_CHAIN_MAGIC) || (entry->magic == FS_ERC20_MAGIC) || (entry->magic == FS_VERSION_MAGIC)) ? FS_REJECT : FS_ACCEPT; return ((entry->magic == FS_CHAIN_MAGIC) || (entry->magic == FS_ERC20_MAGIC) || (entry->magic == FS_VERSION_MAGIC)) ? FS_REJECT : FS_ACCEPT;
} }
static inline fs_action_t _eth_db_match_erase_chain(struct delta_erase_ctx* ctx, struct chain_raw_desc* entry) {
for (int i = 0; i < ctx->erase_chain_len; i += 4) {
if (!memcmp(&entry->chain_id, &ctx->erase_chain[i], 4)) {
return FS_REJECT;
}
}
return FS_ACCEPT;
}
static inline fs_action_t _eth_db_match_erase_token(struct delta_erase_ctx* ctx, struct erc20_raw_desc* entry) {
uint8_t* ticker = entry->data + (entry->net_count * ERC20_NET_LEN) + 1;
size_t off = 0;
while (off < ctx->erase_token_len) {
size_t ticker_off = 0;
while(1) {
if (ticker[ticker_off] != ctx->erase_token[off]) {
while(ctx->erase_token[off++] != '\0') {
continue;
}
break;
}
if (ticker[ticker_off] == '\0') {
return FS_REJECT;
}
ticker_off++;
off++;
}
}
return FS_ACCEPT;
}
fs_action_t _eth_db_match_delta(void* ctx, fs_entry_t* entry) {
switch(entry->magic) {
case FS_VERSION_MAGIC:
return FS_REJECT;
case FS_CHAIN_MAGIC:
return _eth_db_match_erase_chain((struct delta_erase_ctx*) ctx, (struct chain_raw_desc*) entry);
case FS_ERC20_MAGIC:
return _eth_db_match_erase_token((struct delta_erase_ctx*) ctx, (struct erc20_raw_desc*) entry);
default:
return FS_ACCEPT;
}
}
app_err_t eth_db_lookup_chain(chain_desc_t* chain) { app_err_t eth_db_lookup_chain(chain_desc_t* chain) {
struct chain_raw_desc* chain_data = (struct chain_raw_desc*) fs_find(_eth_db_match_chain, chain); struct chain_raw_desc* chain_data = (struct chain_raw_desc*) fs_find(_eth_db_match_chain, chain);
@ -106,11 +172,10 @@ app_err_t eth_db_lookup_version(uint32_t* version) {
return ERR_OK; return ERR_OK;
} }
app_err_t eth_db_update(fs_entry_t* entries, size_t len) { static app_err_t eth_full_db_rewrite(fs_entry_t* entries, size_t len) {
app_err_t err = fs_erase_all(_eth_db_match_all, NULL); app_err_t err = fs_erase_all(_eth_db_match_all, NULL);
// since our matcher doesn't know when it has reached // since our matcher doesn't know when it has reached completion, if everything went OK the error code
// completion, if everything went OK the error code
// will be ERR_DATA on success. // will be ERR_DATA on success.
if (err != ERR_DATA) { if (err != ERR_DATA) {
return err; return err;
@ -118,3 +183,56 @@ app_err_t eth_db_update(fs_entry_t* entries, size_t len) {
return fs_write(entries, len); return fs_write(entries, len);
} }
static app_err_t eth_delta_db_update(struct delta_desc* delta, size_t len) {
uint32_t version;
if (eth_db_lookup_version(&version) != ERR_OK) {
return ERR_HW;
}
if (delta->old_version != version) {
return ERR_VERSION;
}
struct delta_erase_ctx erase_ctx = {
.erase_chain = &delta->data[0],
.erase_token = &delta->data[delta->erase_chain_len],
.erase_chain_len = delta->erase_chain_len,
.erase_token_len = delta->erase_token_len
};
fs_entry_t* entries = (fs_entry_t*) &delta->data[delta->erase_chain_len + delta->erase_token_len];
size_t off = sizeof(struct delta_desc) + delta->erase_chain_len + delta->erase_token_len;
if (off > len) {
return ERR_DATA;
}
app_err_t err = fs_erase_all(_eth_db_match_delta, &erase_ctx);
// since our matcher doesn't know when it has reached completion, if everything went OK the error code
// will be ERR_DATA on success. This could be optimized if noticeable delays are observed.
if (err != ERR_DATA) {
return err;
}
return fs_write(entries, (len - off));
}
app_err_t eth_db_update(uint8_t* data, size_t len) {
if (len < 1) {
return ERR_DATA;
}
uint16_t magic = data[0] | (data[1] << 8);
switch(magic) {
case FS_VERSION_MAGIC:
return eth_full_db_rewrite((fs_entry_t*) data, len);
case FS_DELTA_MAGIC:
return eth_delta_db_update((struct delta_desc*) data, len);
default:
return ERR_UNSUPPORTED;
}
}

View File

@ -21,6 +21,6 @@ typedef struct {
app_err_t eth_db_lookup_chain(chain_desc_t* chain); app_err_t eth_db_lookup_chain(chain_desc_t* chain);
app_err_t eth_db_lookup_erc20(erc20_desc_t* erc20); app_err_t eth_db_lookup_erc20(erc20_desc_t* erc20);
app_err_t eth_db_lookup_version(uint32_t* version); app_err_t eth_db_lookup_version(uint32_t* version);
app_err_t eth_db_update(fs_entry_t* entries, size_t len); app_err_t eth_db_update(uint8_t* data, size_t len);
#endif #endif