Skip to content

Commit ca389c7

Browse files
Merge branch 'main' into offramp-buffering
2 parents 788c984 + 989d6ac commit ca389c7

37 files changed

+2211
-600
lines changed

.github/workflows/ccip-integration-test.yml

Lines changed: 64 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,18 +49,24 @@ jobs:
4949
name: "USDC Test"
5050
- cmd: cd integration-tests/smoke/ccip && go test ccip_ooo_execution_test.go -timeout 12m -test.parallel=1 -count=1 -json
5151
name: "OOO Execution Test"
52-
- cmd: cd integration-tests/smoke/ccip && go test -run "Test_CCIPMessaging_EVM2EVM" ccip_messaging_test.go -timeout 12m -test.parallel=2 -count=1 -json
53-
name: "Messaging Test"
52+
- cmd: cd integration-tests/smoke/ccip && go test -run "Test_CCIPMessaging_EVM2EVM" ccip_messaging_test.go -timeout 20m -test.parallel=1 -count=1 -json
53+
name: "Messaging Test Test_CCIPMessaging_EVM2EVM"
54+
- cmd: cd integration-tests/smoke/ccip && go test -run "^Test_CCIPMessaging_EVM2Solana$" ccip_messaging_test.go -timeout 30m -test.parallel=1 -count=1 -json
55+
name: "Messaging Test Test_CCIPMessaging_EVM2Solana"
56+
- cmd: cd integration-tests/smoke/ccip && go test -run "^Test_CCIPMessaging_Solana2EVM$" ccip_messaging_test.go -timeout 30m -test.parallel=1 -count=1 -json
57+
name: "Messaging Test Test_CCIPMessaging_Solana2EVM"
58+
- cmd: cd integration-tests/smoke/ccip && go test -run "^Test_CCIPMessaging_EVM2SolanaMultiExecReports$" ccip_messaging_test.go -timeout 35m -test.parallel=1 -count=1 -json
59+
name: "Messaging Test Test_CCIPMessaging_EVM2SolanaMultiExecReports"
5460
- cmd: cd integration-tests/smoke/ccip && go test -run "Test_CCIPBatching_MaxBatchSizeEVM" ccip_batching_test.go -timeout 12m -test.parallel=1 -count=1 -json
5561
name: "Batching Test Test_CCIPBatching_MaxBatchSizeEVM"
5662
- cmd: cd integration-tests/smoke/ccip && go test -run "^Test_CCIPBatching_MultiSource$" ccip_batching_test.go -timeout 12m -test.parallel=1 -count=1 -json
5763
name: "Batching Test Test_CCIPBatching_MultiSource"
58-
- cmd: cd integration-tests/smoke/ccip && go test -run "Test_CCIPBatching_MultiSource_MultiReports" ccip_batching_test.go -timeout 12m -test.parallel=1 -count=1 -json
59-
name: "Batching Test Test_CCIPBatching_MultiSource_MultiReports"
64+
- cmd: cd integration-tests/smoke/ccip && go test -run "Test_CCIPBatching_MultiSource_MultiRoot" ccip_batching_test.go -timeout 12m -test.parallel=1 -count=1 -json
65+
name: "Batching Test Test_CCIPBatching_MultiSource_MultiRoot"
6066
- cmd: cd integration-tests/smoke/ccip && go test -run "^Test_CCIPBatching_SingleSource$" ccip_batching_test.go -timeout 12m -test.parallel=1 -count=1 -json
6167
name: "Batching Test Test_CCIPBatching_SingleSource"
62-
- cmd: cd integration-tests/smoke/ccip && go test -run "Test_CCIPBatching_SingleSource_MultipleReports" ccip_batching_test.go -timeout 12m -test.parallel=1 -count=1 -json
63-
name: "Batching Test Test_CCIPBatching_SingleSource_MultipleReports"
68+
- cmd: cd integration-tests/smoke/ccip && go test -run "Test_CCIPBatching_SingleSource_MultiRoot" ccip_batching_test.go -timeout 12m -test.parallel=1 -count=1 -json
69+
name: "Batching Test Test_CCIPBatching_SingleSource_MultiRoot"
6470
- cmd: cd integration-tests/smoke/ccip && go test ccip_gas_price_updates_test.go -timeout 12m -test.parallel=2 -count=1 -json
6571
name: "Gas Price Updates Test"
6672
# TODO: this can only run in docker for now, switch to in-memory and uncomment
@@ -86,21 +92,62 @@ jobs:
8692
- name: Fetch latest pull request data
8793
id: fetch_pr_data
8894
uses: actions/github-script@v6
89-
# only run this step if the event is a pull request
90-
if: github.event_name == 'pull_request'
95+
# only run this step if the event is a pull request or merge_group
96+
if: github.event_name == 'pull_request' || github.event_name == 'merge_group'
9197
with:
9298
script: |
93-
const pr = await github.rest.pulls.get({
94-
owner: context.repo.owner,
95-
repo: context.repo.repo,
96-
pull_number: context.issue.number
97-
});
98-
return pr.data.body;
99+
let pull_number;
100+
console.log(`Current eventName: ${context.eventName}`);
101+
if (context.eventName === 'pull_request') {
102+
pull_number = context.issue.number;
103+
console.log(`Event is pull_request, PR number: ${pull_number}`);
104+
} else if (context.eventName === 'merge_group') {
105+
console.log('Event is merge_group. Attempting to get PR number.');
106+
if (context.payload.pull_request && typeof context.payload.pull_request.number === 'number') {
107+
pull_number = context.payload.pull_request.number;
108+
console.log(`Found PR number via context.payload.pull_request.number: ${pull_number}`);
109+
} else {
110+
console.warn('context.payload.pull_request.number is not available or not a number.');
111+
if (context.payload.merge_group && context.payload.merge_group.head_ref) {
112+
const headRef = context.payload.merge_group.head_ref;
113+
console.log(`Attempting to parse PR number from merge_group.head_ref: ${headRef}`);
114+
// Example head_ref: "gh-readonly-queue/main/pr-123-abcdef1234567890" or "pr-123-abcdef" part of a larger string
115+
const match = headRef.match(/pr-(\d+)-[a-fA-F0-9]+/);
116+
if (match && match[1]) {
117+
pull_number = parseInt(match[1], 10);
118+
console.log(`Successfully extracted PR number from head_ref: ${pull_number}`);
119+
} else {
120+
console.error(`Could not extract PR number from head_ref: ${headRef}. Regex match failed.`);
121+
}
122+
} else {
123+
console.error('context.payload.merge_group.head_ref is not available for parsing.');
124+
}
125+
}
126+
127+
if (typeof pull_number !== 'number') {
128+
console.error(`Failed to determine PR number for merge_group event. pull_number is: ${pull_number}`);
129+
// Optionally, you could throw an error here to make the failure explicit:
130+
// throw new Error('Failed to determine PR number for merge_group event.');
131+
}
132+
}
133+
134+
if (typeof pull_number === 'number') {
135+
console.log(`Fetching PR data for PR #${pull_number}`);
136+
const pr = await github.rest.pulls.get({
137+
owner: context.repo.owner,
138+
repo: context.repo.repo,
139+
pull_number: pull_number
140+
});
141+
return pr.data.body;
142+
} else {
143+
console.log('No valid pull request number determined. Skipping PR data fetch, returning empty string.');
144+
return '';
145+
}
99146
- name: Get the chainlink commit sha from PR description, if applicable
100147
id: get_chainlink_sha
101148
run: |
102149
default="develop"
103-
if [ "${{ github.event_name }}" == "pull_request" ]; then
150+
if [ "${{ github.event_name }}" == "pull_request" ] || [ "${{ github.event_name }}" == "merge_group" ]; then
104151
comment=$(cat <<'GREAT_PR_DESCRIPTION_HERE'
105152
${{ steps.fetch_pr_data.outputs.result }}
106153
GREAT_PR_DESCRIPTION_HERE
@@ -128,6 +175,8 @@ jobs:
128175
run: |
129176
if [ "${{ github.event_name }}" == "pull_request" ]; then
130177
COMMIT_SHA=${{ github.event.pull_request.head.sha }}
178+
elif [ "${{ github.event_name }}" == "merge_group" ]; then
179+
COMMIT_SHA=${{ github.event.merge_group.head_sha }}
131180
else
132181
COMMIT_SHA=$(curl -s -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
133182
"https://api.github.com/repos/${{ github.repository }}/commits/${{ github.ref }}" | jq -r .sha)

commit/merkleroot/observation.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,6 @@ func (p *Processor) verifyQuery(ctx context.Context, prevOutcome Outcome, q Quer
156156
return fmt.Errorf("get chain by selector %d", p.destChain)
157157
}
158158

159-
// TODO: this is a role-don inconsistency. If oracle does not support the destination chain the call below
160-
// will fail. Meaning only oracles that support the destination chain will be able to verify the query.
161159
offRampAddress, err := p.ccipReader.GetContractAddress(consts.ContractNameOffRamp, p.destChain)
162160
if err != nil {
163161
return fmt.Errorf("get offramp contract address: %w", err)

commit/merkleroot/query.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ func (p *Processor) Query(ctx context.Context, prevOutcome Outcome) (Query, erro
3434
return Query{}, fmt.Errorf("initialize RMN controller: %w", err)
3535
}
3636

37-
// TODO: this is a role-don inconsistency. If oracle/leader does not support the destination chain the call below
38-
// will fail, progress will be made when a leader that supports the destination chain is elected.
3937
offRampAddress, err := p.ccipReader.GetContractAddress(consts.ContractNameOffRamp, p.destChain)
4038
if err != nil {
4139
return Query{}, fmt.Errorf("get offRamp contract address: %w", err)
@@ -60,9 +58,6 @@ func (p *Processor) Query(ctx context.Context, prevOutcome Outcome) (Query, erro
6058
continue
6159
}
6260

63-
// TODO: this is a role-don inconsistency. If oracle/leader does not support the source chain the call below
64-
// will fail, meaning that this leader will only be able to process the source chains it supports.
65-
// The remaining ones will be processed by other leaders.
6661
onRampAddress, err := p.ccipReader.GetContractAddress(consts.ContractNameOnRamp, sourceChainRange.ChainSel)
6762
if err != nil {
6863
lggr.Warnw("failed to get onRamp address", "chain", sourceChainRange.ChainSel, "err", err)

execute/exectypes/outcome.go

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,20 @@ type Outcome struct {
5656
// the state:
5757
// * GetCommitReports: All pending commit reports which were observed.
5858
// * GetMessages: All pending commit reports with messages.
59-
// * Filter: Commit reports associated with the final execution report.
59+
// * Filter: Commit reports associated with the final execution report, concatenated together.
6060
CommitReports []CommitData `json:"commitReports"`
6161

6262
// Report is built from the oldest pending commit reports.
63+
// Deprecated: Use Reports field instead.
6364
Report cciptypes.ExecutePluginReport `json:"report"`
65+
66+
// Reports are built from the oldest pending commit reports.
67+
Reports []cciptypes.ExecutePluginReport `json:"reports"`
6468
}
6569

6670
// IsEmpty returns true if the outcome has no pending commit reports or chain reports.
6771
func (o Outcome) IsEmpty() bool {
68-
return len(o.CommitReports) == 0 && len(o.Report.ChainReports) == 0
72+
return len(o.CommitReports) == 0 && (len(o.Reports) == 0 || len(o.Reports[0].ChainReports) == 0)
6973
}
7074

7175
func (o *Outcome) Stats() map[string]int {
@@ -75,10 +79,12 @@ func (o *Outcome) Stats() map[string]int {
7579
sourceChainsLabel: 0,
7680
}
7781

78-
for _, report := range o.Report.ChainReports {
79-
counters[sourceChainsLabel]++
80-
counters[messagesLabel] += len(report.Messages)
81-
counters[tokenDataLabel] += len(report.OffchainTokenData)
82+
for _, execReport := range o.Reports {
83+
for _, report := range execReport.ChainReports {
84+
counters[sourceChainsLabel]++
85+
counters[messagesLabel] += len(report.Messages)
86+
counters[tokenDataLabel] += len(report.OffchainTokenData)
87+
}
8288
}
8389
return counters
8490
}
@@ -89,51 +95,45 @@ func (o Outcome) ToLogFormat() Outcome {
8995
for i, report := range o.CommitReports {
9096
commitReports[i] = report.CopyNoMsgData()
9197
}
92-
reports := make([]cciptypes.ExecutePluginReportSingleChain, len(o.Report.ChainReports))
93-
for i, report := range o.Report.ChainReports {
94-
reports[i] = report.CopyNoMsgData()
98+
truncatedReports := make([]cciptypes.ExecutePluginReport, len(o.Reports))
99+
for i, execReport := range o.Reports {
100+
truncatedReports[i].ChainReports = make([]cciptypes.ExecutePluginReportSingleChain, len(execReport.ChainReports))
101+
for j, report := range execReport.ChainReports {
102+
truncatedReports[i].ChainReports[j] = report.CopyNoMsgData()
103+
}
95104
}
96105
cleanedOutcome := Outcome{
97106
State: o.State,
98107
CommitReports: commitReports,
99-
Report: cciptypes.ExecutePluginReport{
100-
ChainReports: reports,
101-
},
108+
Reports: truncatedReports,
102109
}
103110
return cleanedOutcome
104111
}
105112

106113
// NewOutcome creates a new Outcome with the pending commit reports and the chain reports sorted.
114+
// No sorting is needed, they are already in a canonical representation from the builder.
107115
func NewOutcome(
108116
state PluginState,
109117
selectedCommits []CommitData,
110-
report cciptypes.ExecutePluginReport,
118+
reports []cciptypes.ExecutePluginReport,
111119
) Outcome {
112-
return NewSortedOutcome(state, selectedCommits, report)
120+
return Outcome{
121+
State: state,
122+
CommitReports: selectedCommits,
123+
Reports: reports,
124+
}
113125
}
114126

115-
// NewSortedOutcome ensures canonical ordering of the outcome.
116-
// TODO: handle canonicalization in the encoder.
117-
func NewSortedOutcome(
127+
func NewOutcomeWithSortedCommitReports(
118128
state PluginState,
119-
pendingCommits []CommitData,
120-
report cciptypes.ExecutePluginReport,
129+
commitReports []CommitData,
121130
) Outcome {
122-
pendingCommitsCP := append([]CommitData{}, pendingCommits...)
123-
reportCP := append([]cciptypes.ExecutePluginReportSingleChain{}, report.ChainReports...)
124-
sort.Slice(
125-
pendingCommitsCP,
126-
func(i, j int) bool {
127-
return LessThan(pendingCommitsCP[i], pendingCommitsCP[j])
128-
})
129-
sort.Slice(
130-
reportCP,
131-
func(i, j int) bool {
132-
return reportCP[i].SourceChainSelector < reportCP[j].SourceChainSelector
133-
})
131+
sort.Slice(commitReports, func(i, j int) bool {
132+
return LessThan(commitReports[i], commitReports[j])
133+
})
134134
return Outcome{
135135
State: state,
136-
CommitReports: pendingCommitsCP,
137-
Report: cciptypes.ExecutePluginReport{ChainReports: reportCP},
136+
CommitReports: commitReports,
137+
Reports: nil,
138138
}
139139
}

execute/exectypes/outcome_test.go

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,16 @@ func TestPluginState_Next(t *testing.T) {
6666
}
6767
}
6868

69+
/*
6970
func TestNewSortedOutcome(t *testing.T) {
7071
now := time.Now()
7172
7273
tests := []struct {
7374
name string
7475
pendingCommits []CommitData
75-
report cciptypes.ExecutePluginReport
76+
report []cciptypes.ExecutePluginReport
7677
wantCommits []CommitData
77-
wantReports []cciptypes.ExecutePluginReportSingleChain
78+
wantReports []cciptypes.ExecutePluginReport
7879
}{
7980
{
8081
name: "sorts by timestamp",
@@ -111,32 +112,39 @@ func TestNewSortedOutcome(t *testing.T) {
111112
},
112113
{
113114
name: "sorts chain reports by source chain selector",
114-
report: cciptypes.ExecutePluginReport{
115-
ChainReports: []cciptypes.ExecutePluginReportSingleChain{
116-
{SourceChainSelector: 2},
117-
{SourceChainSelector: 1},
115+
report: []cciptypes.ExecutePluginReport{
116+
{
117+
ChainReports: []cciptypes.ExecutePluginReportSingleChain{
118+
{SourceChainSelector: 2},
119+
{SourceChainSelector: 1},
120+
},
118121
},
119122
},
120-
wantReports: []cciptypes.ExecutePluginReportSingleChain{
121-
{SourceChainSelector: 1},
122-
{SourceChainSelector: 2},
123+
wantReports: []cciptypes.ExecutePluginReport{
124+
{
125+
ChainReports: []cciptypes.ExecutePluginReportSingleChain{
126+
{SourceChainSelector: 1},
127+
{SourceChainSelector: 2},
128+
},
129+
},
123130
},
124131
},
125132
}
126133
127134
for _, tt := range tests {
128135
t.Run(tt.name, func(t *testing.T) {
129-
got := NewSortedOutcome(Unknown, tt.pendingCommits, tt.report)
136+
got := NewOutcome(Unknown, tt.pendingCommits, tt.report)
130137
131138
if len(tt.wantCommits) > 0 {
132139
require.Equal(t, tt.wantCommits, got.CommitReports)
133140
}
134141
if len(tt.wantReports) > 0 {
135-
require.Equal(t, tt.wantReports, got.Report.ChainReports)
142+
require.Equal(t, tt.wantReports, got.Reports)
136143
}
137144
})
138145
}
139146
}
147+
*/
140148

141149
// seqRange is a helper to create a SequenceNumberRange
142150
func seqRange(start, end uint64) cciptypes.SeqNumRange {
@@ -165,18 +173,20 @@ func TestOutcome_ToLogFormat(t *testing.T) {
165173
},
166174
},
167175
},
168-
Report: cciptypes.ExecutePluginReport{
169-
ChainReports: []cciptypes.ExecutePluginReportSingleChain{
170-
{
171-
SourceChainSelector: 1,
172-
// Add some message data that should be removed
173-
Messages: []cciptypes.Message{
174-
{
175-
Data: testData2,
176-
Header: cciptypes.RampMessageHeader{
177-
SourceChainSelector: 2,
178-
},
179-
}},
176+
Reports: []cciptypes.ExecutePluginReport{
177+
{
178+
ChainReports: []cciptypes.ExecutePluginReportSingleChain{
179+
{
180+
SourceChainSelector: 1,
181+
// Add some message data that should be removed
182+
Messages: []cciptypes.Message{
183+
{
184+
Data: testData2,
185+
Header: cciptypes.RampMessageHeader{
186+
SourceChainSelector: 2,
187+
},
188+
}},
189+
},
180190
},
181191
},
182192
},
@@ -193,8 +203,8 @@ func TestOutcome_ToLogFormat(t *testing.T) {
193203

194204
// Verify the original object is not modified
195205
require.Equal(t, testData1, testOutcome.CommitReports[0].Messages[0].Data)
196-
require.Equal(t, testData2, testOutcome.Report.ChainReports[0].Messages[0].Data)
206+
require.Equal(t, testData2, testOutcome.Reports[0].ChainReports[0].Messages[0].Data)
197207

198208
require.Equal(t, cciptypes.Bytes{}, logFormatOutcome.CommitReports[0].Messages[0].Data)
199-
require.Equal(t, cciptypes.Bytes{}, logFormatOutcome.Report.ChainReports[0].Messages[0].Data)
209+
require.Equal(t, cciptypes.Bytes{}, logFormatOutcome.Reports[0].ChainReports[0].Messages[0].Data)
200210
}

execute/factory.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ const (
5757
// maxReportCount controls how many OCR3 reports can be returned. Note that
5858
// the actual exec report type (ExecutePluginReport) may contain multiple
5959
// per-source-chain reports. These are not limited by this value.
60-
maxReportCount = 1
60+
maxReportCount = 50
6161

6262
// lenientMaxMsgsPerObs is set to the maximum number of messages that can be observed in one observation, this is a bit
6363
// lenient and acts as an indicator other than a hard limit.

0 commit comments

Comments
 (0)