Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extended CCIP Report Infos to include all necessary metadata for Solana lookups #487

Merged
merged 2 commits into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 7 additions & 21 deletions commit/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"bytes"
"context"
"encoding/hex"
"encoding/json"
"fmt"
"time"

Expand All @@ -23,22 +22,6 @@ import (
cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3"
)

// ReportInfo is the info data that will be sent with the along with the report
// It will be used to determine if the report should be accepted or not
type ReportInfo struct {
// RemoteF Max number of faulty RMN nodes; f+1 signers are required to verify a report.
RemoteF uint64 `json:"remoteF"`
}

func (ri ReportInfo) Encode() ([]byte, error) {
return json.Marshal(ri)
}

// Decode should be used to decode the report info
func (ri *ReportInfo) Decode(encodedReportInfo []byte) error {
return json.Unmarshal(encodedReportInfo, ri)
}

func (p *Plugin) Reports(
ctx context.Context, seqNr uint64, outcomeBytes ocr3types.Outcome,
) ([]ocr3types.ReportPlus[[]byte], error) {
Expand All @@ -59,7 +42,7 @@ func (p *Plugin) Reports(

var (
rep cciptypes.CommitPluginReport
repInfo ReportInfo
repInfo cciptypes.CommitReportInfo
)

// MerkleRoots and RMNSignatures will be empty arrays if there is nothing to report
Expand All @@ -78,7 +61,10 @@ func (p *Plugin) Reports(
}

if outcome.MerkleRootOutcome.OutcomeType == merkleroot.ReportGenerated {
repInfo = ReportInfo{RemoteF: outcome.MerkleRootOutcome.RMNRemoteCfg.FSign}
repInfo = cciptypes.CommitReportInfo{
RemoteF: outcome.MerkleRootOutcome.RMNRemoteCfg.FSign,
MerkleRoots: rep.MerkleRoots,
}
}

if rep.IsEmpty() {
Expand Down Expand Up @@ -147,8 +133,8 @@ func (p *Plugin) validateReport(
return false, cciptypes.CommitPluginReport{}, nil
}

var reportInfo ReportInfo
if err := reportInfo.Decode(r.Info); err != nil {
var reportInfo cciptypes.CommitReportInfo
if reportInfo, err = cciptypes.DecodeCommitReportInfo(r.Info); err != nil {
return false, cciptypes.CommitPluginReport{}, fmt.Errorf("decode report info: %w", err)
}

Expand Down
17 changes: 13 additions & 4 deletions commit/report_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func TestPluginReports(t *testing.T) {
outc committypes.Outcome
expErr bool
expReports []ccipocr3.CommitPluginReport
expReportInfo ReportInfo
expReportInfo ccipocr3.CommitReportInfo
}{
{
name: "wrong outcome type gives an empty report but no error",
Expand Down Expand Up @@ -79,7 +79,7 @@ func TestPluginReports(t *testing.T) {
RMNSignatures: nil,
},
},
expReportInfo: ReportInfo{},
expReportInfo: ccipocr3.CommitReportInfo{},
expErr: false,
},
{
Expand All @@ -101,7 +101,7 @@ func TestPluginReports(t *testing.T) {
RMNSignatures: nil,
},
},
expReportInfo: ReportInfo{},
expReportInfo: ccipocr3.CommitReportInfo{},
expErr: false,
},
{
Expand Down Expand Up @@ -151,7 +151,16 @@ func TestPluginReports(t *testing.T) {
RMNSignatures: nil,
},
},
expReportInfo: ReportInfo{RemoteF: 123},
expReportInfo: ccipocr3.CommitReportInfo{
RemoteF: 123,
MerkleRoots: []ccipocr3.MerkleRootChain{
{
ChainSel: 3,
OnRampAddress: []byte{1, 2, 3},
SeqNumsRange: ccipocr3.NewSeqNumRange(10, 20),
MerkleRoot: ccipocr3.Bytes32{1, 2, 3, 4, 5, 6},
},
}},
},
}

Expand Down
9 changes: 6 additions & 3 deletions execute/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,18 +348,21 @@ func selectReport(
}

func extractReportInfo(report exectypes.Outcome) cciptypes.ExecuteReportInfo {
var ri cciptypes.ExecuteReportInfo
merkleRoots := []cciptypes.MerkleRootChain{}

for _, commitReport := range report.CommitReports {
ri = append(ri, cciptypes.MerkleRootChain{
merkleRoots = append(merkleRoots, cciptypes.MerkleRootChain{
ChainSel: commitReport.SourceChain,
OnRampAddress: commitReport.OnRampAddress,
SeqNumsRange: commitReport.SequenceNumberRange,
MerkleRoot: commitReport.MerkleRoot,
})
}

return ri
return cciptypes.ExecuteReportInfo{
AbstractReports: report.Report.ChainReports,
MerkleRoots: merkleRoots,
}
}

func (p *Plugin) Reports(
Expand Down
34 changes: 34 additions & 0 deletions pkg/types/ccipocr3/plugin_commit_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ccipocr3

import (
"bytes"
"encoding/json"
"fmt"
)

Expand Down Expand Up @@ -64,3 +65,36 @@ type PriceUpdates struct {
TokenPriceUpdates []TokenPrice `json:"tokenPriceUpdates"`
GasPriceUpdates []GasPriceChain `json:"gasPriceUpdates"`
}

// ReportInfo is the info data that will be sent with the along with the report
// It will be used to determine if the report should be accepted or not
type CommitReportInfo struct {
// RemoteF Max number of faulty RMN nodes; f+1 signers are required to verify a report.
RemoteF uint64 `json:"remoteF"`
MerkleRoots []MerkleRootChain `json:"merkleRoots"`
}

func (cri CommitReportInfo) Encode() ([]byte, error) {
data, err := json.Marshal(cri)
data = append([]byte{01}, data...)
return data, err
}

// DecodeCommitReportInfo is a version aware decode function for the commit
// report info bytes.
func DecodeCommitReportInfo(data []byte) (CommitReportInfo, error) {
if len(data) == 0 {
return CommitReportInfo{}, nil
}

switch data[0] {
case 1:
var result CommitReportInfo
dec := json.NewDecoder(bytes.NewReader(data[1:]))
dec.DisallowUnknownFields()
err := dec.Decode(&result)
return result, err
default:
return CommitReportInfo{}, fmt.Errorf("unknown execute report info version (%d)", data[0])
}
}
5 changes: 4 additions & 1 deletion pkg/types/ccipocr3/plugin_execute_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ type ExecutePluginReportSingleChain struct {

// ExecuteReportInfo contains metadata needed by transmitter and contract
// writer.
type ExecuteReportInfo []MerkleRootChain
type ExecuteReportInfo struct {
AbstractReports []ExecutePluginReportSingleChain
MerkleRoots []MerkleRootChain
}

// Encode v1 execute report info. Very basic versioning in the first byte to
// allow for future encoding optimizations.
Expand Down
33 changes: 22 additions & 11 deletions pkg/types/ccipocr3/plugin_execute_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ func TestDecodeExecuteReportInfo(t *testing.T) {

// unknown field
{
data := append([]byte{1}, []byte(`[{"Bogus":1}]`)...)
data := append([]byte{1}, []byte(`{"Bogus":1}`)...)
_, err := DecodeExecuteReportInfo(data)
require.ErrorContains(t, err, "unknown field")
}

// Not a slice
// Not an object
{
data := append([]byte{1}, []byte(`{"Bogus":1}`)...)
data := append([]byte{1}, []byte(`[{"Bogus":1}]`)...)
_, err := DecodeExecuteReportInfo(data)
require.ErrorContains(t, err, "object") // not super helpful...
require.ErrorContains(t, err, "array") // not super helpful...
}

// empty
Expand All @@ -46,16 +46,27 @@ func TestExecuteReportInfo_EncodeDecode(t *testing.T) {
}{
{
name: "object",
reportInfo: []MerkleRootChain{
{
ChainSel: 10,
OnRampAddress: mustNewUnknownAddress(t, "0x04D4cC5972ad487F71b85654d48b27D32b13a22F"),
SeqNumsRange: NewSeqNumRange(100, 200),
MerkleRoot: Bytes32{},
reportInfo: ExecuteReportInfo{
AbstractReports: []ExecutePluginReportSingleChain{
{
SourceChainSelector: ChainSelector(1),
Messages: []Message{},
OffchainTokenData: [][][]byte{},
Proofs: []Bytes32{},
ProofFlagBits: BigInt{},
},
},
MerkleRoots: []MerkleRootChain{
{
ChainSel: 10,
OnRampAddress: mustNewUnknownAddress(t, "0x04D4cC5972ad487F71b85654d48b27D32b13a22F"),
SeqNumsRange: NewSeqNumRange(100, 200),
MerkleRoot: Bytes32{},
},
},
},
//nolint:lll
want: append([]byte{1}, []byte(`[{"chain":10,"onRampAddress":"0x04d4cc5972ad487f71b85654d48b27d32b13a22f","seqNumsRange":[100,200],"merkleRoot":"0x0000000000000000000000000000000000000000000000000000000000000000"}]`)...),
want: append([]byte{1}, []byte(`{"AbstractReports":[{"sourceChainSelector":1,"messages":[],"offchainTokenData":[],"proofs":[],"proofFlagBits":null}],"MerkleRoots":[{"chain":10,"onRampAddress":"0x04d4cc5972ad487f71b85654d48b27d32b13a22f","seqNumsRange":[100,200],"merkleRoot":"0x0000000000000000000000000000000000000000000000000000000000000000"}]}`)...),
wantErr: require.NoError,
},
}
Expand Down
Loading