Skip to content

Commit a3c5342

Browse files
authored
Merge pull request #241 from Zondax/feat/dynamic_parser
Improve optionals handling
2 parents d004ea1 + 6498d39 commit a3c5342

File tree

12 files changed

+68
-43
lines changed

12 files changed

+68
-43
lines changed

app/Makefile.version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ APPVERSION_M=3
33
# This is the minor version of this release
44
APPVERSION_N=0
55
# This is the patch version of this release
6-
APPVERSION_P=2
6+
APPVERSION_P=3

app/src/candid/candid_parser.c

Lines changed: 56 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
// Good reference: https://github.com/dfinity/agent-js/tree/main/packages/candid
2525
// https://github.com/dfinity/candid/blob/master/spec/Candid.md#deserialisation
2626

27+
#define MAX_FIELDS 25
28+
#define TYPE_OPT 0
29+
#define TYPE_NEURONS_IDS 1
30+
#define TYPE_CALLER 2
2731

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

7377
CHECK_PARSER_ERR(readCandidRecordLength(&txn))
74-
if (txn.txn_length != 3) {
78+
// at least we need to have the 2 non opt fields already defined in the did file
79+
if (txn.txn_length < 2) {
7580
return parser_unexpected_value;
7681
}
77-
txn.element.variant_index = 0;
78-
CHECK_PARSER_ERR(readCandidInnerElement(&txn, &txn.element))
79-
if (txn.element.field_hash != hash_neuron_ids) {
80-
return parser_unexpected_type;
81-
}
82-
83-
// reset txn
84-
CHECK_PARSER_ERR(getCandidTypeFromTable(&txn, tx->candid_rootType))
85-
CHECK_PARSER_ERR(readCandidRecordLength(&txn))
86-
87-
txn.element.variant_index = 1;
88-
CHECK_PARSER_ERR(readCandidInnerElement(&txn, &txn.element))
89-
CHECK_PARSER_ERR(getCandidTypeFromTable(&txn, txn.element.implementation))
90-
CHECK_PARSER_ERR(readCandidOptional(&txn))
91-
if (txn.element.implementation != Bool) {
92-
return parser_unexpected_type;
93-
}
94-
95-
// reset txn
96-
CHECK_PARSER_ERR(getCandidTypeFromTable(&txn, tx->candid_rootType))
97-
CHECK_PARSER_ERR(readCandidRecordLength(&txn))
98-
99-
txn.element.variant_index = 2;
100-
CHECK_PARSER_ERR(readCandidInnerElement(&txn, &txn.element))
101-
if (txn.element.field_hash != hash_include_neurons_readable_by_caller ||
102-
txn.element.implementation != Bool) {
103-
return parser_unexpected_type;
82+
uint64_t n_fields = txn.txn_length;
83+
84+
//Array to save opt fields positon in the record
85+
uint8_t opt_fields_pos[MAX_FIELDS] = {0};
86+
87+
// Check types before parsing
88+
for (uint64_t i = 0; i < n_fields; i++){
89+
//reset txn
90+
CHECK_PARSER_ERR(getCandidTypeFromTable(&txn, tx->candid_rootType))
91+
CHECK_PARSER_ERR(readCandidRecordLength(&txn))
92+
//jump to index
93+
txn.element.variant_index = i;
94+
CHECK_PARSER_ERR(readCandidInnerElement(&txn, &txn.element))
95+
96+
//element is not any of the non opt expected fields than its probably an optinal
97+
if (txn.element.field_hash == hash_neuron_ids) {
98+
opt_fields_pos[i] = TYPE_NEURONS_IDS;
99+
} else if (txn.element.field_hash == hash_include_neurons_readable_by_caller &&
100+
txn.element.implementation == Bool) {
101+
opt_fields_pos[i] = TYPE_CALLER;
102+
} else {
103+
CHECK_PARSER_ERR(getCandidTypeFromTable(&txn, txn.element.implementation))
104+
// Check that is an opt(inside the function) if not return error, not an expected type
105+
CHECK_PARSER_ERR(readCandidOptional(&txn))
106+
opt_fields_pos[i] = TYPE_OPT;
107+
}
104108
}
105109

106110
// let's read
107111
candid_ListNeurons_t *val = &tx->tx_fields.call.data.candid_listNeurons;
108112
uint64_t tmp_neuron_id = 0;
109-
CHECK_PARSER_ERR(readCandidByte(&ctx, &val->neuron_ids_size))
110-
111-
val->neuron_ids_ptr = ctx.buffer + ctx.offset;
112-
for (uint8_t i = 0; i < val->neuron_ids_size; i++) {
113-
CHECK_PARSER_ERR(readCandidNat64(&ctx, &tmp_neuron_id))
114-
}
115-
116-
CHECK_PARSER_ERR(readCandidByte(&ctx, &val->has_include_empty_neurons_readable_by_caller))
117-
if(val->has_include_empty_neurons_readable_by_caller) {
118-
CHECK_PARSER_ERR(readCandidByte(&ctx, &val->include_empty_neurons_readable_by_caller))
113+
uint8_t tmp_presence = 0;
114+
for( uint64_t i = 0; i < n_fields; i++) {
115+
// If opt_fields_pos is 0 we have a opt field in this position
116+
switch (opt_fields_pos[i]) {
117+
case TYPE_OPT: // read the optinal, expect its null or empty if not return error
118+
CHECK_PARSER_ERR(readCandidByte(&ctx, &tmp_presence))
119+
if(tmp_presence){ //expect empty optionals
120+
return parser_unexpected_value;
121+
}
122+
break;
123+
case TYPE_NEURONS_IDS: //read number os ids
124+
CHECK_PARSER_ERR(readCandidByte(&ctx, &val->neuron_ids_size))
125+
126+
val->neuron_ids_ptr = ctx.buffer + ctx.offset;
127+
for (uint8_t j = 0; j < val->neuron_ids_size; j++) {
128+
CHECK_PARSER_ERR(readCandidNat64(&ctx, &tmp_neuron_id))
129+
}
130+
break;
131+
case TYPE_CALLER: // read bool
132+
CHECK_PARSER_ERR(readCandidByte(&ctx, &val->include_neurons_readable_by_caller))
133+
break;
134+
default:
135+
return parser_unexpected_value;
136+
}
119137
}
120138

121-
CHECK_PARSER_ERR(readCandidByte(&ctx, &val->include_neurons_readable_by_caller))
122139
return parser_ok;
123140
}
124141

tests/phase2.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@
469469
},
470470
{
471471
"index": 200,
472-
"name": "List Neurons",
472+
"name": "List Neurons empty opt",
473473
"blob": "d9d9f7a167636f6e74656e74a66361726758224449444c036d786e7e6c03acbe9cc50700ccd2d3bf0c01dabcd1c70d7e01020000016b63616e69737465725f69644a000000000000000101016e696e67726573735f6578706972791b17e4dd23029fe8006b6d6574686f645f6e616d656c6c6973745f6e6575726f6e736c726571756573745f747970656463616c6c6673656e646572581d19aa3d42c048dd7d14f0cfa0df69a1c1381780f6e9a137abaa6a82e302",
474474
"output": ["0 | Transaction type : List Own Neurons"],
475475
"output_expert": ["0 | Transaction type : List Own Neurons"],
@@ -478,7 +478,7 @@
478478
{
479479
"index": 201,
480480
"name": "List Neurons",
481-
"blob": "d9d9f7a167636f6e74656e74a66361726758334449444c036d786e7e6c03acbe9cc50700ccd2d3bf0c01dabcd1c70d7e01020200c8c056ea395dd500406c4830c8a17a0101006b63616e69737465725f69644a000000000000000101016e696e67726573735f6578706972791b17e4dd23029fe8006b6d6574686f645f6e616d656c6c6973745f6e6575726f6e736c726571756573745f747970656463616c6c6673656e646572581d19aa3d42c048dd7d14f0cfa0df69a1c1381780f6e9a137abaa6a82e302",
481+
"blob": "d9d9f7a167636f6e74656e74a66361726758324449444c036d786e7e6c03acbe9cc50700ccd2d3bf0c01dabcd1c70d7e01020200c8c056ea395dd500406c4830c8a17a00006b63616e69737465725f69644a000000000000000101016e696e67726573735f6578706972791b17e4dd23029fe8006b6d6574686f645f6e616d656c6c6973745f6e6575726f6e736c726571756573745f747970656463616c6c6673656e646572581d19aa3d42c048dd7d14f0cfa0df69a1c1381780f6e9a137abaa6a82e302",
482482
"output": [
483483
"0 | Transaction type : List Own Neurons",
484484
"1 | Neuron ID 1 : 15374508381553346560",
@@ -1204,5 +1204,13 @@
12041204
"4 | Followees (2/3) : 3141242222",
12051205
"5 | Followees (3/3) : 8836564053576663040"
12061206
]
1207+
},
1208+
{
1209+
"index": 376,
1210+
"name": "List Neurons no opt",
1211+
"blob": "d9d9f7a167636f6e74656e74a66361726758194449444c026d786c02acbe9cc50700dabcd1c70d7e010100016b63616e69737465725f69644a000000000000000101016e696e67726573735f6578706972791b1717844f7cfe21c06b6d6574686f645f6e616d656c6c6973745f6e6575726f6e736c726571756573745f747970656463616c6c6673656e6465724104",
1212+
"output": ["0 | Transaction type : List Own Neurons"],
1213+
"output_expert": ["0 | Transaction type : List Own Neurons"],
1214+
"valid": true
12071215
}
12081216
]
-144 Bytes
Loading
-6 Bytes
Loading
-6 Bytes
Loading
-7 Bytes
Loading
-7 Bytes
Loading
-126 Bytes
Loading
-7 Bytes
Loading

0 commit comments

Comments
 (0)