Skip to content

Commit

Permalink
Merge branch 'ccip-develop' into price-reader
Browse files Browse the repository at this point in the history
  • Loading branch information
asoliman92 authored Aug 15, 2024
2 parents 6829d88 + 8c54f7e commit 2b55c95
Show file tree
Hide file tree
Showing 4 changed files with 237 additions and 88 deletions.
68 changes: 58 additions & 10 deletions execute/exectypes/outcome.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,47 @@ import (
cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3"
)

type PluginState string

const (
// Unknown is the zero value, this allows a "Next" state transition for uninitialized values (i.e. the first round).
Unknown PluginState = ""

// GetCommitReports is the first step, it is used to select commit reports from the destination chain.
GetCommitReports PluginState = "GetCommitReports"

// GetMessages is the second step, given a set of commit reports it fetches the associated messages.
GetMessages PluginState = "GetMessages"

// Filter is the final step, any additional destination data is collected to complete the execution report.
Filter PluginState = "Filter"
)

// Next returns the next state for the plugin. The Unknown state is used to transition from uninitialized values.
func (p PluginState) Next() PluginState {
switch p {
case GetCommitReports:
return GetMessages

case GetMessages:
// TODO: go to Filter after GetMessages
return GetCommitReports

case Unknown:
fallthrough
case Filter:
return GetCommitReports

default:
panic("unexpected execute plugin state")
}
}

// Outcome is the outcome of the ExecutePlugin.
type Outcome struct {
// State that the outcome was generated for.
State PluginState

// PendingCommitReports are the oldest reports with pending commits. The slice is
// sorted from oldest to newest.
PendingCommitReports []CommitData `json:"commitReports"`
Expand All @@ -17,28 +56,27 @@ type Outcome struct {
Report cciptypes.ExecutePluginReport `json:"report"`
}

// IsEmpty returns true if the outcome has no pending commit reports or chain reports.
func (o Outcome) IsEmpty() bool {
return len(o.PendingCommitReports) == 0 && len(o.Report.ChainReports) == 0
}

// NewOutcome creates a new Outcome with the pending commit reports and the chain reports sorted.
func NewOutcome(
state PluginState,
pendingCommits []CommitData,
report cciptypes.ExecutePluginReport,
) Outcome {
return newSortedOutcome(pendingCommits, report)
}

// Encode encodes the outcome by first sorting the pending commit reports and the chain reports
// and then JSON marshalling.
// The encoding MUST be deterministic.
func (o Outcome) Encode() ([]byte, error) {
// We sort again here in case construction is not via the constructor.
return json.Marshal(newSortedOutcome(o.PendingCommitReports, o.Report))
return newSortedOutcome(state, pendingCommits, report)
}

// newSortedOutcome ensures canonical ordering of the outcome.
// TODO: handle canonicalization in the encoder.
func newSortedOutcome(
state PluginState,
pendingCommits []CommitData,
report cciptypes.ExecutePluginReport) Outcome {
report cciptypes.ExecutePluginReport,
) Outcome {
pendingCommitsCP := append([]CommitData{}, pendingCommits...)
reportCP := append([]cciptypes.ExecutePluginReportSingleChain{}, report.ChainReports...)
sort.Slice(
Expand All @@ -52,11 +90,21 @@ func newSortedOutcome(
return reportCP[i].SourceChainSelector < reportCP[j].SourceChainSelector
})
return Outcome{
State: state,
PendingCommitReports: pendingCommitsCP,
Report: cciptypes.ExecutePluginReport{ChainReports: reportCP},
}
}

// Encode encodes the outcome by first sorting the pending commit reports and the chain reports
// and then JSON marshalling.
// The encoding MUST be deterministic.
func (o Outcome) Encode() ([]byte, error) {
// We sort again here in case construction is not via the constructor.
return json.Marshal(newSortedOutcome(o.State, o.PendingCommitReports, o.Report))
}

// DecodeOutcome decodes the outcome from JSON.
func DecodeOutcome(b []byte) (Outcome, error) {
o := Outcome{}
err := json.Unmarshal(b, &o)
Expand Down
53 changes: 53 additions & 0 deletions execute/exectypes/outcome_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package exectypes

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestPluginState_Next(t *testing.T) {
tests := []struct {
name string
p PluginState
want PluginState
isPanic bool
}{
{
name: "Zero value",
p: Unknown,
want: GetCommitReports,
},
{
name: "Phase 1 to 2",
p: GetCommitReports,
want: GetMessages,
},
{
name: "Phase 2 to 1",
p: GetMessages,
want: GetCommitReports,
},
{
name: "panic",
p: PluginState("ElToroLoco"),
isPanic: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if tt.isPanic {
require.Panics(t, func() {
tt.p.Next()
})
return
}

if got := tt.p.Next(); got != tt.want {
t.Errorf("Next() = %v, want %v", got, tt.want)
}
})
}
}
Loading

0 comments on commit 2b55c95

Please sign in to comment.