Skip to content

Commit

Permalink
add batching test
Browse files Browse the repository at this point in the history
  • Loading branch information
makramkd committed Nov 19, 2024
1 parent f579844 commit dc7879b
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 76 deletions.
4 changes: 2 additions & 2 deletions deployment/ccip/changeset/add_chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,10 +225,10 @@ func TestAddChainInbound(t *testing.T) {
ExtraArgs: nil,
})
require.NoError(t,
ccipdeployment.ConfirmCommitWithExpectedSeqNumRange(t, e.Env.Chains[initialDeploy[0]], e.Env.Chains[newChain], state.Chains[newChain].OffRamp, &startBlock, cciptypes.SeqNumRange{
commonutils.JustError(ccipdeployment.ConfirmCommitWithExpectedSeqNumRange(t, e.Env.Chains[initialDeploy[0]], e.Env.Chains[newChain], state.Chains[newChain].OffRamp, &startBlock, cciptypes.SeqNumRange{
cciptypes.SeqNum(1),
cciptypes.SeqNum(msgSentEvent.SequenceNumber),
}))
})))
require.NoError(t,
commonutils.JustError(ccipdeployment.ConfirmExecWithSeqNr(t, e.Env.Chains[initialDeploy[0]], e.Env.Chains[newChain], state.Chains[newChain].OffRamp, &startBlock, msgSentEvent.SequenceNumber)))

Expand Down
21 changes: 11 additions & 10 deletions deployment/ccip/test_assertions.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"golang.org/x/sync/errgroup"

"github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3"
commonutils "github.com/smartcontractkit/chainlink-common/pkg/utils"
"github.com/smartcontractkit/chainlink-common/pkg/utils/tests"
"github.com/smartcontractkit/chainlink/deployment/environment/memory"

Expand Down Expand Up @@ -176,7 +177,7 @@ func ConfirmCommitForAllWithExpectedSeqNums(
return nil
}

return ConfirmCommitWithExpectedSeqNumRange(
return commonutils.JustError(ConfirmCommitWithExpectedSeqNumRange(
t,
srcChain,
dstChain,
Expand All @@ -185,7 +186,7 @@ func ConfirmCommitForAllWithExpectedSeqNums(
ccipocr3.SeqNumRange{
ccipocr3.SeqNum(expectedSeqNums[dstChain.Selector]),
ccipocr3.SeqNum(expectedSeqNums[dstChain.Selector]),
})
}))
})
}
}
Expand Down Expand Up @@ -220,14 +221,14 @@ func ConfirmCommitWithExpectedSeqNumRange(
offRamp *offramp.OffRamp,
startBlock *uint64,
expectedSeqNumRange ccipocr3.SeqNumRange,
) error {
) (*offramp.OffRampCommitReportAccepted, error) {
sink := make(chan *offramp.OffRampCommitReportAccepted)
subscription, err := offRamp.WatchCommitReportAccepted(&bind.WatchOpts{
Context: context.Background(),
Start: startBlock,
}, sink)
if err != nil {
return fmt.Errorf("error to subscribe CommitReportAccepted : %w", err)
return nil, fmt.Errorf("error to subscribe CommitReportAccepted : %w", err)
}

defer subscription.Unsubscribe()
Expand Down Expand Up @@ -268,17 +269,17 @@ func ConfirmCommitWithExpectedSeqNumRange(
if mr.SourceChainSelector == src.Selector &&
uint64(expectedSeqNumRange.Start()) >= mr.MinSeqNr &&
uint64(expectedSeqNumRange.End()) <= mr.MaxSeqNr {
t.Logf("Received commit report for [%d, %d] on selector %d from source selector %d expected seq nr range %s, token prices: %v",
mr.MinSeqNr, mr.MaxSeqNr, dest.Selector, src.Selector, expectedSeqNumRange.String(), event.PriceUpdates.TokenPriceUpdates)
return nil
t.Logf("Received commit report for [%d, %d] on selector %d from source selector %d expected seq nr range %s, token prices: %v, tx hash: %s",
mr.MinSeqNr, mr.MaxSeqNr, dest.Selector, src.Selector, expectedSeqNumRange.String(), event.PriceUpdates.TokenPriceUpdates, event.Raw.TxHash.String())
return event, nil
}
}
}
}
case subErr := <-subscription.Err():
return fmt.Errorf("subscription error: %w", subErr)
return nil, fmt.Errorf("subscription error: %w", subErr)
case <-timer.C:
return fmt.Errorf("timed out after waiting %s duration for commit report on chain selector %d from source selector %d expected seq nr range %s",
return nil, fmt.Errorf("timed out after waiting %s duration for commit report on chain selector %d from source selector %d expected seq nr range %s",
duration.String(), dest.Selector, src.Selector, expectedSeqNumRange.String())
case report := <-sink:
if len(report.MerkleRoots) > 0 {
Expand All @@ -290,7 +291,7 @@ func ConfirmCommitWithExpectedSeqNumRange(
uint64(expectedSeqNumRange.End()) <= mr.MaxSeqNr {
t.Logf("Received commit report for [%d, %d] on selector %d from source selector %d expected seq nr range %s, token prices: %v",
mr.MinSeqNr, mr.MaxSeqNr, dest.Selector, src.Selector, expectedSeqNumRange.String(), report.PriceUpdates.TokenPriceUpdates)
return nil
return report, nil
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions deployment/ccip/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -523,10 +523,10 @@ func ConfirmRequestOnSourceAndDest(t *testing.T, env deployment.Environment, sta

fmt.Printf("Request sent for seqnr %d", msgSentEvent.SequenceNumber)
require.NoError(t,
ConfirmCommitWithExpectedSeqNumRange(t, env.Chains[sourceCS], env.Chains[destCS], state.Chains[destCS].OffRamp, &startBlock, cciptypes.SeqNumRange{
commonutils.JustError(ConfirmCommitWithExpectedSeqNumRange(t, env.Chains[sourceCS], env.Chains[destCS], state.Chains[destCS].OffRamp, &startBlock, cciptypes.SeqNumRange{
cciptypes.SeqNum(msgSentEvent.SequenceNumber),
cciptypes.SeqNum(msgSentEvent.SequenceNumber),
}))
})))

fmt.Printf("Commit confirmed for seqnr %d", msgSentEvent.SequenceNumber)
require.NoError(
Expand Down
224 changes: 162 additions & 62 deletions integration-tests/smoke/ccip_batching_test.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
package smoke

import (
"context"
"fmt"
"math/big"
"sync"
"testing"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
"golang.org/x/exp/maps"

"github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3"
jobv1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/job"
"github.com/smartcontractkit/chainlink/deployment"
ccdeploy "github.com/smartcontractkit/chainlink/deployment/ccip"
"github.com/smartcontractkit/chainlink/deployment/ccip/changeset"
"github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testsetups"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/multicall3"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/onramp"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"
"github.com/smartcontractkit/chainlink/v2/core/logger"
)
Expand Down Expand Up @@ -83,80 +90,173 @@ func Test_CCIPBatching(t *testing.T) {
require.NoError(t, ccdeploy.AddLaneWithDefaultPrices(e.Env, state, sourceChain1, destChain))
require.NoError(t, ccdeploy.AddLaneWithDefaultPrices(e.Env, state, sourceChain2, destChain))

// var (
// replayed bool
// nonce map[uint64]uint64
// senderSource1 = common.LeftPadBytes(e.Env.Chains[sourceChain1].DeployerKey.From.Bytes(), 32)
// senderSource2 = common.LeftPadBytes(e.Env.Chains[sourceChain2].DeployerKey.From.Bytes(), 32)
// outSource1 messagingTestCaseOutput
// outSource2 messagingTestCaseOutput
// setupSource1 = testCaseSetup{
// t: t,
// sender: senderSource1,
// deployedEnv: e,
// onchainState: state,
// sourceChain: sourceChain1,
// destChain: destChain,
// }
// setupSource2 = testCaseSetup{
// t: t,
// sender: senderSource2,
// deployedEnv: e,
// onchainState: state,
// sourceChain: sourceChain2,
// destChain: destChain,
// }
// )
const (
numMessages = 5
)

t.Run("batch data only messages from multiple sources", func(t *testing.T) {
var wg sync.WaitGroup

wg.Add(1)
go func(sourceChainSelector uint64) {
defer wg.Done()
sendMessages(
ctx,
t,
e.Env.Chains[sourceChainSelector],
e.Env.Chains[sourceChainSelector].DeployerKey,
state.Chains[sourceChainSelector].OnRamp,
state.Chains[sourceChainSelector].Router,
state.Chains[sourceChainSelector].Multicall3,
destChain,
numMessages,
common.LeftPadBytes(state.Chains[destChain].Receiver.Address().Bytes(), 32),
)
}(sourceChain1)

wg.Add(1)
go func(sourceChainSelector uint64) {
defer wg.Done()
sendMessages(
ctx,
t,
e.Env.Chains[sourceChainSelector],
e.Env.Chains[sourceChainSelector].DeployerKey,
state.Chains[sourceChainSelector].OnRamp,
state.Chains[sourceChainSelector].Router,
state.Chains[sourceChainSelector].Multicall3,
destChain,
numMessages,
common.LeftPadBytes(state.Chains[destChain].Receiver.Address().Bytes(), 32),
)
}(sourceChain2)

wg.Wait()

// confirm the commit reports
var (
sourceChain1Report *offramp.OffRampCommitReportAccepted
sourceChain2Report *offramp.OffRampCommitReportAccepted
)
wg.Add(1)
go func() {
defer wg.Done()
var err error
sourceChain1Report, err = ccdeploy.ConfirmCommitWithExpectedSeqNumRange(t,
e.Env.Chains[sourceChain1],
e.Env.Chains[destChain],
state.Chains[destChain].OffRamp,
nil,
ccipocr3.NewSeqNumRange(ccipocr3.SeqNum(1), ccipocr3.SeqNum(numMessages)),
)
require.NoErrorf(t, err, "failed to confirm commit from chain %d", sourceChain1)
}()

wg.Add(1)
go func() {
defer wg.Done()
var err error
sourceChain2Report, err = ccdeploy.ConfirmCommitWithExpectedSeqNumRange(t,
e.Env.Chains[sourceChain2],
e.Env.Chains[destChain],
state.Chains[destChain].OffRamp,
nil,
ccipocr3.NewSeqNumRange(ccipocr3.SeqNum(1), ccipocr3.SeqNum(numMessages)),
)
require.NoErrorf(t, err, "failed to confirm commit from chain %d", sourceChain2)
}()

t.Log("waiting for commit report")
wg.Wait()

// the reports should be the same for both, since both roots should be batched within
// that one report.
require.Equal(t, sourceChain1Report, sourceChain2Report, "commit reports should be the same")
})

t.Run("batch mix of data only messages and token messages from multiple sources", func(t *testing.T) {
// Generate some messages, on each source.
// Send them from a multicall contract, i.e multiple ccip messages in the same tx.
// assert they are committed in the same batch.
})
}

func sendMessages(
ctx context.Context,
t *testing.T,
sourceChain deployment.Chain,
sourceTransactOpts *bind.TransactOpts,
sourceOnRamp *onramp.OnRamp,
sourceRouter *router.Router,
sourceMulticall3 *multicall3.Multicall3,
destChainSelector uint64,
numMessages int,
receiver []byte,
) {
calls, totalValue := genMessages(
ctx,
t,
sourceRouter,
destChainSelector,
numMessages,
receiver,
)

// Send the tx with the messages through the multicall
tx, err := sourceMulticall3.Aggregate3Value(
&bind.TransactOpts{
From: sourceTransactOpts.From,
Signer: sourceTransactOpts.Signer,
Value: totalValue,
},
calls,
)
_, err = deployment.ConfirmIfNoError(sourceChain, tx, err)
require.NoError(t, err, "failed to confirm tx")

// check that the message was emitted
iter, err := sourceOnRamp.FilterCCIPMessageSent(
nil, []uint64{destChainSelector}, nil,
)
require.NoError(t, err)

// there should be numMessages messages emitted
for i := 0; i < numMessages; i++ {
require.Truef(t, iter.Next(), "expected %d messages, got %d", numMessages, i+1)
t.Logf("Message id of msg %d: %x", i, iter.Event.Message.Header.MessageId[:])
}
}

func genMessages(
ctx context.Context,
t *testing.T,
sourceRouter *router.Router,
destChainSelector uint64,
count int,
receiver []byte,
) (calls []multicall3.Multicall3Call3Value, totalValue *big.Int) {
totalValue = big.NewInt(0)
for i := 0; i < count; i++ {
msg := router.ClientEVM2AnyMessage{
Receiver: common.LeftPadBytes(state.Chains[destChain].Receiver.Address().Bytes(), 32),
Data: []byte("hello world"),
Receiver: receiver,
Data: []byte(fmt.Sprintf("hello world %d", i)),
TokenAmounts: nil,
FeeToken: common.HexToAddress("0x0"),
ExtraArgs: nil,
}
fee, err := state.Chains[sourceChain1].Router.GetFee(&bind.CallOpts{
Context: ctx,
}, destChain, msg)
require.NoError(t, err)

// Send the tx with the message through the multicall
calldata := ccdeploy.CCIPSendCalldata(t, destChain, msg)
tx, err := state.Chains[sourceChain1].Multicall3.Aggregate3Value(
&bind.TransactOpts{
From: e.Env.Chains[sourceChain1].DeployerKey.From,
Signer: e.Env.Chains[sourceChain1].DeployerKey.Signer,
Value: fee,
},
[]multicall3.Multicall3Call3Value{
{
Target: state.Chains[sourceChain1].Router.Address(),
AllowFailure: false,
CallData: calldata,
Value: fee,
},
},
)
require.NoError(t, err)
_, err = e.Env.Chains[sourceChain1].Confirm(tx)
fee, err := sourceRouter.GetFee(&bind.CallOpts{Context: ctx}, destChainSelector, msg)
require.NoError(t, err)

// check that the message was emitted
iter, err := state.Chains[sourceChain1].OnRamp.FilterCCIPMessageSent(
nil, []uint64{destChain}, nil,
)
require.NoError(t, err)
require.True(t, iter.Next())
require.Equal(t, msg.Receiver, iter.Event.Message.Receiver)
})
totalValue.Add(totalValue, fee)

t.Run("batch mix of data only messages and token messages from multiple sources", func(t *testing.T) {
// Generate some messages, on each source.
// Send them from a multicall contract, i.e multiple ccip messages in the same tx.
// assert they are committed in the same batch.
})
calls = append(calls, multicall3.Multicall3Call3Value{
Target: sourceRouter.Address(),
AllowFailure: false,
CallData: ccdeploy.CCIPSendCalldata(t, destChainSelector, msg),
Value: fee,
})
}

return calls, totalValue
}

0 comments on commit dc7879b

Please sign in to comment.