|
24 | 24 | // Good reference: https://github.com/dfinity/agent-js/tree/main/packages/candid
|
25 | 25 | // https://github.com/dfinity/candid/blob/master/spec/Candid.md#deserialisation
|
26 | 26 |
|
| 27 | +#define MAX_FIELDS 25 |
| 28 | +#define TYPE_OPT 0 |
| 29 | +#define TYPE_NEURONS_IDS 1 |
| 30 | +#define TYPE_CALLER 2 |
27 | 31 |
|
28 | 32 | #define CREATE_CTX(__CTX, __TX, __INPUT, __INPUT_SIZE) \
|
29 | 33 | parser_context_t __CTX; \
|
@@ -71,54 +75,67 @@ parser_error_t readCandidListNeurons(parser_tx_t *tx, const uint8_t *input, uint
|
71 | 75 | CHECK_PARSER_ERR(getCandidTypeFromTable(&txn, tx->candid_rootType))
|
72 | 76 |
|
73 | 77 | 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) { |
75 | 80 | return parser_unexpected_value;
|
76 | 81 | }
|
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 | + } |
104 | 108 | }
|
105 | 109 |
|
106 | 110 | // let's read
|
107 | 111 | candid_ListNeurons_t *val = &tx->tx_fields.call.data.candid_listNeurons;
|
108 | 112 | 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 | + } |
119 | 137 | }
|
120 | 138 |
|
121 |
| - CHECK_PARSER_ERR(readCandidByte(&ctx, &val->include_neurons_readable_by_caller)) |
122 | 139 | return parser_ok;
|
123 | 140 | }
|
124 | 141 |
|
|
0 commit comments