Skip to content

Commit 1e9906e

Browse files
fix: increments in upf converter txNonce calculation
1 parent bdebc08 commit 1e9906e

2 files changed

Lines changed: 123 additions & 89 deletions

File tree

experimental/analyzer/upf/upf.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,12 +212,12 @@ func asciiHash(data [32]byte) rawBytes {
212212
func calculateOpCount(opCount uint64, opIndex int, operations []mcmstypes.Operation) uint64 {
213213
chainSelector := operations[opIndex].ChainSelector
214214
for i, op := range operations {
215-
if op.ChainSelector == chainSelector {
216-
opCount += 1
217-
}
218215
if i == opIndex {
219216
break
220217
}
218+
if op.ChainSelector == chainSelector {
219+
opCount += 1
220+
}
221221
}
222222

223223
return opCount

experimental/analyzer/upf/upf_test.go

Lines changed: 120 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -31,45 +31,25 @@ func TestUpfConvertTimelockProposal(t *testing.T) {
3131
t.Parallel()
3232
ds := datastore.NewMemoryDataStore()
3333

34-
mustAdd := func(chain uint64, addr, typeAndVersion string) {
35-
tv := deployment.MustTypeAndVersionFromString(typeAndVersion)
36-
storeAddr := addr
37-
if strings.HasPrefix(addr, "0x") {
38-
storeAddr = addr
39-
}
40-
ref := datastore.AddressRef{
41-
ChainSelector: chain,
42-
Address: storeAddr,
43-
Type: datastore.ContractType(tv.Type),
44-
Version: &tv.Version,
45-
// Use address+type as a unique Qualifier (avoids clashes)
46-
Qualifier: fmt.Sprintf("%s-%s", addr, tv.Type),
47-
}
48-
if !tv.Labels.IsEmpty() {
49-
ref.Labels = datastore.NewLabelSet(tv.Labels.List()...)
50-
}
51-
require.NoError(t, ds.Addresses().Add(ref))
52-
}
53-
5434
// ---- EVM: ethereum-testnet-sepolia-base-1
55-
mustAdd(10344971235874465080, "0x5f077BCeE6e285154473F65699d6F46Fd03D105A", "RBACTimelock 1.0.0")
56-
mustAdd(10344971235874465080, "0xA5D5B0B844c8f11B61F28AC98BBA84dEA9b80953", "ProposerManyChainMultisig 1.0.0")
57-
mustAdd(10344971235874465080, "0x76B12C4f3672aA613F1b2302327827B7B74064E1", "RMNRemote 1.6.0")
35+
dsAddContract(t, ds, 10344971235874465080, "0x5f077BCeE6e285154473F65699d6F46Fd03D105A", "RBACTimelock 1.0.0")
36+
dsAddContract(t, ds, 10344971235874465080, "0xA5D5B0B844c8f11B61F28AC98BBA84dEA9b80953", "ProposerManyChainMultisig 1.0.0")
37+
dsAddContract(t, ds, 10344971235874465080, "0x76B12C4f3672aA613F1b2302327827B7B74064E1", "RMNRemote 1.6.0")
5838

5939
// ---- EVM: bsc-testnet
60-
mustAdd(13264668187771770619, "0x804759c9bdd258A810987FDe21c9E24C5383b722", "RBACTimelock 1.0.0")
61-
mustAdd(13264668187771770619, "0x9A60462e4CA802E3E945663930Be0d162e662091", "ProposerManyChainMultisig 1.0.0")
62-
mustAdd(13264668187771770619, "0x76B12C4f3672aA613F1b2302327827B7B74064E1", "RMNRemote 1.6.0")
40+
dsAddContract(t, ds, 13264668187771770619, "0x804759c9bdd258A810987FDe21c9E24C5383b722", "RBACTimelock 1.0.0")
41+
dsAddContract(t, ds, 13264668187771770619, "0x9A60462e4CA802E3E945663930Be0d162e662091", "ProposerManyChainMultisig 1.0.0")
42+
dsAddContract(t, ds, 13264668187771770619, "0x76B12C4f3672aA613F1b2302327827B7B74064E1", "RMNRemote 1.6.0")
6343

6444
// ---- Solana: devnet
65-
mustAdd(16423721717087811551, "5vNJx78mz7KVMjhuipyr9jKBKcMrKYGdjGkgE4LUmjKk", "ManyChainMultiSigProgram 1.0.0")
66-
mustAdd(16423721717087811551, "5vNJx78mz7KVMjhuipyr9jKBKcMrKYGdjGkgE4LUmjKk.ID6xwqkfFkH6dx2LF0O2NKfHKwHywEB0", "ProposerManyChainMultiSig 1.0.0")
67-
mustAdd(16423721717087811551, "DoajfR5tK24xVw51fWcawUZWhAXD8yrBJVacc13neVQA", "RBACTimelockProgram 1.0.0")
68-
mustAdd(16423721717087811551, "DoajfR5tK24xVw51fWcawUZWhAXD8yrBJVacc13neVQA.E4R6Nwg1K8Zvi6McLdkaGDD5ClX1KkyV", "RBACTimelock 1.0.0")
69-
mustAdd(16423721717087811551, "FTDusxFg9NmmFGRg5jfA9nHCiCpZ7dJktawfRBcUBhq", "ProposerAccessControllerAccount 1.0.0")
70-
mustAdd(16423721717087811551, "2hABoxD9U5A4j4x3kNDf4dBJ7ZP384Zbs3TuFn9QUTSs", "CancellerAccessControllerAccount 1.0.0")
71-
mustAdd(16423721717087811551, "68ds9kDfB6rJfC4zzeeQ8E9ZMwqSzFQEie1886VAPn68", "BypasserAccessControllerAccount 1.0.0")
72-
mustAdd(16423721717087811551, "RmnXLft1mSEwDgMKu2okYuHkiazxntFFcZFrrcXxYg7", "RMNRemote 1.0.0")
45+
dsAddContract(t, ds, 16423721717087811551, "5vNJx78mz7KVMjhuipyr9jKBKcMrKYGdjGkgE4LUmjKk", "ManyChainMultiSigProgram 1.0.0")
46+
dsAddContract(t, ds, 16423721717087811551, "5vNJx78mz7KVMjhuipyr9jKBKcMrKYGdjGkgE4LUmjKk.ID6xwqkfFkH6dx2LF0O2NKfHKwHywEB0", "ProposerManyChainMultiSig 1.0.0")
47+
dsAddContract(t, ds, 16423721717087811551, "DoajfR5tK24xVw51fWcawUZWhAXD8yrBJVacc13neVQA", "RBACTimelockProgram 1.0.0")
48+
dsAddContract(t, ds, 16423721717087811551, "DoajfR5tK24xVw51fWcawUZWhAXD8yrBJVacc13neVQA.E4R6Nwg1K8Zvi6McLdkaGDD5ClX1KkyV", "RBACTimelock 1.0.0")
49+
dsAddContract(t, ds, 16423721717087811551, "FTDusxFg9NmmFGRg5jfA9nHCiCpZ7dJktawfRBcUBhq", "ProposerAccessControllerAccount 1.0.0")
50+
dsAddContract(t, ds, 16423721717087811551, "2hABoxD9U5A4j4x3kNDf4dBJ7ZP384Zbs3TuFn9QUTSs", "CancellerAccessControllerAccount 1.0.0")
51+
dsAddContract(t, ds, 16423721717087811551, "68ds9kDfB6rJfC4zzeeQ8E9ZMwqSzFQEie1886VAPn68", "BypasserAccessControllerAccount 1.0.0")
52+
dsAddContract(t, ds, 16423721717087811551, "RmnXLft1mSEwDgMKu2okYuHkiazxntFFcZFrrcXxYg7", "RMNRemote 1.0.0")
7353

7454
env := deployment.Environment{
7555
DataStore: ds.Seal(),
@@ -280,7 +260,7 @@ transactions:
280260
to: "0x5f077BCeE6e285154473F65699d6F46Fd03D105A"
281261
value: 0
282262
data: "0xa944142d00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000773593ff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012c0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000076b12c4f3672aa613f1b2302327827b7b74064e1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000064f8bb876e000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000b8159170038f96fb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
283-
txNonce: 2
263+
txNonce: 1
284264
metadata:
285265
contractType: RBACTimelock
286266
decodedCalldata:
@@ -307,7 +287,7 @@ transactions:
307287
to: "0x804759c9bdd258A810987FDe21c9E24C5383b722"
308288
value: 0
309289
data: "0xa944142d00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000773593ff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012c0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000076b12c4f3672aa613f1b2302327827b7b74064e1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000064f8bb876e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000008f90b8876dee65380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
310-
txNonce: 3
290+
txNonce: 2
311291
metadata:
312292
contractType: RBACTimelock
313293
decodedCalldata:
@@ -334,7 +314,7 @@ transactions:
334314
to: DoajfR5tK24xVw51fWcawUZWhAXD8yrBJVacc13neVQA
335315
value: 0
336316
data: D2DZq3wEcfNFNFI2TndnMUs4WnZpNk1jTGRrYUdERDVDbFgxS2t5VpAXlZ2LYPhZ+p8F9JucBPQaESwj/lQ3CwCjnNzLdfsEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB3NZP/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAA=
337-
txNonce: 4
317+
txNonce: 3
338318
metadata:
339319
contractType: RBACTimelock
340320
decodedCalldata:
@@ -361,7 +341,7 @@ transactions:
361341
to: DoajfR5tK24xVw51fWcawUZWhAXD8yrBJVacc13neVQA
362342
value: 0
363343
data: w+bVh5CUjlVFNFI2TndnMUs4WnZpNk1jTGRrYUdERDVDbFgxS2t5VpAXlZ2LYPhZ+p8F9JucBPQaESwj/lQ3CwCjnNzLdfsEBliT7ZWrhugwWyiYp2G+HCHNv7C39ebv1T6DsoMrGlAEAAAA569Vk65pFF7HVjX5akNsLQQfz9+AaloAzqNrzzoGc1AAAB74fnS+SLFE6OvgAxbo+S+KqA2nm/gNrv6H0f98BW1YAAGvogYtczqE0C5vP92khgtsL3GSUtW9S5XWTvA81tlPygABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
364-
txNonce: 5
344+
txNonce: 4
365345
metadata:
366346
contractType: RBACTimelock
367347
decodedCalldata:
@@ -394,7 +374,7 @@ transactions:
394374
to: DoajfR5tK24xVw51fWcawUZWhAXD8yrBJVacc13neVQA
395375
value: 0
396376
data: TE1mg4gMLQVFNFI2TndnMUs4WnZpNk1jTGRrYUdERDVDbFgxS2t5VpAXlZ2LYPhZ+p8F9JucBPQaESwj/lQ3CwCjnNzLdfsEAAAAABgAAAAKf+LjigPASfuWjwNwkRW4AAAAAAAAAAA=
397-
txNonce: 6
377+
txNonce: 5
398378
metadata:
399379
contractType: RBACTimelock
400380
decodedCalldata:
@@ -420,7 +400,7 @@ transactions:
420400
to: DoajfR5tK24xVw51fWcawUZWhAXD8yrBJVacc13neVQA
421401
value: 0
422402
data: P9AgYlW27IxFNFI2TndnMUs4WnZpNk1jTGRrYUdERDVDbFgxS2t5VpAXlZ2LYPhZ+p8F9JucBPQaESwj/lQ3CwCjnNzLdfsE
423-
txNonce: 7
403+
txNonce: 6
424404
metadata:
425405
contractType: RBACTimelock
426406
decodedCalldata:
@@ -443,7 +423,7 @@ transactions:
443423
to: DoajfR5tK24xVw51fWcawUZWhAXD8yrBJVacc13neVQA
444424
value: 0
445425
data: 8oxXakfiViBFNFI2TndnMUs4WnZpNk1jTGRrYUdERDVDbFgxS2t5VpAXlZ2LYPhZ+p8F9JucBPQaESwj/lQ3CwCjnNzLdfsELAEAAAAAAAA=
446-
txNonce: 8
426+
txNonce: 7
447427
metadata:
448428
contractType: RBACTimelock
449429
decodedCalldata:
@@ -516,6 +496,36 @@ var timelockProposalSui = `{
516496
]
517497
}`
518498

499+
var upfProposalSui = `---
500+
msigType: mcms
501+
proposalHash: "0x1c733d9d09e9d41e1651596078df88b00c68e085cc6bf14b8f346866b1741a28"
502+
mcmsParams:
503+
validUntil: 1999999999
504+
merkleRoot: "0xeeaa854482fdd28dec1ca358c4ba9c7399560b580683c7fa372e9a69eab8ba1d"
505+
asciiProposalHash: '\x93>\x07\xb8>\xce3\xfa\xa7\xccZ\x1e\xea\xf8|\xb39\x9c\x10s\xd7\x98\xc8\xa6\x1d\xe13\x99\xa1u\xe2.'
506+
overridePreviousRoot: false
507+
transactions:
508+
- index: 0
509+
chainFamily: sui
510+
chainId: "2"
511+
chainName: sui-testnet
512+
chainShortName: sui-testnet
513+
msigAddress: "0x4e825a4758064df713762e431c3a16b8105857195214469db0d6985b7d70266d"
514+
timelockAddress: "0x4e825a4758064df713762e431c3a16b8105857195214469db0d6985b7d70266d"
515+
to: ""
516+
value: 0
517+
data: AU6CWkdYBk33E3YuQxw6FrgQWFcZUhRGnbDWmFt9cCZtAQltY21zX3VzZXIBDGZ1bmN0aW9uX29uZQFYi8WcKEL0NsEiFpGjWdxClBwfJeyhP0ut55f7Dg2PS2W5dbWeXl19LUYyEaeuZRHbtJS9IbqY1GNZHOkUhofVcGRhdGVkIEZpZWxkIEEKAQIDBAUGBwgJCiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACB3NZP/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwBAAAAAAAA
518+
txNonce: 1
519+
metadata:
520+
contractType: MCMS
521+
decodedCalldata:
522+
functionName: "failed to decode Sui transaction: could not find function in contractInterfaces for mcms::timelock_schedule_batch"
523+
functionArgs: {}
524+
signers:
525+
"9762610643973837292":
526+
- "0xA5D5B0B844c8f11B61F28AC98BBA84dEA9b80953"
527+
`
528+
519529
var timelockProposalSuiUnknownModule = `{
520530
"version": "v1",
521531
"kind": "TimelockProposal",
@@ -531,7 +541,7 @@ var timelockProposalSuiUnknownModule = `{
531541
},
532542
"description": "Sui proposal with unknown module",
533543
"action": "schedule",
534-
"delay": "5m0s",
544+
"delay": "5m0s",
535545
"timelockAddresses": {
536546
"9762610643973837292": "0x4e825a4758064df713762e431c3a16b8105857195214469db0d6985b7d70266d"
537547
},
@@ -555,32 +565,42 @@ var timelockProposalSuiUnknownModule = `{
555565
]
556566
}`
557567

568+
var upfProposalSuiUnknownModule = `---
569+
msigType: mcms
570+
proposalHash: "0x5433c70ce0b94602235ae03d5485a3ff991b90d35b90f3474af5455f1105c198"
571+
mcmsParams:
572+
validUntil: 1999999999
573+
merkleRoot: "0x0104cddb47805604d82eeab0e02cb33c4374c1e635ab038d2a1ed9038c48e4a9"
574+
asciiProposalHash: 'L\xb9E\x9d\xfeMY\x83\xec3\xba\x00\xa6F0@\x82 \xd4\xc0\x9bj-"C\xcb\xf6\xb6v\xc0B\xbc'
575+
overridePreviousRoot: false
576+
transactions:
577+
- index: 0
578+
chainFamily: sui
579+
chainId: "2"
580+
chainName: sui-testnet
581+
chainShortName: sui-testnet
582+
msigAddress: "0x4e825a4758064df713762e431c3a16b8105857195214469db0d6985b7d70266d"
583+
timelockAddress: "0x4e825a4758064df713762e431c3a16b8105857195214469db0d6985b7d70266d"
584+
to: ""
585+
value: 0
586+
data: AU6CWkdYBk33E3YuQxw6FrgQWFcZUhRGnbDWmFt9cCZtAQ51bmtub3duX21vZHVsZQENc29tZV9mdW5jdGlvbgEJc29tZSBkYXRhIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIHc1k/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALAEAAAAAAAA=
587+
txNonce: 1
588+
metadata:
589+
contractType: MCMS
590+
decodedCalldata:
591+
functionName: "failed to decode Sui transaction: could not find function in contractInterfaces for mcms::timelock_schedule_batch"
592+
functionArgs: {}
593+
signers:
594+
"9762610643973837292":
595+
- "0xA5D5B0B844c8f11B61F28AC98BBA84dEA9b80953"
596+
`
597+
558598
func TestUpfConvertTimelockProposalWithSui(t *testing.T) {
559599
t.Parallel()
560600
ds := datastore.NewMemoryDataStore()
561601

562-
mustAdd := func(chain uint64, addr, typeAndVersion string) {
563-
tv := deployment.MustTypeAndVersionFromString(typeAndVersion)
564-
storeAddr := addr
565-
if strings.HasPrefix(addr, "0x") {
566-
storeAddr = addr
567-
}
568-
ref := datastore.AddressRef{
569-
ChainSelector: chain,
570-
Address: storeAddr,
571-
Type: datastore.ContractType(tv.Type),
572-
Version: &tv.Version,
573-
// Use address+type as a unique Qualifier (avoids clashes)
574-
Qualifier: fmt.Sprintf("%s-%s", addr, tv.Type),
575-
}
576-
if !tv.Labels.IsEmpty() {
577-
ref.Labels = datastore.NewLabelSet(tv.Labels.List()...)
578-
}
579-
require.NoError(t, ds.Addresses().Add(ref))
580-
}
581-
582602
// ---- Sui: testnet
583-
mustAdd(chainsel.SUI_TESTNET.Selector, "0x4e825a4758064df713762e431c3a16b8105857195214469db0d6985b7d70266d", "MCMSUser 1.0.0")
603+
dsAddContract(t, ds, chainsel.SUI_TESTNET.Selector, "0x4e825a4758064df713762e431c3a16b8105857195214469db0d6985b7d70266d", "MCMSUser 1.0.0")
584604

585605
env := deployment.Environment{
586606
DataStore: ds.Seal(),
@@ -594,18 +614,21 @@ func TestUpfConvertTimelockProposalWithSui(t *testing.T) {
594614
name string
595615
timelockProposal string
596616
signers map[mcmstypes.ChainSelector][]common.Address
597-
want string
598-
wantErr string
617+
assertion func(*testing.T, string, error)
599618
}{
600619
{
601620
name: "Sui proposal with valid transaction",
602621
timelockProposal: timelockProposalSui,
603-
want: "", // We'll just verify it doesn't error and contains expected content
604622
signers: map[mcmstypes.ChainSelector][]common.Address{
605623
mcmstypes.ChainSelector(chainsel.SUI_TESTNET.Selector): {
606624
common.HexToAddress("0xA5D5B0B844c8f11B61F28AC98BBA84dEA9b80953"),
607625
},
608626
},
627+
assertion: func(t *testing.T, gotUpf string, err error) {
628+
t.Helper()
629+
require.NoError(t, err)
630+
require.Equal(t, upfProposalSui, gotUpf)
631+
},
609632
},
610633
{
611634
name: "Sui proposal with unknown module",
@@ -615,7 +638,11 @@ func TestUpfConvertTimelockProposalWithSui(t *testing.T) {
615638
common.HexToAddress("0xA5D5B0B844c8f11B61F28AC98BBA84dEA9b80953"),
616639
},
617640
},
618-
wantErr: "", // Should not error but will have error message in function name
641+
assertion: func(t *testing.T, gotUpf string, err error) {
642+
t.Helper()
643+
require.NoError(t, err)
644+
require.Equal(t, upfProposalSuiUnknownModule, gotUpf)
645+
},
619646
},
620647
}
621648

@@ -629,25 +656,32 @@ func TestUpfConvertTimelockProposalWithSui(t *testing.T) {
629656

630657
got, err := UpfConvertTimelockProposal(proposalCtx, timelockProposal, mcmProposal, tt.signers)
631658

632-
if tt.wantErr != "" {
633-
require.ErrorContains(t, err, tt.wantErr)
634-
return
635-
}
636-
637-
require.NoError(t, err)
638-
if tt.want != "" {
639-
require.Empty(t, cmp.Diff(tt.want, got))
640-
} else {
641-
// For test cases without specific expected output, just verify it contains expected content
642-
switch tt.name {
643-
case "Sui proposal with valid transaction":
644-
require.Contains(t, got, "chainFamily: sui")
645-
require.Contains(t, got, "chainName: sui-testnet")
646-
case "Sui proposal with unknown module":
647-
// This should contain some error indication
648-
require.Contains(t, got, "failed to decode Sui transaction")
649-
}
650-
}
659+
tt.assertion(t, got, err)
651660
})
652661
}
653662
}
663+
664+
// ----- helpers -----
665+
666+
func dsAddContract(t *testing.T, ds datastore.MutableDataStore, chain uint64, addr, typeAndVersion string) {
667+
t.Helper()
668+
669+
tv := deployment.MustTypeAndVersionFromString(typeAndVersion)
670+
storeAddr := addr
671+
if strings.HasPrefix(addr, "0x") {
672+
storeAddr = addr
673+
}
674+
ref := datastore.AddressRef{
675+
ChainSelector: chain,
676+
Address: storeAddr,
677+
Type: datastore.ContractType(tv.Type),
678+
Version: &tv.Version,
679+
// Use address+type as a unique Qualifier (avoids clashes)
680+
Qualifier: fmt.Sprintf("%s-%s", addr, tv.Type),
681+
}
682+
if !tv.Labels.IsEmpty() {
683+
ref.Labels = datastore.NewLabelSet(tv.Labels.List()...)
684+
}
685+
686+
require.NoError(t, ds.Addresses().Add(ref))
687+
}

0 commit comments

Comments
 (0)