From 33f91788deb60920bdd9a5fc930f3b7f487e066d Mon Sep 17 00:00:00 2001 From: Makram Date: Tue, 10 Sep 2024 19:34:10 +0400 Subject: [PATCH] pkg/types/ccipocr3: add rmn sigs to report (#758) * pkg/types/ccipocr3: add rmn sigs to report Additionally, mark NewCommitPluginReport as deprecated. * add ccip-offchain as codeowners of ccip types * remove usage of deprecated func, update tests * bump doc --- .github/CODEOWNERS | 2 + pkg/types/ccipocr3/plugin_commit_types.go | 44 +++++++++++++++++-- .../ccipocr3/plugin_commit_types_test.go | 27 ++++++++++-- 3 files changed, 66 insertions(+), 7 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 8ab6a76d3..47df75410 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -16,3 +16,5 @@ /pkg/values/ @smartcontractkit/keystone /pkg/workflows/ @smartcontractkit/keystone /pkg/beholder/ @smartcontractkit/realtime +/pkg/types/ccipocr3 @smartcontractkit/ccip-offchain +/pkg/types/ccip @smartcontractkit/ccip-offchain diff --git a/pkg/types/ccipocr3/plugin_commit_types.go b/pkg/types/ccipocr3/plugin_commit_types.go index ea05512bd..43539c7ed 100644 --- a/pkg/types/ccipocr3/plugin_commit_types.go +++ b/pkg/types/ccipocr3/plugin_commit_types.go @@ -1,10 +1,27 @@ package ccipocr3 +// CommitPluginReport contains the necessary information to commit CCIP +// messages from potentially many source chains, to a single destination chain. +// +// It must consist of either: +// +// 1. a non-empty MerkleRoots array, or +// 2. a non-empty PriceUpdates array +// +// If neither of the above is provided the report is considered empty and should +// not be transmitted on-chain. +// +// In the event the MerkleRoots array is non-empty, it may also contain +// RMNSignatures, if RMN is configured for some lanes involved in the commitment. +// A report with RMN signatures but without merkle roots is invalid. type CommitPluginReport struct { - MerkleRoots []MerkleRootChain `json:"merkleRoots"` - PriceUpdates PriceUpdates `json:"priceUpdates"` + MerkleRoots []MerkleRootChain `json:"merkleRoots"` + PriceUpdates PriceUpdates `json:"priceUpdates"` + RMNSignatures []RMNECDSASignature `json:"rmnSignatures"` } +// Deprecated: don't use this constructor, just create a CommitPluginReport struct directly. +// Will be removed in a future version once all uses have been replaced. func NewCommitPluginReport(merkleRoots []MerkleRootChain, tokenPriceUpdates []TokenPrice, gasPriceUpdate []GasPriceChain) CommitPluginReport { return CommitPluginReport{ MerkleRoots: merkleRoots, @@ -16,7 +33,8 @@ func NewCommitPluginReport(merkleRoots []MerkleRootChain, tokenPriceUpdates []To func (r CommitPluginReport) IsEmpty() bool { return len(r.MerkleRoots) == 0 && len(r.PriceUpdates.TokenPriceUpdates) == 0 && - len(r.PriceUpdates.GasPriceUpdates) == 0 + len(r.PriceUpdates.GasPriceUpdates) == 0 && + len(r.RMNSignatures) == 0 } type MerkleRootChain struct { @@ -37,6 +55,26 @@ func NewMerkleRootChain( } } +// RMNECDSASignature is the ECDSA signature from a single RMN node +// on the RMN "Report" structure that consists of: +// 1. the destination chain ID +// 2. the destination chain selector +// 3. the rmn remote contract address +// 4. the offramp address +// 5. the rmn home config digest +// 6. the dest lane updates array, which is a struct that consists of: +// * source chain selector +// * min sequence number +// * max sequence number +// * the merkle root of the messages in the above range +// * the onramp address (in bytes, for EVM, abi-encoded) +// +// For more details see the contract here: https://github.com/smartcontractkit/chainlink/blob/7ba0f37134a618375542079ff1805fe2224d7916/contracts/src/v0.8/ccip/interfaces/IRMNV2.sol#L8-L12 +type RMNECDSASignature struct { + R Bytes32 `json:"r"` + S Bytes32 `json:"s"` +} + type PriceUpdates struct { TokenPriceUpdates []TokenPrice `json:"tokenPriceUpdates"` GasPriceUpdates []GasPriceChain `json:"gasPriceUpdates"` diff --git a/pkg/types/ccipocr3/plugin_commit_types_test.go b/pkg/types/ccipocr3/plugin_commit_types_test.go index 83312beb3..fcdceca52 100644 --- a/pkg/types/ccipocr3/plugin_commit_types_test.go +++ b/pkg/types/ccipocr3/plugin_commit_types_test.go @@ -8,18 +8,37 @@ import ( func TestCommitPluginReport(t *testing.T) { t.Run("is empty", func(t *testing.T) { - r := NewCommitPluginReport(nil, nil, nil) + r := CommitPluginReport{} assert.True(t, r.IsEmpty()) }) t.Run("is not empty", func(t *testing.T) { - r := NewCommitPluginReport(make([]MerkleRootChain, 1), nil, nil) + r := CommitPluginReport{ + MerkleRoots: make([]MerkleRootChain, 1), + } assert.False(t, r.IsEmpty()) - r = NewCommitPluginReport(nil, make([]TokenPrice, 1), make([]GasPriceChain, 1)) + r = CommitPluginReport{ + PriceUpdates: PriceUpdates{ + TokenPriceUpdates: make([]TokenPrice, 1), + GasPriceUpdates: make([]GasPriceChain, 1), + }, + } assert.False(t, r.IsEmpty()) - r = NewCommitPluginReport(make([]MerkleRootChain, 1), make([]TokenPrice, 1), make([]GasPriceChain, 1)) + r = CommitPluginReport{ + RMNSignatures: make([]RMNECDSASignature, 1), + } + assert.False(t, r.IsEmpty()) + + r = CommitPluginReport{ + MerkleRoots: make([]MerkleRootChain, 1), + PriceUpdates: PriceUpdates{ + TokenPriceUpdates: make([]TokenPrice, 1), + GasPriceUpdates: make([]GasPriceChain, 1), + }, + RMNSignatures: make([]RMNECDSASignature, 1), + } assert.False(t, r.IsEmpty()) }) }