Skip to content

Commit 0ae02d5

Browse files
authored
Merge pull request #1 from onflow/multi-chain-test-cases
Add support for multiple networks (Flow Emulator, Flow Testnet, Flow Mainnet)
2 parents ee2c59d + 6ddf651 commit 0ae02d5

File tree

198 files changed

+2454
-1852
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

198 files changed

+2454
-1852
lines changed

app/src/coin_script_hashes.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,13 @@
1919
extern "C" {
2020
#endif
2121

22-
#define CONTRACT_HASH_TOKEN_TRANSFER "ca80b628d985b358ae1cb136bcd976997c942fa10dbabfeafb4e20fa66a5a5e2"
2322
#define CONTRACT_HASH_CREATE_ACCOUNT "eef2d0494448554177612e63026256258339230cbc6931ded78d6149443c6173"
2423
#define CONTRACT_HASH_ADD_NEW_KEY "595c86561441b32b2b91ee03f9e10ca6efa7b41bcc994f51317ec0aa9d8f8a42"
2524

25+
#define CONTRACT_HASH_TOKEN_TRANSFER_EMULATOR "ca80b628d985b358ae1cb136bcd976997c942fa10dbabfeafb4e20fa66a5a5e2"
26+
#define CONTRACT_HASH_TOKEN_TRANSFER_TESTNET "d56f4e1d2355cdcfacfd01e471459c6ef168bfdf84371a685ccf31cf3cdedc2d"
27+
#define CONTRACT_HASH_TOKEN_TRANSFER_MAINNET "47851586d962335e3f7d9e5d11a4c527ee4b5fd1c3895e3ce1b9c2821f60b166"
28+
2629
#ifdef __cplusplus
2730
}
2831
#endif

app/src/parser.c

+141-27
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,105 @@ parser_error_t parser_getNumItems(const parser_context_t *ctx, uint8_t *num_item
7171
return parser_ok;
7272
}
7373

74+
// based on Dapper provided code at https://github.com/onflow/flow-go-sdk/blob/96796f0cabc1847d7879a5230ab55fd3cdd41ae8/address.go#L286
75+
76+
const uint16_t linearCodeN = 64;
77+
const uint64_t codeword_mainnet = 0;
78+
const uint64_t codeword_testnet = 0x6834ba37b3980209;
79+
const uint64_t codeword_emulatornet = 0x1cb159857af02018;
80+
81+
const uint32_t parityCheckMatrixColumns[] = {
82+
0x00001, 0x00002, 0x00004, 0x00008,
83+
0x00010, 0x00020, 0x00040, 0x00080,
84+
0x00100, 0x00200, 0x00400, 0x00800,
85+
0x01000, 0x02000, 0x04000, 0x08000,
86+
0x10000, 0x20000, 0x40000, 0x7328d,
87+
0x6689a, 0x6112f, 0x6084b, 0x433fd,
88+
0x42aab, 0x41951, 0x233ce, 0x22a81,
89+
0x21948, 0x1ef60, 0x1deca, 0x1c639,
90+
0x1bdd8, 0x1a535, 0x194ac, 0x18c46,
91+
0x1632b, 0x1529b, 0x14a43, 0x13184,
92+
0x12942, 0x118c1, 0x0f812, 0x0e027,
93+
0x0d00e, 0x0c83c, 0x0b01d, 0x0a831,
94+
0x0982b, 0x07034, 0x0682a, 0x05819,
95+
0x03807, 0x007d2, 0x00727, 0x0068e,
96+
0x0067c, 0x0059d, 0x004eb, 0x003b4,
97+
0x0036a, 0x002d9, 0x001c7, 0x0003f,
98+
};
99+
100+
bool validateChainAddress(uint64_t chainCodeWord, uint64_t address) {
101+
uint64_t codeWord = address ^chainCodeWord;
102+
103+
if (codeWord == 0) {
104+
return false;
105+
}
106+
107+
uint64_t parity = 0;
108+
for (uint16_t i = 0; i < linearCodeN; i++) {
109+
if ((codeWord & 1) == 1) {
110+
parity ^= parityCheckMatrixColumns[i];
111+
}
112+
codeWord >>= 1;
113+
}
114+
115+
return parity == 0;
116+
}
117+
118+
parser_error_t chainIDFromPayer(const flow_payer_t *v, chain_id_e *chainID) {
119+
if (v->ctx.bufferLen != 8) {
120+
return parser_invalid_address;
121+
}
122+
123+
uint64_t address = 0;
124+
for (uint8_t i = 0; i < 8; i++) {
125+
address <<= 8;
126+
address += v->ctx.buffer[i];
127+
}
128+
129+
if (validateChainAddress(codeword_mainnet, address)) {
130+
*chainID = chain_id_mainnet;
131+
return parser_ok;
132+
}
133+
134+
if (validateChainAddress(codeword_testnet, address)) {
135+
*chainID = chain_id_testnet;
136+
return parser_ok;
137+
}
138+
139+
if (validateChainAddress(codeword_emulatornet, address)) {
140+
*chainID = chain_id_emulator;
141+
return parser_ok;
142+
}
143+
144+
return parser_unexpected_value;
145+
}
146+
147+
parser_error_t parser_printChainID(const flow_payer_t *v,
148+
char *outVal, uint16_t outValLen,
149+
uint8_t pageIdx, uint8_t *pageCount) {
150+
MEMZERO(outVal, outValLen);
151+
chain_id_e chainID;
152+
CHECK_PARSER_ERR(chainIDFromPayer(v, &chainID));
153+
154+
*pageCount = 1;
155+
switch (chainID) {
156+
case chain_id_mainnet:
157+
snprintf(outVal, outValLen, "Mainnet");
158+
return parser_ok;
159+
case chain_id_testnet:
160+
snprintf(outVal, outValLen, "Testnet");
161+
return parser_ok;
162+
case chain_id_emulator:
163+
snprintf(outVal, outValLen, "Emulator");
164+
return parser_ok;
165+
case chain_id_unknown:
166+
default:
167+
return parser_invalid_address;
168+
}
169+
170+
return parser_invalid_address;
171+
}
172+
74173
__Z_INLINE parser_error_t parser_printArgument(const flow_argument_list_t *v,
75174
uint8_t argIndex, char *expectedType, jsmntype_t jsonType,
76175
char *outVal, uint16_t outValLen,
@@ -264,55 +363,58 @@ parser_error_t parser_getItemTokenTransfer(const parser_context_t *ctx,
264363
char *outKey, uint16_t outKeyLen,
265364
char *outVal, uint16_t outValLen,
266365
uint8_t pageIdx, uint8_t *pageCount) {
267-
if (displayIdx == 0) {
268-
snprintf(outKey, outKeyLen, "Type");
269-
snprintf(outVal, outValLen, "Token Transfer");
270-
return parser_ok;
271-
}
272-
displayIdx--;
366+
*pageCount = 1;
273367

274368
switch (displayIdx) {
275369
case 0:
370+
snprintf(outKey, outKeyLen, "Type");
371+
snprintf(outVal, outValLen, "Token Transfer");
372+
return parser_ok;
373+
case 1:
374+
snprintf(outKey, outKeyLen, "ChainID");
375+
return parser_printChainID(&parser_tx_obj.payer,
376+
outVal, outValLen, pageIdx, pageCount);
377+
case 2:
276378
snprintf(outKey, outKeyLen, "Amount");
277-
return parser_printArgument(&parser_tx_obj.arguments, displayIdx,
379+
return parser_printArgument(&parser_tx_obj.arguments, 0,
278380
"UFix64", JSMN_STRING,
279381
outVal, outValLen, pageIdx, pageCount);
280-
case 1:
382+
case 3:
281383
snprintf(outKey, outKeyLen, "Destination");
282-
return parser_printArgument(&parser_tx_obj.arguments, displayIdx,
384+
return parser_printArgument(&parser_tx_obj.arguments, 1,
283385
"Address", JSMN_STRING,
284386
outVal, outValLen, pageIdx, pageCount);
285-
case 2:
387+
case 4:
286388
snprintf(outKey, outKeyLen, "Ref Block");
287389
return parser_printBlockId(&parser_tx_obj.referenceBlockId, outVal, outValLen, pageIdx, pageCount);
288-
case 3:
390+
case 5:
289391
snprintf(outKey, outKeyLen, "Gas Limit");
290392
return parser_printGasLimit(&parser_tx_obj.gasLimit, outVal, outValLen, pageIdx, pageCount);
291-
case 4:
393+
case 6:
292394
snprintf(outKey, outKeyLen, "Prop Key Addr");
293395
return parser_printPropKeyAddr(&parser_tx_obj.proposalKeyAddress, outVal, outValLen, pageIdx, pageCount);
294-
case 5:
396+
case 7:
295397
snprintf(outKey, outKeyLen, "Prop Key Id");
296398
return parser_printPropKeyId(&parser_tx_obj.proposalKeyId, outVal, outValLen, pageIdx, pageCount);
297-
case 6:
399+
case 8:
298400
snprintf(outKey, outKeyLen, "Prop Key Seq Num");
299401
return parser_printPropSeqNum(&parser_tx_obj.proposalKeySequenceNumber, outVal, outValLen, pageIdx,
300402
pageCount);
301-
case 7:
403+
case 9:
302404
snprintf(outKey, outKeyLen, "Payer");
303405
return parser_printPayer(&parser_tx_obj.payer, outVal, outValLen, pageIdx, pageCount);
304406
default:
305407
break;
306408
}
307-
displayIdx -= 8;
409+
displayIdx -= 10;
308410

309411
if (displayIdx < parser_tx_obj.authorizers.authorizer_count) {
310412
snprintf(outKey, outKeyLen, "Authorizer %d", displayIdx + 1);
311413
return parser_printAuthorizer(&parser_tx_obj.authorizers.authorizer[displayIdx], outVal, outValLen, pageIdx,
312414
pageCount);
313415
}
314416

315-
return parser_ok;
417+
return parser_display_idx_out_of_range;
316418
}
317419

318420
parser_error_t parser_getItemCreateAccount(const parser_context_t *ctx,
@@ -321,13 +423,20 @@ parser_error_t parser_getItemCreateAccount(const parser_context_t *ctx,
321423
char *outVal, uint16_t outValLen,
322424
uint8_t pageIdx, uint8_t *pageCount) {
323425
zemu_log_stack("parser_getItemCreateAccount");
426+
*pageCount = 1;
324427

325428
if (displayIdx == 0) {
326429
snprintf(outKey, outKeyLen, "Type");
327430
snprintf(outVal, outValLen, "Create Account");
328431
return parser_ok;
329432
}
330433
displayIdx--;
434+
if (displayIdx == 0) {
435+
snprintf(outKey, outKeyLen, "ChainID");
436+
return parser_printChainID(&parser_tx_obj.payer,
437+
outVal, outValLen, pageIdx, pageCount);
438+
}
439+
displayIdx--;
331440

332441
const uint8_t pkCount = _countArgumentItems(&parser_tx_obj.arguments, 0);
333442
if (displayIdx < pkCount) {
@@ -372,58 +481,63 @@ parser_error_t parser_getItemCreateAccount(const parser_context_t *ctx,
372481
pageCount);
373482
}
374483

375-
return parser_ok;
484+
return parser_display_idx_out_of_range;
376485
}
377486

378487
parser_error_t parser_getItemAddNewKey(const parser_context_t *ctx,
379488
uint16_t displayIdx,
380489
char *outKey, uint16_t outKeyLen,
381490
char *outVal, uint16_t outValLen,
382491
uint8_t pageIdx, uint8_t *pageCount) {
492+
*pageCount = 1;
383493
switch (displayIdx) {
384494
case 0:
385495
snprintf(outKey, outKeyLen, "Type");
386496
snprintf(outVal, outValLen, "Add New Key");
387497
return parser_ok;
388-
case 1: {
498+
case 1:
499+
snprintf(outKey, outKeyLen, "ChainID");
500+
return parser_printChainID(&parser_tx_obj.payer,
501+
outVal, outValLen, pageIdx, pageCount);
502+
case 2: {
389503
CHECK_PARSER_ERR(
390504
parser_printArgumentPublicKey(
391505
&parser_tx_obj.arguments.argCtx[0], outVal, outValLen,
392506
pageIdx, pageCount))
393507
snprintf(outKey, outKeyLen, "Pub key");
394508
return parser_ok;
395509
}
396-
case 2:
510+
case 3:
397511
snprintf(outKey, outKeyLen, "Ref Block");
398512
return parser_printBlockId(&parser_tx_obj.referenceBlockId, outVal, outValLen, pageIdx, pageCount);
399-
case 3:
513+
case 4:
400514
snprintf(outKey, outKeyLen, "Gas Limit");
401515
return parser_printGasLimit(&parser_tx_obj.gasLimit, outVal, outValLen, pageIdx, pageCount);
402-
case 4:
516+
case 5:
403517
snprintf(outKey, outKeyLen, "Prop Key Addr");
404518
return parser_printPropKeyAddr(&parser_tx_obj.proposalKeyAddress, outVal, outValLen, pageIdx, pageCount);
405-
case 5:
519+
case 6:
406520
snprintf(outKey, outKeyLen, "Prop Key Id");
407521
return parser_printPropKeyId(&parser_tx_obj.proposalKeyId, outVal, outValLen, pageIdx, pageCount);
408-
case 6:
522+
case 7:
409523
snprintf(outKey, outKeyLen, "Prop Key Seq Num");
410524
return parser_printPropSeqNum(&parser_tx_obj.proposalKeySequenceNumber, outVal, outValLen, pageIdx,
411525
pageCount);
412-
case 7:
526+
case 8:
413527
snprintf(outKey, outKeyLen, "Payer");
414528
return parser_printPayer(&parser_tx_obj.payer, outVal, outValLen, pageIdx, pageCount);
415529
default:
416530
break;
417531
}
418-
displayIdx -= 8;
532+
displayIdx -= 9;
419533

420534
if (displayIdx < parser_tx_obj.authorizers.authorizer_count) {
421535
snprintf(outKey, outKeyLen, "Authorizer %d", displayIdx + 1);
422536
return parser_printAuthorizer(&parser_tx_obj.authorizers.authorizer[displayIdx], outVal, outValLen, pageIdx,
423537
pageCount);
424538
}
425539

426-
return parser_ok;
540+
return parser_display_idx_out_of_range;
427541
}
428542

429543
parser_error_t parser_getItem(const parser_context_t *ctx,

app/src/parser_impl.c

+7-4
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,10 @@ parser_error_t _matchScriptType(uint8_t scriptHash[32], script_type_e *scriptTyp
251251
return parser_unexpected_error;
252252
}
253253

254-
if (MEMCMP(CONTRACT_HASH_TOKEN_TRANSFER, buffer, 64) == 0) {
254+
if (
255+
(MEMCMP(CONTRACT_HASH_TOKEN_TRANSFER_EMULATOR, buffer, 64) == 0) ||
256+
(MEMCMP(CONTRACT_HASH_TOKEN_TRANSFER_TESTNET, buffer, 64) == 0) ||
257+
(MEMCMP(CONTRACT_HASH_TOKEN_TRANSFER_MAINNET, buffer, 64) == 0)) {
255258
*scriptType = script_token_transfer;
256259
return parser_ok;
257260
}
@@ -504,11 +507,11 @@ uint8_t _countArgumentItems(const flow_argument_list_t *v, uint8_t argumentIndex
504507
uint8_t _getNumItems(const parser_context_t *c, const parser_tx_t *v) {
505508
switch (v->script.type) {
506509
case script_token_transfer:
507-
return 9 + v->authorizers.authorizer_count;
510+
return 10 + v->authorizers.authorizer_count;
508511
case script_create_account:
509-
return 7 + _countArgumentItems(&v->arguments, 0) + v->authorizers.authorizer_count;
512+
return 8 + _countArgumentItems(&v->arguments, 0) + v->authorizers.authorizer_count;
510513
case script_add_new_key:
511-
return 8 + v->authorizers.authorizer_count;
514+
return 9 + v->authorizers.authorizer_count;
512515
case script_unknown:
513516
default:
514517
return 0;

app/src/parser_txdef.h

+7
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ typedef enum {
3838
script_add_new_key
3939
} script_type_e;
4040

41+
typedef enum {
42+
chain_id_unknown,
43+
chain_id_emulator,
44+
chain_id_testnet,
45+
chain_id_mainnet,
46+
} chain_id_e;
47+
4148
typedef struct {
4249
parser_context_t ctx;
4350
uint8_t digest[CX_SHA256_SIZE];

0 commit comments

Comments
 (0)