From 2fbf8fd69ac04c455d291fdfc94edd75af53a572 Mon Sep 17 00:00:00 2001 From: dimitris Date: Tue, 25 Jun 2024 14:47:11 +0300 Subject: [PATCH] ocr3 - changes related to multiramps (#1034) Update commit plugin logic to support multiramps. With multiramps we are not able to compute the msg hash on the source chain but only on the destination chain. Changes: 0. Updated the spec. Check the spec diff for a summary of the changes. 1. Msg ID is computed on source and only used for tracing purposes. 2. Msg Hash is computed for the destination chain by the MsgHasher destination chain specific implementation. 4. Merkle tree uses msg hash for leaves instead of msg id. --- .../plugins/ccip/commit/plugin_e2e_test.go | 9 +- .../plugins/ccip/commit/plugin_functions.go | 93 +++--- .../ccip/commit/plugin_functions_test.go | 267 ++++++++++-------- core/services/ocr3/plugins/ccip/go.mod | 2 +- core/services/ocr3/plugins/ccip/go.sum | 4 +- .../ccip/internal/mocks/messagehasher.go | 5 +- .../ocr3/plugins/ccip/spec/commit_plugin.py | 38 ++- 7 files changed, 227 insertions(+), 191 deletions(-) diff --git a/core/services/ocr3/plugins/ccip/commit/plugin_e2e_test.go b/core/services/ocr3/plugins/ccip/commit/plugin_e2e_test.go index 42e8799968..bc93fa96d7 100644 --- a/core/services/ocr3/plugins/ccip/commit/plugin_e2e_test.go +++ b/core/services/ocr3/plugins/ccip/commit/plugin_e2e_test.go @@ -3,6 +3,7 @@ package commit import ( "context" "reflect" + "strconv" "testing" "time" @@ -301,8 +302,8 @@ func setupAllNodesReadAllChains(ctx context.Context, t *testing.T, lggr logger.L chainB, cciptypes.NewSeqNumRange(21, cciptypes.SeqNum(21+cfg.NewMsgScanBatchSize)), ).Return([]cciptypes.CCIPMsg{ - {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: cciptypes.Bytes32{1}, SourceChain: chainB, SeqNum: 21}}, - {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: cciptypes.Bytes32{2}, SourceChain: chainB, SeqNum: 22}}, + {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{MsgHash: cciptypes.Bytes32{1}, ID: "1", SourceChain: chainB, SeqNum: 21}}, + {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{MsgHash: cciptypes.Bytes32{2}, ID: "2", SourceChain: chainB, SeqNum: 22}}, }, nil) n.ccipReader.On("GasPrices", ctx, []cciptypes.ChainSelector{chainA, chainB}). @@ -401,8 +402,8 @@ func setupNodesDoNotAgreeOnMsgs(ctx context.Context, t *testing.T, lggr logger.L cciptypes.SeqNum(21+cfg.NewMsgScanBatchSize), ), ).Return([]cciptypes.CCIPMsg{ - {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: cciptypes.Bytes32{1, byte(i)}, SourceChain: chainB, SeqNum: 21 + cciptypes.SeqNum(i*10)}}, - {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: cciptypes.Bytes32{2, byte(i)}, SourceChain: chainB, SeqNum: 22 + cciptypes.SeqNum(i*20)}}, + {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{MsgHash: cciptypes.Bytes32{1}, ID: "1" + strconv.Itoa(i), SourceChain: chainB, SeqNum: 21 + cciptypes.SeqNum(i*10)}}, + {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{MsgHash: cciptypes.Bytes32{2}, ID: "2" + strconv.Itoa(i), SourceChain: chainB, SeqNum: 22 + cciptypes.SeqNum(i*20)}}, }, nil) n.ccipReader.On("GasPrices", ctx, []cciptypes.ChainSelector{chainA, chainB}). diff --git a/core/services/ocr3/plugins/ccip/commit/plugin_functions.go b/core/services/ocr3/plugins/ccip/commit/plugin_functions.go index e68004d374..2b64113c79 100644 --- a/core/services/ocr3/plugins/ccip/commit/plugin_functions.go +++ b/core/services/ocr3/plugins/ccip/commit/plugin_functions.go @@ -19,7 +19,7 @@ import ( ) // observeLatestCommittedSeqNums finds the maximum committed sequence numbers for each source chain. -// If we cannot observe the dest we return an empty slice and no error.. +// If we cannot observe the dest we return an empty slice and no error. func observeLatestCommittedSeqNums( ctx context.Context, lggr logger.Logger, @@ -85,16 +85,12 @@ func observeNewMsgs( lggr.Debugw("no new messages discovered", "chain", seqNumChain.ChainSel) } - for _, msg := range newMsgs { - msgHash, err := msgHasher.Hash(ctx, msg) + for i := range newMsgs { + h, err := msgHasher.Hash(ctx, newMsgs[i]) if err != nil { return fmt.Errorf("hash message: %w", err) } - - if msgHash != msg.ID { - lggr.Warnw("invalid message discovered", "msg", msg, "err", err) - continue - } + newMsgs[i].MsgHash = h // populate msgHash field } newMsgsPerChain[chainIdx] = newMsgs @@ -244,52 +240,52 @@ func newMsgsConsensusForChain( lggr.Debugw("observed messages consensus", "chain", chainSel, "fChain", fChain, "observedMsgs", len(observedMsgs)) - // First come to consensus about the (sequence number, id) pairs. - // For each sequence number consider correct the ID with the most votes. - msgSeqNumToIDCounts := make(map[cciptypes.SeqNum]map[string]int) // seqNum -> msgID -> count + // First come to consensus about the (sequence number, msg hash) pairs. + // For each sequence number consider the Hash with the most votes. + msgSeqNumToHashCounts := make(map[cciptypes.SeqNum]map[string]int) // seqNum -> msgHash -> count for _, msg := range observedMsgs { - if _, exists := msgSeqNumToIDCounts[msg.SeqNum]; !exists { - msgSeqNumToIDCounts[msg.SeqNum] = make(map[string]int) + if _, exists := msgSeqNumToHashCounts[msg.SeqNum]; !exists { + msgSeqNumToHashCounts[msg.SeqNum] = make(map[string]int) } - msgSeqNumToIDCounts[msg.SeqNum][msg.ID.String()]++ + msgSeqNumToHashCounts[msg.SeqNum][msg.MsgHash.String()]++ } - lggr.Debugw("observed message counts", "chain", chainSel, "msgSeqNumToIdCounts", msgSeqNumToIDCounts) + lggr.Debugw("observed message counts", "chain", chainSel, "msgSeqNumToHashCounts", msgSeqNumToHashCounts) msgObservationsCount := make(map[cciptypes.SeqNum]int) - msgSeqNumToID := make(map[cciptypes.SeqNum]cciptypes.Bytes32) - for seqNum, idCounts := range msgSeqNumToIDCounts { - if len(idCounts) == 0 { - lggr.Errorw("critical error id counts should never be empty", "seqNum", seqNum) + msgSeqNumToHash := make(map[cciptypes.SeqNum]cciptypes.Bytes32) + for seqNum, hashCounts := range msgSeqNumToHashCounts { + if len(hashCounts) == 0 { + lggr.Fatalw("hash counts should never be empty", "seqNum", seqNum) continue } - // Find the ID with the most votes for each sequence number. - idsSlice := make([]string, 0, len(idCounts)) - for id := range idCounts { - idsSlice = append(idsSlice, id) + // Find the MsgHash with the most votes for each sequence number. + hashesSlice := make([]string, 0, len(hashCounts)) + for h := range hashCounts { + hashesSlice = append(hashesSlice, h) } - // determinism in case we have the same count for different ids - sort.Slice(idsSlice, func(i, j int) bool { return idsSlice[i] < idsSlice[j] }) + // determinism in case we have the same count for different hashes + sort.Slice(hashesSlice, func(i, j int) bool { return hashesSlice[i] < hashesSlice[j] }) - maxCnt := idCounts[idsSlice[0]] - mostVotedID := idsSlice[0] - for _, id := range idsSlice[1:] { - cnt := idCounts[id] + maxCnt := hashCounts[hashesSlice[0]] + mostVotedHash := hashesSlice[0] + for _, h := range hashesSlice[1:] { + cnt := hashCounts[h] if cnt > maxCnt { maxCnt = cnt - mostVotedID = id + mostVotedHash = h } } msgObservationsCount[seqNum] = maxCnt - idBytes, err := cciptypes.NewBytes32FromString(mostVotedID) + hashBytes, err := cciptypes.NewBytes32FromString(mostVotedHash) if err != nil { - return observedMsgsConsensus{}, fmt.Errorf("critical issue converting id '%s' to bytes32: %w", - mostVotedID, err) + return observedMsgsConsensus{}, fmt.Errorf("critical issue converting hash '%s' to bytes32: %w", + mostVotedHash, err) } - msgSeqNumToID[seqNum] = idBytes + msgSeqNumToHash[seqNum] = hashBytes } - lggr.Debugw("observed message consensus", "chain", chainSel, "msgSeqNumToId", msgSeqNumToID) + lggr.Debugw("observed message consensus", "chain", chainSel, "msgSeqNumToHash", msgSeqNumToHash) // Filter out msgs not observed by at least 2f_chain+1 followers. msgSeqNumsQuorum := mapset.NewSet[cciptypes.SeqNum]() @@ -313,22 +309,13 @@ func newMsgsConsensusForChain( seqNumConsensusRange.SetEnd(seqNum) } - msgsBySeqNum := make(map[cciptypes.SeqNum]cciptypes.CCIPMsgBaseDetails) - for _, msg := range observedMsgs { - consensusMsgID, ok := msgSeqNumToID[msg.SeqNum] - if !ok || consensusMsgID != msg.ID { - continue - } - msgsBySeqNum[msg.SeqNum] = msg - } - treeLeaves := make([][32]byte, 0) for seqNum := seqNumConsensusRange.Start(); seqNum <= seqNumConsensusRange.End(); seqNum++ { - msg, ok := msgsBySeqNum[seqNum] + msgHash, ok := msgSeqNumToHash[seqNum] if !ok { - return observedMsgsConsensus{}, fmt.Errorf("msg not found in map for seq num %d", seqNum) + return observedMsgsConsensus{}, fmt.Errorf("msg hash not found for seq num %d", seqNum) } - treeLeaves = append(treeLeaves, msg.ID) + treeLeaves = append(treeLeaves, msgHash) } lggr.Debugw("constructing merkle tree", "chain", chainSel, "treeLeaves", len(treeLeaves)) @@ -491,18 +478,28 @@ func validateObservedSequenceNumbers(msgs []cciptypes.CCIPMsgBaseDetails, maxSeq } seqNums := make(map[cciptypes.ChainSelector]mapset.Set[cciptypes.SeqNum], len(msgs)) + hashes := mapset.NewSet[string]() for _, msg := range msgs { - // The same sequence number must not appear more than once for the same chain and must be valid. + if msg.MsgHash.IsEmpty() { + return fmt.Errorf("observed msg hash must not be empty") + } if _, exists := seqNums[msg.SourceChain]; !exists { seqNums[msg.SourceChain] = mapset.NewSet[cciptypes.SeqNum]() } + // The same sequence number must not appear more than once for the same chain and must be valid. if seqNums[msg.SourceChain].Contains(msg.SeqNum) { return fmt.Errorf("duplicate sequence number %d for chain %d", msg.SeqNum, msg.SourceChain) } seqNums[msg.SourceChain].Add(msg.SeqNum) + // The observed msg hash cannot appear twice for different msgs. + if hashes.Contains(msg.MsgHash.String()) { + return fmt.Errorf("duplicate msg hash %s", msg.MsgHash.String()) + } + hashes.Add(msg.MsgHash.String()) + // The observed msg sequence number cannot be less than or equal to the max observed sequence number. maxSeqNum, exists := maxSeqNumsMap[msg.SourceChain] if !exists { diff --git a/core/services/ocr3/plugins/ccip/commit/plugin_functions_test.go b/core/services/ocr3/plugins/ccip/commit/plugin_functions_test.go index 86c8e1cce9..6bff9abe18 100644 --- a/core/services/ocr3/plugins/ccip/commit/plugin_functions_test.go +++ b/core/services/ocr3/plugins/ccip/commit/plugin_functions_test.go @@ -4,6 +4,7 @@ import ( "context" "math/big" "slices" + "strconv" "testing" "time" @@ -137,17 +138,17 @@ func Test_observeNewMsgs(t *testing.T) { msgScanBatchSize: 256, newMsgs: map[cciptypes.ChainSelector][]cciptypes.CCIPMsg{ 1: { - {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}, + {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: "1", SourceChain: 1, SeqNum: 11}}, }, 2: { - {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: [32]byte{2}, SourceChain: 2, SeqNum: 21}}, - {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: [32]byte{3}, SourceChain: 2, SeqNum: 22}}, + {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: "2", SourceChain: 2, SeqNum: 21}}, + {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: "3", SourceChain: 2, SeqNum: 22}}, }, }, expMsgs: []cciptypes.CCIPMsg{ - {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}, - {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: [32]byte{2}, SourceChain: 2, SeqNum: 21}}, - {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: [32]byte{3}, SourceChain: 2, SeqNum: 22}}, + {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: "1", SourceChain: 1, SeqNum: 11}}, + {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: "2", SourceChain: 2, SeqNum: 21}}, + {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: "3", SourceChain: 2, SeqNum: 22}}, }, expErr: false, }, @@ -161,13 +162,13 @@ func Test_observeNewMsgs(t *testing.T) { msgScanBatchSize: 256, newMsgs: map[cciptypes.ChainSelector][]cciptypes.CCIPMsg{ 2: { - {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: [32]byte{2}, SourceChain: 2, SeqNum: 21}}, - {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: [32]byte{3}, SourceChain: 2, SeqNum: 22}}, + {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: "2", SourceChain: 2, SeqNum: 21}}, + {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: "3", SourceChain: 2, SeqNum: 22}}, }, }, expMsgs: []cciptypes.CCIPMsg{ - {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: [32]byte{2}, SourceChain: 2, SeqNum: 21}}, - {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: [32]byte{3}, SourceChain: 2, SeqNum: 22}}, + {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: "2", SourceChain: 2, SeqNum: 21}}, + {CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ID: "3", SourceChain: 2, SeqNum: 22}}, }, expErr: false, }, @@ -178,6 +179,12 @@ func Test_observeNewMsgs(t *testing.T) { ctx := context.Background() mockReader := mocks.NewCCIPReader() msgHasher := mocks.NewMessageHasher() + for i := range tc.expMsgs { // make sure the hashes are populated + h, err := msgHasher.Hash(ctx, tc.expMsgs[i]) + assert.NoError(t, err) + tc.expMsgs[i].MsgHash = h + } + lggr := logger.Test(t) for _, seqNumChain := range tc.maxSeqNumsPerChain { @@ -237,7 +244,7 @@ func Benchmark_observeNewMsgs(b *testing.B) { for msgSeqNum := 1; msgSeqNum <= newMsgsPerChain; msgSeqNum++ { newMsgs = append(newMsgs, cciptypes.CCIPMsg{ CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ - ID: cciptypes.Bytes32{byte(msgSeqNum)}, + ID: strconv.Itoa(msgSeqNum), SourceChain: seqNumChain.ChainSel, SeqNum: cciptypes.SeqNum(msgSeqNum), }, @@ -372,10 +379,10 @@ func Test_validateObservedSequenceNumbers(t *testing.T) { { name: "dup msg seq num", msgs: []cciptypes.CCIPMsgBaseDetails{ - {ID: cciptypes.Bytes32{1}, SourceChain: 1, SeqNum: 12}, - {ID: cciptypes.Bytes32{1}, SourceChain: 1, SeqNum: 13}, - {ID: cciptypes.Bytes32{1}, SourceChain: 1, SeqNum: 14}, - {ID: cciptypes.Bytes32{1}, SourceChain: 1, SeqNum: 13}, // dup + {ID: "1", SourceChain: 1, SeqNum: 12}, + {ID: "1", SourceChain: 1, SeqNum: 13}, + {ID: "1", SourceChain: 1, SeqNum: 14}, + {ID: "1", SourceChain: 1, SeqNum: 13}, // dup }, maxSeqNums: []cciptypes.SeqNumChain{ {ChainSel: 1, SeqNum: 10}, @@ -386,10 +393,10 @@ func Test_validateObservedSequenceNumbers(t *testing.T) { { name: "msg seq nums ok", msgs: []cciptypes.CCIPMsgBaseDetails{ - {ID: cciptypes.Bytes32{1}, SourceChain: 1, SeqNum: 12}, - {ID: cciptypes.Bytes32{1}, SourceChain: 1, SeqNum: 13}, - {ID: cciptypes.Bytes32{1}, SourceChain: 1, SeqNum: 14}, - {ID: cciptypes.Bytes32{1}, SourceChain: 2, SeqNum: 21}, + {MsgHash: cciptypes.Bytes32{1}, ID: "1", SourceChain: 1, SeqNum: 12}, + {MsgHash: cciptypes.Bytes32{2}, ID: "1", SourceChain: 1, SeqNum: 13}, + {MsgHash: cciptypes.Bytes32{3}, ID: "1", SourceChain: 1, SeqNum: 14}, + {MsgHash: cciptypes.Bytes32{4}, ID: "1", SourceChain: 2, SeqNum: 21}, }, maxSeqNums: []cciptypes.SeqNumChain{ {ChainSel: 1, SeqNum: 10}, @@ -400,10 +407,10 @@ func Test_validateObservedSequenceNumbers(t *testing.T) { { name: "msg seq nums does not match observed max seq num", msgs: []cciptypes.CCIPMsgBaseDetails{ - {ID: cciptypes.Bytes32{1}, SourceChain: 1, SeqNum: 12}, - {ID: cciptypes.Bytes32{1}, SourceChain: 1, SeqNum: 13}, - {ID: cciptypes.Bytes32{1}, SourceChain: 1, SeqNum: 10}, // max seq num is already 10 - {ID: cciptypes.Bytes32{1}, SourceChain: 2, SeqNum: 21}, + {ID: "1", SourceChain: 1, SeqNum: 12}, + {ID: "1", SourceChain: 1, SeqNum: 13}, + {ID: "1", SourceChain: 1, SeqNum: 10}, // max seq num is already 10 + {ID: "1", SourceChain: 2, SeqNum: 21}, }, maxSeqNums: []cciptypes.SeqNumChain{ {ChainSel: 1, SeqNum: 10}, @@ -414,13 +421,41 @@ func Test_validateObservedSequenceNumbers(t *testing.T) { { name: "max seq num not found", msgs: []cciptypes.CCIPMsgBaseDetails{ - {ID: cciptypes.Bytes32{1}, SourceChain: 1, SeqNum: 12}, - {ID: cciptypes.Bytes32{1}, SourceChain: 1, SeqNum: 13}, - {ID: cciptypes.Bytes32{1}, SourceChain: 1, SeqNum: 14}, - {ID: cciptypes.Bytes32{1}, SourceChain: 2, SeqNum: 21}, // max seq num not reported + {ID: "1", SourceChain: 1, SeqNum: 12}, + {ID: "1", SourceChain: 1, SeqNum: 13}, + {ID: "1", SourceChain: 1, SeqNum: 14}, + {ID: "1", SourceChain: 2, SeqNum: 21}, // max seq num not reported + }, + maxSeqNums: []cciptypes.SeqNumChain{ + {ChainSel: 1, SeqNum: 10}, + }, + expErr: true, + }, + { + name: "msg hashes ok", + msgs: []cciptypes.CCIPMsgBaseDetails{ + {MsgHash: cciptypes.Bytes32{123}, ID: "1", SourceChain: 1, SeqNum: 12}, + {MsgHash: cciptypes.Bytes32{99}, ID: "1", SourceChain: 1, SeqNum: 13}, + {MsgHash: cciptypes.Bytes32{12}, ID: "1", SourceChain: 300, SeqNum: 23}, + }, + maxSeqNums: []cciptypes.SeqNumChain{ + {ChainSel: 1, SeqNum: 10}, + {ChainSel: 2, SeqNum: 20}, + {ChainSel: 300, SeqNum: 22}, + }, + expErr: false, + }, + { + name: "dup msg hashes", + msgs: []cciptypes.CCIPMsgBaseDetails{ + {MsgHash: cciptypes.Bytes32{123}, ID: "1", SourceChain: 1, SeqNum: 12}, + {MsgHash: cciptypes.Bytes32{99}, ID: "1", SourceChain: 1, SeqNum: 13}, + {MsgHash: cciptypes.Bytes32{123}, ID: "1", SourceChain: 300, SeqNum: 23}, // dup hash }, maxSeqNums: []cciptypes.SeqNumChain{ {ChainSel: 1, SeqNum: 10}, + {ChainSel: 2, SeqNum: 20}, + {ChainSel: 300, SeqNum: 22}, }, expErr: true, }, @@ -452,10 +487,10 @@ func Test_validateObserverReadingEligibility(t *testing.T) { name: "observer can read all chains", observer: libocrtypes.PeerID{10}, msgs: []cciptypes.CCIPMsgBaseDetails{ - {ID: cciptypes.Bytes32{1}, SourceChain: 1, SeqNum: 12}, - {ID: cciptypes.Bytes32{3}, SourceChain: 2, SeqNum: 12}, - {ID: cciptypes.Bytes32{1}, SourceChain: 3, SeqNum: 12}, - {ID: cciptypes.Bytes32{2}, SourceChain: 3, SeqNum: 12}, + {ID: "1", SourceChain: 1, SeqNum: 12}, + {ID: "3", SourceChain: 2, SeqNum: 12}, + {ID: "1", SourceChain: 3, SeqNum: 12}, + {ID: "2", SourceChain: 3, SeqNum: 12}, }, nodeSupportedChains: mapset.NewSet[cciptypes.ChainSelector](1, 2, 3), destChain: 1, @@ -487,10 +522,10 @@ func Test_validateObserverReadingEligibility(t *testing.T) { name: "observer cfg not found", observer: libocrtypes.PeerID{10}, msgs: []cciptypes.CCIPMsgBaseDetails{ - {ID: cciptypes.Bytes32{1}, SourceChain: 1, SeqNum: 12}, - {ID: cciptypes.Bytes32{3}, SourceChain: 2, SeqNum: 12}, - {ID: cciptypes.Bytes32{1}, SourceChain: 3, SeqNum: 12}, - {ID: cciptypes.Bytes32{2}, SourceChain: 3, SeqNum: 12}, + {ID: "1", SourceChain: 1, SeqNum: 12}, + {ID: "3", SourceChain: 2, SeqNum: 12}, + {ID: "1", SourceChain: 3, SeqNum: 12}, + {ID: "2", SourceChain: 3, SeqNum: 12}, }, nodeSupportedChains: mapset.NewSet[cciptypes.ChainSelector](1, 3), // observer 10 not found destChain: 1, @@ -650,9 +685,9 @@ func Test_newMsgsConsensusForChain(t *testing.T) { {ChainSel: 1, SeqNum: 10}, }, observations: []cciptypes.CommitPluginObservation{ - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, }, expMerkleRoots: []cciptypes.MerkleRootChain{}, expErr: false, @@ -666,11 +701,11 @@ func Test_newMsgsConsensusForChain(t *testing.T) { {ChainSel: 1, SeqNum: 10}, }, observations: []cciptypes.CommitPluginObservation{ - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, }, expMerkleRoots: []cciptypes.MerkleRootChain{ { @@ -689,23 +724,21 @@ func Test_newMsgsConsensusForChain(t *testing.T) { {ChainSel: 1, SeqNum: 10}, }, observations: []cciptypes.CommitPluginObservation{ - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{2}, SourceChain: 1, SeqNum: 12}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{2}, SourceChain: 1, SeqNum: 12}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{2}, SourceChain: 1, SeqNum: 12}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{2}, SourceChain: 1, SeqNum: 12}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{2}, SourceChain: 1, SeqNum: 12}}}, - - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{3}, SourceChain: 1, SeqNum: 13}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{3}, SourceChain: 1, SeqNum: 13}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{3}, SourceChain: 1, SeqNum: 13}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{3}, SourceChain: 1, SeqNum: 13}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{3}, SourceChain: 1, SeqNum: 13}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "2", SourceChain: 1, SeqNum: 12}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "2", SourceChain: 1, SeqNum: 12}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "2", SourceChain: 1, SeqNum: 12}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "2", SourceChain: 1, SeqNum: 12}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "2", SourceChain: 1, SeqNum: 12}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "3", SourceChain: 1, SeqNum: 13}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "3", SourceChain: 1, SeqNum: 13}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "3", SourceChain: 1, SeqNum: 13}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "3", SourceChain: 1, SeqNum: 13}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "3", SourceChain: 1, SeqNum: 13}}}, }, expMerkleRoots: []cciptypes.MerkleRootChain{ { @@ -724,23 +757,21 @@ func Test_newMsgsConsensusForChain(t *testing.T) { {ChainSel: 1, SeqNum: 10}, }, observations: []cciptypes.CommitPluginObservation{ - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 10}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 10}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 10}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 10}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 10}}}, - - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{2}, SourceChain: 1, SeqNum: 12}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{2}, SourceChain: 1, SeqNum: 12}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{2}, SourceChain: 1, SeqNum: 12}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{2}, SourceChain: 1, SeqNum: 12}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{2}, SourceChain: 1, SeqNum: 12}}}, - - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{3}, SourceChain: 1, SeqNum: 13}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{3}, SourceChain: 1, SeqNum: 13}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{3}, SourceChain: 1, SeqNum: 13}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{3}, SourceChain: 1, SeqNum: 13}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{3}, SourceChain: 1, SeqNum: 13}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 10}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 10}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 10}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 10}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 10}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "2", SourceChain: 1, SeqNum: 12}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "2", SourceChain: 1, SeqNum: 12}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "2", SourceChain: 1, SeqNum: 12}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "2", SourceChain: 1, SeqNum: 12}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "2", SourceChain: 1, SeqNum: 12}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "3", SourceChain: 1, SeqNum: 13}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "3", SourceChain: 1, SeqNum: 13}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "3", SourceChain: 1, SeqNum: 13}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "3", SourceChain: 1, SeqNum: 13}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "3", SourceChain: 1, SeqNum: 13}}}, }, expMerkleRoots: []cciptypes.MerkleRootChain{ { @@ -759,20 +790,18 @@ func Test_newMsgsConsensusForChain(t *testing.T) { {ChainSel: 1, SeqNum: 10}, }, observations: []cciptypes.CommitPluginObservation{ - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{2}, SourceChain: 1, SeqNum: 12}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{2}, SourceChain: 1, SeqNum: 12}}}, - - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{3}, SourceChain: 1, SeqNum: 13}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{3}, SourceChain: 1, SeqNum: 13}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{3}, SourceChain: 1, SeqNum: 13}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{3}, SourceChain: 1, SeqNum: 13}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{3}, SourceChain: 1, SeqNum: 13}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "2", SourceChain: 1, SeqNum: 12}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "2", SourceChain: 1, SeqNum: 12}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "3", SourceChain: 1, SeqNum: 13}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "3", SourceChain: 1, SeqNum: 13}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "3", SourceChain: 1, SeqNum: 13}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "3", SourceChain: 1, SeqNum: 13}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "3", SourceChain: 1, SeqNum: 13}}}, }, expMerkleRoots: []cciptypes.MerkleRootChain{ { @@ -793,19 +822,17 @@ func Test_newMsgsConsensusForChain(t *testing.T) { {ChainSel: 2, SeqNum: 20}, }, observations: []cciptypes.CommitPluginObservation{ - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{3}, SourceChain: 2, SeqNum: 21}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{3}, SourceChain: 2, SeqNum: 21}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{3}, SourceChain: 2, SeqNum: 21}}}, - - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{4}, SourceChain: 2, SeqNum: 22}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{4}, SourceChain: 2, SeqNum: 22}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{4}, SourceChain: 2, SeqNum: 22}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "3", SourceChain: 2, SeqNum: 21}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "3", SourceChain: 2, SeqNum: 21}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "3", SourceChain: 2, SeqNum: 21}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "4", SourceChain: 2, SeqNum: 22}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "4", SourceChain: 2, SeqNum: 22}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "4", SourceChain: 2, SeqNum: 22}}}, }, expMerkleRoots: []cciptypes.MerkleRootChain{ { @@ -828,23 +855,21 @@ func Test_newMsgsConsensusForChain(t *testing.T) { {ChainSel: 1, SeqNum: 10}, }, observations: []cciptypes.CommitPluginObservation{ - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{1}, SourceChain: 1, SeqNum: 11}}}, - - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{10}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{10}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{111}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{111}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{3}, SourceChain: 1, SeqNum: 11}}}, - - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{2}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{2}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{2}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{2}, SourceChain: 1, SeqNum: 11}}}, - {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: [32]byte{2}, SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "1", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "10", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "10", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "111", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "111", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "3", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "2", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "2", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "2", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "2", SourceChain: 1, SeqNum: 11}}}, + {NewMsgs: []cciptypes.CCIPMsgBaseDetails{{ID: "2", SourceChain: 1, SeqNum: 11}}}, }, expMerkleRoots: []cciptypes.MerkleRootChain{ { diff --git a/core/services/ocr3/plugins/ccip/go.mod b/core/services/ocr3/plugins/ccip/go.mod index b1495f2a62..b497e58564 100644 --- a/core/services/ocr3/plugins/ccip/go.mod +++ b/core/services/ocr3/plugins/ccip/go.mod @@ -4,7 +4,7 @@ go 1.21.7 require ( github.com/deckarep/golang-set/v2 v2.6.0 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240621142824-4ab126926def + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240625074419-c278d083facf github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c github.com/stretchr/testify v1.9.0 golang.org/x/crypto v0.24.0 diff --git a/core/services/ocr3/plugins/ccip/go.sum b/core/services/ocr3/plugins/ccip/go.sum index 59452140b3..c71295378b 100644 --- a/core/services/ocr3/plugins/ccip/go.sum +++ b/core/services/ocr3/plugins/ccip/go.sum @@ -50,8 +50,8 @@ github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6Ng github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240621142824-4ab126926def h1:MI8onvelUa+ZsYNlvtRx1c45Io9F+RtcPYxJAgTcRK0= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240621142824-4ab126926def/go.mod h1:n/jIcH2y0klmCZ8mRquIXjhOwJq395PvMmNP7FE0bVI= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240625074419-c278d083facf h1:d9AS/K8RSVG64USb20N/U7RaPOsYPcmuLGJq7iE+caM= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240625074419-c278d083facf/go.mod h1:L32xvCpk84Nglit64OhySPMP1tM3TTBK7Tw0qZl7Sd4= github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c h1:lIyMbTaF2H0Q71vkwZHX/Ew4KF2BxiKhqEXwF8rn+KI= github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c/go.mod h1:fb1ZDVXACvu4frX3APHZaEBp0xi1DIm34DcA0CwTsZM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/core/services/ocr3/plugins/ccip/internal/mocks/messagehasher.go b/core/services/ocr3/plugins/ccip/internal/mocks/messagehasher.go index cb3c3fd645..5a85e25f4c 100644 --- a/core/services/ocr3/plugins/ccip/internal/mocks/messagehasher.go +++ b/core/services/ocr3/plugins/ccip/internal/mocks/messagehasher.go @@ -13,5 +13,8 @@ func NewMessageHasher() *MessageHasher { } func (m *MessageHasher) Hash(ctx context.Context, msg cciptypes.CCIPMsg) (cciptypes.Bytes32, error) { - return msg.ID, nil + // simply return the msg id as bytes32 + var b32 [32]byte + copy(b32[:], msg.ID) + return b32, nil } diff --git a/core/services/ocr3/plugins/ccip/spec/commit_plugin.py b/core/services/ocr3/plugins/ccip/spec/commit_plugin.py index c6048bc3e8..5698650153 100644 --- a/core/services/ocr3/plugins/ccip/spec/commit_plugin.py +++ b/core/services/ocr3/plugins/ccip/spec/commit_plugin.py @@ -22,7 +22,8 @@ class Interval: @dataclass class Message: seq_nr: int - message_id: bytes + message_id: bytes # a unique message identifier computed on the source chain + message_hash: bytes # hash of message body computed on the destination chain and used on merkle tree # TODO: @dataclass @@ -89,9 +90,10 @@ def observation(self, previous_outcome: CommitOutcome) -> CommitObservation: new_msgs = {} for (chain, seq_num) in previous_outcome.latest_committed_seq_nums: if chain in self.cfg.oracle_info[self.cfg.oracle]: - new_msgs[chain] = self.onRamp(chain).get_msgs(chain, start=seq_num+1, limit=256) - for msg in new_msgs[chain]: - assert(msg.id == msg.compute_id()) + msgs = self.onRamp(chain).get_msgs(chain, start=seq_num+1, limit=256) + for msg in msgs: + msg.message_hash = msg.compute_hash() + new_msgs[chain] = msgs # Observe token prices. {token: price} token_prices = self.get_token_prices() @@ -123,11 +125,17 @@ def validate_observation(self, attributed_observation): assert self.cfg.dest_chain in self.cfg.oracle_info[oracle] # Only accept source observations from nodes which support those sources. + msg_ids = set() + msg_hashes = set() for (chain, msgs) in observation.new_msgs.items(): assert(chain in self.cfg.oracle_info[oracle]) - # Don't allow duplicates by seqNr or id. Required to prevent double counting. - assert(len(msgs) == len(set([msg.seq_num for msg in msgs]))) - assert(len(msgs) == len(set([msg.id for msg in msgs]))) + # Don't allow duplicates of (chain, seqNr), (id) and (hash). Required to prevent double counting. + assert(len(msgs) == len(set([msg.seq_num for msg in msgs]))) + for msg in msgs: + assert msg.message_id not in msg_ids + assert msg.message_hash not in msg_hashes + msg_ids.add(msg.message_id) + msg_hashes.add(msg.message_hash) def observation_quorum(self): return "2F+1" @@ -148,17 +156,19 @@ def outcome(self, observations: List[CommitObservation])->CommitOutcome: msgs = [msg for msg in msgs if msg.seq_num > latest_committed_seq_nums[chain]] msgs_by_seq_num = msgs.group_by_seq_num() # { 423: [0x1, 0x1, 0x2] } - # 2 nodes say that msg id is 0x1 and 1 node says it's 0x2 + # 2 nodes say that msg hash is 0x1 and 1 node says it's 0x2 + # if different hashes have the same number of votes, we select the + # hash with the lowest lexicographic order - msg_ids = { seq_num: elem_most_occurrences(ids) for (seq_num, ids) in msgs_by_seq_num.items() } - for (seq_num, id) in msg_ids.items(): # require at least 2f+1 observations of the voted id - assert(msgs_by_seq_num[seq_num].count(id) >= 2*f_chain[chain]+1) + msg_hashes = { seq_num: elem_most_occurrences(hashes) for (seq_num, hashes) in msgs_by_seq_num.items() } + for (seq_num, hash) in msg_hashes.items(): # require at least 2f+1 observations of the voted hash + assert(msgs_by_seq_num[seq_num].count(hash) >= 2*f_chain[chain]+1) - msgs_for_tree = [] # [ (seq_num, id) ] - for (seq_num, id) in msg_ids.ordered_by_seq_num(): + msgs_for_tree = [] # [ (seq_num, hash) ] + for (seq_num, hash) in msg_hashes.ordered_by_seq_num(): if len(msgs_for_tree) > 0 and msgs_for_tree[-1].seq_num+1 != seq_num: break # gap in sequence numbers, stop here - msgs_for_tree.append((seq_num, id)) + msgs_for_tree.append((seq_num, hash)) commits[chain] = Commit(root=build_merkle_tree(msgs_for_tree), interval=Interval(min=msgs_for_tree[0].seq_num, max=msgs_for_tree[-1].seq_num))