|
1 | 1 | package interop |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "encoding/hex" |
4 | 5 | "math/big" |
5 | 6 | "testing" |
6 | 7 |
|
| 8 | + "github.com/ethereum-optimism/optimism/devnet-sdk/contracts/bindings" |
7 | 9 | "github.com/ethereum-optimism/optimism/devnet-sdk/contracts/constants" |
8 | 10 | "github.com/ethereum-optimism/optimism/devnet-sdk/system" |
9 | 11 | "github.com/ethereum-optimism/optimism/devnet-sdk/testing/systest" |
10 | 12 | "github.com/ethereum-optimism/optimism/devnet-sdk/testing/testlib/validators" |
11 | 13 | sdktypes "github.com/ethereum-optimism/optimism/devnet-sdk/types" |
| 14 | + "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait" |
12 | 15 | "github.com/ethereum-optimism/optimism/op-service/testlog" |
13 | 16 | "github.com/ethereum/go-ethereum/common" |
| 17 | + "github.com/ethereum/go-ethereum/core/vm" |
14 | 18 | "github.com/ethereum/go-ethereum/log" |
15 | 19 | "github.com/stretchr/testify/require" |
16 | 20 | ) |
17 | 21 |
|
18 | | -func initiateMessageScenario(sourceChainIdx, destChainIdx uint64, walletGetter validators.WalletGetter) systest.InteropSystemTestFunc { |
| 22 | +func messagePassingScenario(lowLevelSystemGetter validators.LowLevelSystemGetter, sourceChainIdx, destChainIdx uint64, sourceWalletGetter, destWalletGetter validators.WalletGetter) systest.InteropSystemTestFunc { |
19 | 23 | return func(t systest.T, sys system.InteropSystem) { |
20 | 24 | ctx := t.Context() |
| 25 | + llsys := lowLevelSystemGetter(ctx) |
21 | 26 |
|
22 | 27 | logger := testlog.Logger(t, log.LevelInfo) |
23 | | - logger = logger.With("test", "TestInitiateMessage", "devnet", sys.Identifier()) |
| 28 | + logger = logger.With("test", "TestMessagePassing", "devnet", sys.Identifier()) |
24 | 29 |
|
25 | 30 | chainA := sys.L2s()[sourceChainIdx] |
26 | | - chainB := sys.L2s()[destChainIdx] |
| 31 | + chainB := llsys.L2s()[destChainIdx] |
27 | 32 |
|
28 | | - logger = logger.With("sourceChain", chainA.ID(), "destChain", chainB.ID()) |
| 33 | + logger.Info("chain info", "sourceChain", chainA.ID(), "destChain", chainB.ID()) |
29 | 34 |
|
30 | | - // userA is funded at chainA and want to send message to chainB |
31 | | - userA := walletGetter(ctx) |
| 35 | + // userA is funded at chainA and want to initialize message at chain A |
| 36 | + userA := sourceWalletGetter(ctx) |
| 37 | + // userB is funded at chainB and want to execute message to chainB |
| 38 | + userB := destWalletGetter(ctx) |
| 39 | + |
| 40 | + sha256PrecompileAddr := common.BytesToAddress([]byte{0x2}) |
| 41 | + dummyMessage := []byte("l33t message") |
32 | 42 |
|
33 | 43 | // Initiate message |
34 | | - dummyAddress := common.Address{0x13, 0x37} |
35 | | - dummyMessage := []byte{0x13, 0x33, 0x33, 0x37} |
36 | | - logger.Info("Initiate message", "address", dummyAddress, "message", dummyMessage) |
37 | | - require.NoError(t, userA.InitiateMessage(chainB.ID(), dummyAddress, dummyMessage).Send(ctx).Wait()) |
| 44 | + logger.Info("Initiate message", "address", sha256PrecompileAddr, "message", dummyMessage) |
| 45 | + initResult := userA.InitiateMessage(chainB.ID(), sha256PrecompileAddr, dummyMessage).Send(ctx) |
| 46 | + require.NoError(t, initResult.Wait()) |
| 47 | + |
| 48 | + initReceipt, ok := initResult.Info().(system.Receipt) |
| 49 | + require.True(t, ok) |
| 50 | + logger.Info("Initiate message", "txHash", initReceipt.TxHash().Hex()) |
| 51 | + logs := initReceipt.Logs() |
| 52 | + // We are directly calling sendMessage, so we expect single log for SentMessage event |
| 53 | + require.Equal(t, 1, len(logs), "expected single log") |
| 54 | + log := logs[0] |
| 55 | + |
| 56 | + // Build sentMessage for message execution |
| 57 | + blockNumber := initReceipt.BlockNumber() |
| 58 | + blockA, err := chainA.Node().BlockByNumber(ctx, blockNumber) |
| 59 | + require.NoError(t, err) |
| 60 | + blockTimeA := big.NewInt(int64(blockA.Time())) |
| 61 | + logger.Info("Initiate message was included at", "timestamp", blockTimeA.String()) |
| 62 | + |
| 63 | + sentMessage := []byte{} |
| 64 | + for _, topic := range log.Topics { |
| 65 | + sentMessage = append(sentMessage, topic.Bytes()...) |
| 66 | + } |
| 67 | + sentMessage = append(sentMessage, log.Data...) |
| 68 | + |
| 69 | + // Build identifier for message execution |
| 70 | + logIndex := big.NewInt(int64(log.Index)) |
| 71 | + identifier := bindings.Identifier{ |
| 72 | + Origin: constants.L2ToL2CrossDomainMessenger, |
| 73 | + BlockNumber: blockNumber, |
| 74 | + LogIndex: logIndex, |
| 75 | + Timestamp: blockTimeA, |
| 76 | + ChainId: chainA.ID(), |
| 77 | + } |
| 78 | + |
| 79 | + // Execute message |
| 80 | + logger.Info("Execute message", "address", sha256PrecompileAddr, "message", dummyMessage) |
| 81 | + execResult := userB.ExecuteMessage(identifier, sentMessage).Send(ctx) |
| 82 | + require.NoError(t, execResult.Wait()) |
| 83 | + |
| 84 | + execReceipt, ok := execResult.Info().(system.Receipt) |
| 85 | + require.True(t, ok) |
| 86 | + |
| 87 | + execTxHash := execReceipt.TxHash() |
| 88 | + logger.Info("Execute message", "txHash", execTxHash.Hex()) |
| 89 | + |
| 90 | + blockNumberB := execReceipt.BlockNumber() |
| 91 | + blockB, err := chainB.Node().BlockByNumber(ctx, blockNumberB) |
| 92 | + require.NoError(t, err) |
| 93 | + blockTimeB := big.NewInt(int64(blockB.Time())) |
| 94 | + logger.Info("Execute message was included at", "timestamp", blockTimeB.String()) |
| 95 | + |
| 96 | + // Validation that message has passed and got executed successfully |
| 97 | + gethClient, err := chainB.GethClient() |
| 98 | + require.NoError(t, err) |
| 99 | + |
| 100 | + trace, err := wait.DebugTraceTx(ctx, gethClient, execTxHash) |
| 101 | + require.NoError(t, err) |
| 102 | + |
| 103 | + precompile := vm.PrecompiledContractsHomestead[sha256PrecompileAddr] |
| 104 | + expected, err := precompile.Run(dummyMessage) |
| 105 | + require.NoError(t, err) |
| 106 | + logger.Info("sha256 computed offchain", "value", hex.EncodeToString(expected)) |
| 107 | + |
| 108 | + // length of sha256 image is 32 |
| 109 | + output := trace.CallTrace.Output |
| 110 | + require.GreaterOrEqual(t, len(output), 32) |
| 111 | + actual := []byte(output[len(output)-32:]) |
| 112 | + logger.Info("sha256 computed onchain", "value", hex.EncodeToString(actual)) |
| 113 | + |
| 114 | + require.Equal(t, expected, actual) |
38 | 115 | } |
39 | 116 | } |
40 | 117 |
|
41 | | -func TestInteropSystemInitiateMessage(t *testing.T) { |
| 118 | +// TestMessagePassing checks the basic functionality of message passing two interoperable chains. |
| 119 | +// Scenario: Source chain initiates message to make destination chain execute sha256 precompile. |
| 120 | +func TestMessagePassing(t *testing.T) { |
42 | 121 | sourceChainIdx := uint64(0) |
43 | 122 | destChainIdx := uint64(1) |
44 | | - walletGetter, fundsValidator := validators.AcquireL2WalletWithFunds(sourceChainIdx, sdktypes.NewBalance(big.NewInt(1.0*constants.ETH))) |
| 123 | + sourceWalletGetter, sourcefundsValidator := validators.AcquireL2WalletWithFunds(sourceChainIdx, sdktypes.NewBalance(big.NewInt(1.0*constants.ETH))) |
| 124 | + destWalletGetter, destfundsValiator := validators.AcquireL2WalletWithFunds(destChainIdx, sdktypes.NewBalance(big.NewInt(1.0*constants.ETH))) |
| 125 | + lowLevelSystemGetter, lowLevelSystemValidator := validators.AcquireLowLevelSystem() |
45 | 126 |
|
46 | 127 | systest.InteropSystemTest(t, |
47 | | - initiateMessageScenario(sourceChainIdx, destChainIdx, walletGetter), |
48 | | - fundsValidator, |
| 128 | + messagePassingScenario(lowLevelSystemGetter, sourceChainIdx, destChainIdx, sourceWalletGetter, destWalletGetter), |
| 129 | + sourcefundsValidator, |
| 130 | + destfundsValiator, |
| 131 | + lowLevelSystemValidator, |
49 | 132 | ) |
50 | 133 | } |
0 commit comments