Skip to content

Commit

Permalink
Merge pull request #241 from Zondax/feat/dynamic_parser
Browse files Browse the repository at this point in the history
Improve optionals handling
  • Loading branch information
chcmedeiros authored Aug 28, 2024
2 parents d004ea1 + 6498d39 commit a3c5342
Show file tree
Hide file tree
Showing 12 changed files with 68 additions and 43 deletions.
2 changes: 1 addition & 1 deletion app/Makefile.version
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ APPVERSION_M=3
# This is the minor version of this release
APPVERSION_N=0
# This is the patch version of this release
APPVERSION_P=2
APPVERSION_P=3
95 changes: 56 additions & 39 deletions app/src/candid/candid_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
// Good reference: https://github.com/dfinity/agent-js/tree/main/packages/candid
// https://github.com/dfinity/candid/blob/master/spec/Candid.md#deserialisation

#define MAX_FIELDS 25
#define TYPE_OPT 0
#define TYPE_NEURONS_IDS 1
#define TYPE_CALLER 2

#define CREATE_CTX(__CTX, __TX, __INPUT, __INPUT_SIZE) \
parser_context_t __CTX; \
Expand Down Expand Up @@ -71,54 +75,67 @@ parser_error_t readCandidListNeurons(parser_tx_t *tx, const uint8_t *input, uint
CHECK_PARSER_ERR(getCandidTypeFromTable(&txn, tx->candid_rootType))

CHECK_PARSER_ERR(readCandidRecordLength(&txn))
if (txn.txn_length != 3) {
// at least we need to have the 2 non opt fields already defined in the did file
if (txn.txn_length < 2) {
return parser_unexpected_value;
}
txn.element.variant_index = 0;
CHECK_PARSER_ERR(readCandidInnerElement(&txn, &txn.element))
if (txn.element.field_hash != hash_neuron_ids) {
return parser_unexpected_type;
}

// reset txn
CHECK_PARSER_ERR(getCandidTypeFromTable(&txn, tx->candid_rootType))
CHECK_PARSER_ERR(readCandidRecordLength(&txn))

txn.element.variant_index = 1;
CHECK_PARSER_ERR(readCandidInnerElement(&txn, &txn.element))
CHECK_PARSER_ERR(getCandidTypeFromTable(&txn, txn.element.implementation))
CHECK_PARSER_ERR(readCandidOptional(&txn))
if (txn.element.implementation != Bool) {
return parser_unexpected_type;
}

// reset txn
CHECK_PARSER_ERR(getCandidTypeFromTable(&txn, tx->candid_rootType))
CHECK_PARSER_ERR(readCandidRecordLength(&txn))

txn.element.variant_index = 2;
CHECK_PARSER_ERR(readCandidInnerElement(&txn, &txn.element))
if (txn.element.field_hash != hash_include_neurons_readable_by_caller ||
txn.element.implementation != Bool) {
return parser_unexpected_type;
uint64_t n_fields = txn.txn_length;

//Array to save opt fields positon in the record
uint8_t opt_fields_pos[MAX_FIELDS] = {0};

// Check types before parsing
for (uint64_t i = 0; i < n_fields; i++){
//reset txn
CHECK_PARSER_ERR(getCandidTypeFromTable(&txn, tx->candid_rootType))
CHECK_PARSER_ERR(readCandidRecordLength(&txn))
//jump to index
txn.element.variant_index = i;
CHECK_PARSER_ERR(readCandidInnerElement(&txn, &txn.element))

//element is not any of the non opt expected fields than its probably an optinal
if (txn.element.field_hash == hash_neuron_ids) {
opt_fields_pos[i] = TYPE_NEURONS_IDS;
} else if (txn.element.field_hash == hash_include_neurons_readable_by_caller &&
txn.element.implementation == Bool) {
opt_fields_pos[i] = TYPE_CALLER;
} else {
CHECK_PARSER_ERR(getCandidTypeFromTable(&txn, txn.element.implementation))
// Check that is an opt(inside the function) if not return error, not an expected type
CHECK_PARSER_ERR(readCandidOptional(&txn))
opt_fields_pos[i] = TYPE_OPT;
}
}

// let's read
candid_ListNeurons_t *val = &tx->tx_fields.call.data.candid_listNeurons;
uint64_t tmp_neuron_id = 0;
CHECK_PARSER_ERR(readCandidByte(&ctx, &val->neuron_ids_size))

val->neuron_ids_ptr = ctx.buffer + ctx.offset;
for (uint8_t i = 0; i < val->neuron_ids_size; i++) {
CHECK_PARSER_ERR(readCandidNat64(&ctx, &tmp_neuron_id))
}

CHECK_PARSER_ERR(readCandidByte(&ctx, &val->has_include_empty_neurons_readable_by_caller))
if(val->has_include_empty_neurons_readable_by_caller) {
CHECK_PARSER_ERR(readCandidByte(&ctx, &val->include_empty_neurons_readable_by_caller))
uint8_t tmp_presence = 0;
for( uint64_t i = 0; i < n_fields; i++) {
// If opt_fields_pos is 0 we have a opt field in this position
switch (opt_fields_pos[i]) {
case TYPE_OPT: // read the optinal, expect its null or empty if not return error
CHECK_PARSER_ERR(readCandidByte(&ctx, &tmp_presence))
if(tmp_presence){ //expect empty optionals
return parser_unexpected_value;
}
break;
case TYPE_NEURONS_IDS: //read number os ids
CHECK_PARSER_ERR(readCandidByte(&ctx, &val->neuron_ids_size))

val->neuron_ids_ptr = ctx.buffer + ctx.offset;
for (uint8_t j = 0; j < val->neuron_ids_size; j++) {
CHECK_PARSER_ERR(readCandidNat64(&ctx, &tmp_neuron_id))
}
break;
case TYPE_CALLER: // read bool
CHECK_PARSER_ERR(readCandidByte(&ctx, &val->include_neurons_readable_by_caller))
break;
default:
return parser_unexpected_value;
}
}

CHECK_PARSER_ERR(readCandidByte(&ctx, &val->include_neurons_readable_by_caller))
return parser_ok;
}

Expand Down
12 changes: 10 additions & 2 deletions tests/phase2.json
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@
},
{
"index": 200,
"name": "List Neurons",
"name": "List Neurons empty opt",
"blob": "d9d9f7a167636f6e74656e74a66361726758224449444c036d786e7e6c03acbe9cc50700ccd2d3bf0c01dabcd1c70d7e01020000016b63616e69737465725f69644a000000000000000101016e696e67726573735f6578706972791b17e4dd23029fe8006b6d6574686f645f6e616d656c6c6973745f6e6575726f6e736c726571756573745f747970656463616c6c6673656e646572581d19aa3d42c048dd7d14f0cfa0df69a1c1381780f6e9a137abaa6a82e302",
"output": ["0 | Transaction type : List Own Neurons"],
"output_expert": ["0 | Transaction type : List Own Neurons"],
Expand All @@ -478,7 +478,7 @@
{
"index": 201,
"name": "List Neurons",
"blob": "d9d9f7a167636f6e74656e74a66361726758334449444c036d786e7e6c03acbe9cc50700ccd2d3bf0c01dabcd1c70d7e01020200c8c056ea395dd500406c4830c8a17a0101006b63616e69737465725f69644a000000000000000101016e696e67726573735f6578706972791b17e4dd23029fe8006b6d6574686f645f6e616d656c6c6973745f6e6575726f6e736c726571756573745f747970656463616c6c6673656e646572581d19aa3d42c048dd7d14f0cfa0df69a1c1381780f6e9a137abaa6a82e302",
"blob": "d9d9f7a167636f6e74656e74a66361726758324449444c036d786e7e6c03acbe9cc50700ccd2d3bf0c01dabcd1c70d7e01020200c8c056ea395dd500406c4830c8a17a00006b63616e69737465725f69644a000000000000000101016e696e67726573735f6578706972791b17e4dd23029fe8006b6d6574686f645f6e616d656c6c6973745f6e6575726f6e736c726571756573745f747970656463616c6c6673656e646572581d19aa3d42c048dd7d14f0cfa0df69a1c1381780f6e9a137abaa6a82e302",
"output": [
"0 | Transaction type : List Own Neurons",
"1 | Neuron ID 1 : 15374508381553346560",
Expand Down Expand Up @@ -1204,5 +1204,13 @@
"4 | Followees (2/3) : 3141242222",
"5 | Followees (3/3) : 8836564053576663040"
]
},
{
"index": 376,
"name": "List Neurons no opt",
"blob": "d9d9f7a167636f6e74656e74a66361726758194449444c026d786c02acbe9cc50700dabcd1c70d7e010100016b63616e69737465725f69644a000000000000000101016e696e67726573735f6578706972791b1717844f7cfe21c06b6d6574686f645f6e616d656c6c6973745f6e6575726f6e736c726571756573745f747970656463616c6c6673656e6465724104",
"output": ["0 | Transaction type : List Own Neurons"],
"output_expert": ["0 | Transaction type : List Own Neurons"],
"valid": true
}
]
Binary file modified tests_zemu/snapshots/fl-mainmenu/00004.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests_zemu/snapshots/s-mainmenu/00004.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests_zemu/snapshots/s-mainmenu/00010.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests_zemu/snapshots/sp-mainmenu/00004.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests_zemu/snapshots/sp-mainmenu/00010.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests_zemu/snapshots/st-mainmenu/00004.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests_zemu/snapshots/x-mainmenu/00004.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests_zemu/snapshots/x-mainmenu/00010.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion tests_zemu/tests/candid.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const CANDID_TRANSACTIONS = [
},
{
name: 'candid_list_neurons',
blob: 'd9d9f7a167636f6e74656e74a66361726758334449444c036d786e7e6c03acbe9cc50700ccd2d3bf0c01dabcd1c70d7e01020200c8c056ea395dd500406c4830c8a17a0101006b63616e69737465725f69644a000000000000000101016e696e67726573735f6578706972791b17e4dd23029fe8006b6d6574686f645f6e616d656c6c6973745f6e6575726f6e736c726571756573745f747970656463616c6c6673656e646572581d19aa3d42c048dd7d14f0cfa0df69a1c1381780f6e9a137abaa6a82e302',
blob: 'd9d9f7a167636f6e74656e74a66361726758324449444c036d786e7e6c03acbe9cc50700ccd2d3bf0c01dabcd1c70d7e01020200c8c056ea395dd500406c4830c8a17a00006b63616e69737465725f69644a000000000000000101016e696e67726573735f6578706972791b17e4dd23029fe8006b6d6574686f645f6e616d656c6c6973745f6e6575726f6e736c726571756573745f747970656463616c6c6673656e646572581d19aa3d42c048dd7d14f0cfa0df69a1c1381780f6e9a137abaa6a82e302',
},
{
name: 'candid_stake_maturity',
Expand Down

0 comments on commit a3c5342

Please sign in to comment.