Commit 791fd687 authored by OptimismBot's avatar OptimismBot Committed by GitHub

Merge pull request #5488 from ethereum-optimism/aj/e2e-helpers

op-e2e: Extract system test helpers
parents 5c51b177 f522fdea
...@@ -20,10 +20,7 @@ import ( ...@@ -20,10 +20,7 @@ import (
// TestERC20BridgeDeposits tests the the L1StandardBridge bridge ERC20 // TestERC20BridgeDeposits tests the the L1StandardBridge bridge ERC20
// functionality. // functionality.
func TestERC20BridgeDeposits(t *testing.T) { func TestERC20BridgeDeposits(t *testing.T) {
parallel(t) InitParallel(t)
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
......
package op_e2e
import (
"flag"
"os"
"testing"
"github.com/ethereum/go-ethereum/log"
)
var enableParallelTesting bool = true
// Init testing to enable test flags
var _ = func() bool {
testing.Init()
return true
}()
var verboseGethNodes bool
func init() {
flag.BoolVar(&verboseGethNodes, "gethlogs", true, "Enable logs on geth nodes")
flag.Parse()
if os.Getenv("OP_E2E_DISABLE_PARALLEL") == "true" {
enableParallelTesting = false
}
}
func InitParallel(t *testing.T) {
t.Helper()
if enableParallelTesting {
t.Parallel()
}
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
}
...@@ -121,7 +121,7 @@ var hardcodedSlots = []storageSlot{ ...@@ -121,7 +121,7 @@ var hardcodedSlots = []storageSlot{
} }
func TestMigration(t *testing.T) { func TestMigration(t *testing.T) {
parallel(t) InitParallel(t)
if !config.enabled { if !config.enabled {
t.Skipf("skipping migration tests") t.Skipf("skipping migration tests")
return return
......
...@@ -20,7 +20,7 @@ import ( ...@@ -20,7 +20,7 @@ import (
// TestMissingGasLimit tests that op-geth cannot build a block without gas limit while optimism is active in the chain config. // TestMissingGasLimit tests that op-geth cannot build a block without gas limit while optimism is active in the chain config.
func TestMissingGasLimit(t *testing.T) { func TestMissingGasLimit(t *testing.T) {
parallel(t) InitParallel(t)
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
cfg.DeployConfig.FundDevAccounts = false cfg.DeployConfig.FundDevAccounts = false
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
...@@ -43,7 +43,7 @@ func TestMissingGasLimit(t *testing.T) { ...@@ -43,7 +43,7 @@ func TestMissingGasLimit(t *testing.T) {
// TestInvalidDepositInFCU runs an invalid deposit through a FCU/GetPayload/NewPayload/FCU set of calls. // TestInvalidDepositInFCU runs an invalid deposit through a FCU/GetPayload/NewPayload/FCU set of calls.
// This tests that deposits must always allow the block to be built even if they are invalid. // This tests that deposits must always allow the block to be built even if they are invalid.
func TestInvalidDepositInFCU(t *testing.T) { func TestInvalidDepositInFCU(t *testing.T) {
parallel(t) InitParallel(t)
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
cfg.DeployConfig.FundDevAccounts = false cfg.DeployConfig.FundDevAccounts = false
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
...@@ -78,7 +78,7 @@ func TestInvalidDepositInFCU(t *testing.T) { ...@@ -78,7 +78,7 @@ func TestInvalidDepositInFCU(t *testing.T) {
} }
func TestPreregolith(t *testing.T) { func TestPreregolith(t *testing.T) {
parallel(t) InitParallel(t)
futureTimestamp := hexutil.Uint64(4) futureTimestamp := hexutil.Uint64(4)
tests := []struct { tests := []struct {
name string name string
...@@ -90,6 +90,7 @@ func TestPreregolith(t *testing.T) { ...@@ -90,6 +90,7 @@ func TestPreregolith(t *testing.T) {
for _, test := range tests { for _, test := range tests {
test := test test := test
t.Run("GasUsed_"+test.name, func(t *testing.T) { t.Run("GasUsed_"+test.name, func(t *testing.T) {
InitParallel(t)
// Setup an L2 EE and create a client connection to the engine. // Setup an L2 EE and create a client connection to the engine.
// We also need to setup a L1 Genesis to create the rollup genesis. // We also need to setup a L1 Genesis to create the rollup genesis.
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
...@@ -138,6 +139,7 @@ func TestPreregolith(t *testing.T) { ...@@ -138,6 +139,7 @@ func TestPreregolith(t *testing.T) {
}) })
t.Run("DepositNonce_"+test.name, func(t *testing.T) { t.Run("DepositNonce_"+test.name, func(t *testing.T) {
InitParallel(t)
// Setup an L2 EE and create a client connection to the engine. // Setup an L2 EE and create a client connection to the engine.
// We also need to setup a L1 Genesis to create the rollup genesis. // We also need to setup a L1 Genesis to create the rollup genesis.
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
...@@ -196,6 +198,7 @@ func TestPreregolith(t *testing.T) { ...@@ -196,6 +198,7 @@ func TestPreregolith(t *testing.T) {
}) })
t.Run("UnusedGasConsumed_"+test.name, func(t *testing.T) { t.Run("UnusedGasConsumed_"+test.name, func(t *testing.T) {
InitParallel(t)
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
cfg.DeployConfig.L2GenesisRegolithTimeOffset = test.regolithTime cfg.DeployConfig.L2GenesisRegolithTimeOffset = test.regolithTime
...@@ -237,6 +240,7 @@ func TestPreregolith(t *testing.T) { ...@@ -237,6 +240,7 @@ func TestPreregolith(t *testing.T) {
}) })
t.Run("AllowSystemTx_"+test.name, func(t *testing.T) { t.Run("AllowSystemTx_"+test.name, func(t *testing.T) {
InitParallel(t)
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
cfg.DeployConfig.L2GenesisRegolithTimeOffset = test.regolithTime cfg.DeployConfig.L2GenesisRegolithTimeOffset = test.regolithTime
...@@ -258,7 +262,7 @@ func TestPreregolith(t *testing.T) { ...@@ -258,7 +262,7 @@ func TestPreregolith(t *testing.T) {
} }
func TestRegolith(t *testing.T) { func TestRegolith(t *testing.T) {
parallel(t) InitParallel(t)
tests := []struct { tests := []struct {
name string name string
regolithTime hexutil.Uint64 regolithTime hexutil.Uint64
...@@ -273,6 +277,7 @@ func TestRegolith(t *testing.T) { ...@@ -273,6 +277,7 @@ func TestRegolith(t *testing.T) {
for _, test := range tests { for _, test := range tests {
test := test test := test
t.Run("GasUsedIsAccurate_"+test.name, func(t *testing.T) { t.Run("GasUsedIsAccurate_"+test.name, func(t *testing.T) {
InitParallel(t)
// Setup an L2 EE and create a client connection to the engine. // Setup an L2 EE and create a client connection to the engine.
// We also need to setup a L1 Genesis to create the rollup genesis. // We also need to setup a L1 Genesis to create the rollup genesis.
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
...@@ -324,6 +329,7 @@ func TestRegolith(t *testing.T) { ...@@ -324,6 +329,7 @@ func TestRegolith(t *testing.T) {
}) })
t.Run("DepositNonceCorrect_"+test.name, func(t *testing.T) { t.Run("DepositNonceCorrect_"+test.name, func(t *testing.T) {
InitParallel(t)
// Setup an L2 EE and create a client connection to the engine. // Setup an L2 EE and create a client connection to the engine.
// We also need to setup a L1 Genesis to create the rollup genesis. // We also need to setup a L1 Genesis to create the rollup genesis.
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
...@@ -385,6 +391,7 @@ func TestRegolith(t *testing.T) { ...@@ -385,6 +391,7 @@ func TestRegolith(t *testing.T) {
}) })
t.Run("ReturnUnusedGasToPool_"+test.name, func(t *testing.T) { t.Run("ReturnUnusedGasToPool_"+test.name, func(t *testing.T) {
InitParallel(t)
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
cfg.DeployConfig.L2GenesisRegolithTimeOffset = &test.regolithTime cfg.DeployConfig.L2GenesisRegolithTimeOffset = &test.regolithTime
...@@ -427,6 +434,7 @@ func TestRegolith(t *testing.T) { ...@@ -427,6 +434,7 @@ func TestRegolith(t *testing.T) {
}) })
t.Run("RejectSystemTx_"+test.name, func(t *testing.T) { t.Run("RejectSystemTx_"+test.name, func(t *testing.T) {
InitParallel(t)
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
cfg.DeployConfig.L2GenesisRegolithTimeOffset = &test.regolithTime cfg.DeployConfig.L2GenesisRegolithTimeOffset = &test.regolithTime
...@@ -448,6 +456,7 @@ func TestRegolith(t *testing.T) { ...@@ -448,6 +456,7 @@ func TestRegolith(t *testing.T) {
}) })
t.Run("IncludeGasRefunds_"+test.name, func(t *testing.T) { t.Run("IncludeGasRefunds_"+test.name, func(t *testing.T) {
InitParallel(t)
// Simple constructor that is prefixed to the actual contract code // Simple constructor that is prefixed to the actual contract code
// Results in the contract code being returned as the code for the new contract // Results in the contract code being returned as the code for the new contract
deployPrefixSize := byte(16) deployPrefixSize := byte(16)
......
...@@ -18,7 +18,7 @@ import ( ...@@ -18,7 +18,7 @@ import (
) )
func TestVerifyL2OutputRoot(t *testing.T) { func TestVerifyL2OutputRoot(t *testing.T) {
parallel(t) InitParallel(t)
ctx := context.Background() ctx := context.Background()
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
......
...@@ -2,10 +2,8 @@ package op_e2e ...@@ -2,10 +2,8 @@ package op_e2e
import ( import (
"context" "context"
"flag"
"fmt" "fmt"
"math/big" "math/big"
"os"
"testing" "testing"
"time" "time"
...@@ -17,7 +15,6 @@ import ( ...@@ -17,7 +15,6 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/ethclient/gethclient"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
...@@ -36,41 +33,12 @@ import ( ...@@ -36,41 +33,12 @@ import (
"github.com/ethereum-optimism/optimism/op-node/rollup/driver" "github.com/ethereum-optimism/optimism/op-node/rollup/driver"
"github.com/ethereum-optimism/optimism/op-node/sources" "github.com/ethereum-optimism/optimism/op-node/sources"
"github.com/ethereum-optimism/optimism/op-node/testlog" "github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum-optimism/optimism/op-node/withdrawals"
"github.com/ethereum-optimism/optimism/op-service/backoff" "github.com/ethereum-optimism/optimism/op-service/backoff"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof" oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
) )
var enableParallelTesting bool = true
// Init testing to enable test flags
var _ = func() bool {
testing.Init()
return true
}()
var verboseGethNodes bool
func init() {
flag.BoolVar(&verboseGethNodes, "gethlogs", true, "Enable logs on geth nodes")
flag.Parse()
if os.Getenv("OP_E2E_DISABLE_PARALLEL") == "true" {
enableParallelTesting = false
}
}
func parallel(t *testing.T) {
t.Helper()
if enableParallelTesting {
t.Parallel()
}
}
func TestL2OutputSubmitter(t *testing.T) { func TestL2OutputSubmitter(t *testing.T) {
parallel(t) InitParallel(t)
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
cfg.NonFinalizedProposals = true // speed up the time till we see output proposals cfg.NonFinalizedProposals = true // speed up the time till we see output proposals
...@@ -141,10 +109,7 @@ func TestL2OutputSubmitter(t *testing.T) { ...@@ -141,10 +109,7 @@ func TestL2OutputSubmitter(t *testing.T) {
// TestSystemE2E sets up a L1 Geth node, a rollup node, and a L2 geth node and then confirms that L1 deposits are reflected on L2. // TestSystemE2E sets up a L1 Geth node, a rollup node, and a L2 geth node and then confirms that L1 deposits are reflected on L2.
// All nodes are run in process (but are the full nodes, not mocked or stubbed). // All nodes are run in process (but are the full nodes, not mocked or stubbed).
func TestSystemE2E(t *testing.T) { func TestSystemE2E(t *testing.T) {
parallel(t) InitParallel(t)
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
...@@ -165,37 +130,20 @@ func TestSystemE2E(t *testing.T) { ...@@ -165,37 +130,20 @@ func TestSystemE2E(t *testing.T) {
// Send Transaction & wait for success // Send Transaction & wait for success
fromAddr := sys.cfg.Secrets.Addresses().Alice fromAddr := sys.cfg.Secrets.Addresses().Alice
// Find deposit contract ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
depositContract, err := bindings.NewOptimismPortal(predeploys.DevOptimismPortalAddr, l1Client)
require.Nil(t, err)
// Create signer
opts, err := bind.NewKeyedTransactorWithChainID(ethPrivKey, cfg.L1ChainIDBig())
require.Nil(t, err)
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel() defer cancel()
startBalance, err := l2Verif.BalanceAt(ctx, fromAddr, nil) startBalance, err := l2Verif.BalanceAt(ctx, fromAddr, nil)
require.Nil(t, err) require.Nil(t, err)
// Finally send TX // Send deposit transaction
opts, err := bind.NewKeyedTransactorWithChainID(ethPrivKey, cfg.L1ChainIDBig())
require.Nil(t, err)
mintAmount := big.NewInt(1_000_000_000_000) mintAmount := big.NewInt(1_000_000_000_000)
opts.Value = mintAmount opts.Value = mintAmount
tx, err := depositContract.DepositTransaction(opts, fromAddr, common.Big0, 1_000_000, false, nil) SendDepositTx(t, cfg, l1Client, l2Verif, opts, func(l2Opts *DepositTxOpts) {})
require.Nil(t, err, "with deposit tx")
receipt, err := waitForTransaction(tx.Hash(), l1Client, 3*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.Nil(t, err, "Waiting for deposit tx on L1")
reconstructedDep, err := derive.UnmarshalDepositLogEvent(receipt.Logs[0])
require.NoError(t, err, "Could not reconstruct L2 Deposit")
tx = types.NewTx(reconstructedDep)
receipt, err = waitForTransaction(tx.Hash(), l2Verif, 6*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.NoError(t, err)
require.Equal(t, receipt.Status, types.ReceiptStatusSuccessful)
// Confirm balance // Confirm balance
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second) ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second)
defer cancel() defer cancel()
endBalance, err := l2Verif.BalanceAt(ctx, fromAddr, nil) endBalance, err := l2Verif.BalanceAt(ctx, fromAddr, nil)
require.Nil(t, err) require.Nil(t, err)
...@@ -205,25 +153,12 @@ func TestSystemE2E(t *testing.T) { ...@@ -205,25 +153,12 @@ func TestSystemE2E(t *testing.T) {
require.Equal(t, mintAmount, diff, "Did not get expected balance change") require.Equal(t, mintAmount, diff, "Did not get expected balance change")
// Submit TX to L2 sequencer node // Submit TX to L2 sequencer node
toAddr := common.Address{0xff, 0xff} receipt := SendL2Tx(t, cfg, l2Seq, ethPrivKey, func(opts *TxOpts) {
tx = types.MustSignNewTx(ethPrivKey, types.LatestSignerForChainID(cfg.L2ChainIDBig()), &types.DynamicFeeTx{ opts.Value = big.NewInt(1_000_000_000)
ChainID: cfg.L2ChainIDBig(), opts.Nonce = 1 // Already have deposit
Nonce: 1, // Already have deposit opts.ToAddr = &common.Address{0xff, 0xff}
To: &toAddr, opts.VerifyOnClients(l2Verif)
Value: big.NewInt(1_000_000_000),
GasTipCap: big.NewInt(10),
GasFeeCap: big.NewInt(200),
Gas: 21000,
}) })
err = l2Seq.SendTransaction(context.Background(), tx)
require.Nil(t, err, "Sending L2 tx to sequencer")
_, err = waitForTransaction(tx.Hash(), l2Seq, 3*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.Nil(t, err, "Waiting for L2 tx on sequencer")
receipt, err = waitForTransaction(tx.Hash(), l2Verif, 10*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.Nil(t, err, "Waiting for L2 tx on verifier")
require.Equal(t, types.ReceiptStatusSuccessful, receipt.Status, "TX should have succeeded")
// Verify blocks match after batch submission on verifiers and sequencers // Verify blocks match after batch submission on verifiers and sequencers
verifBlock, err := l2Verif.BlockByNumber(context.Background(), receipt.BlockNumber) verifBlock, err := l2Verif.BlockByNumber(context.Background(), receipt.BlockNumber)
...@@ -249,10 +184,7 @@ func TestSystemE2E(t *testing.T) { ...@@ -249,10 +184,7 @@ func TestSystemE2E(t *testing.T) {
// TestConfirmationDepth runs the rollup with both sequencer and verifier not immediately processing the tip of the chain. // TestConfirmationDepth runs the rollup with both sequencer and verifier not immediately processing the tip of the chain.
func TestConfirmationDepth(t *testing.T) { func TestConfirmationDepth(t *testing.T) {
parallel(t) InitParallel(t)
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
cfg.DeployConfig.SequencerWindowSize = 4 cfg.DeployConfig.SequencerWindowSize = 4
...@@ -300,10 +232,7 @@ func TestConfirmationDepth(t *testing.T) { ...@@ -300,10 +232,7 @@ func TestConfirmationDepth(t *testing.T) {
// TestPendingGasLimit tests the configuration of the gas limit of the pending block, // TestPendingGasLimit tests the configuration of the gas limit of the pending block,
// and if it does not conflict with the regular gas limit on the verifier or sequencer. // and if it does not conflict with the regular gas limit on the verifier or sequencer.
func TestPendingGasLimit(t *testing.T) { func TestPendingGasLimit(t *testing.T) {
parallel(t) InitParallel(t)
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
...@@ -360,10 +289,7 @@ func TestPendingGasLimit(t *testing.T) { ...@@ -360,10 +289,7 @@ func TestPendingGasLimit(t *testing.T) {
// TestFinalize tests if L2 finalizes after sufficient time after L1 finalizes // TestFinalize tests if L2 finalizes after sufficient time after L1 finalizes
func TestFinalize(t *testing.T) { func TestFinalize(t *testing.T) {
parallel(t) InitParallel(t)
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
...@@ -388,10 +314,7 @@ func TestFinalize(t *testing.T) { ...@@ -388,10 +314,7 @@ func TestFinalize(t *testing.T) {
} }
func TestMintOnRevertedDeposit(t *testing.T) { func TestMintOnRevertedDeposit(t *testing.T) {
parallel(t) InitParallel(t)
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
sys, err := cfg.Start() sys, err := cfg.Start()
...@@ -401,9 +324,6 @@ func TestMintOnRevertedDeposit(t *testing.T) { ...@@ -401,9 +324,6 @@ func TestMintOnRevertedDeposit(t *testing.T) {
l1Client := sys.Clients["l1"] l1Client := sys.Clients["l1"]
l2Verif := sys.Clients["verifier"] l2Verif := sys.Clients["verifier"]
// Find deposit contract
depositContract, err := bindings.NewOptimismPortal(predeploys.DevOptimismPortalAddr, l1Client)
require.Nil(t, err)
l1Node := sys.Nodes["l1"] l1Node := sys.Nodes["l1"]
// create signer // create signer
...@@ -425,19 +345,12 @@ func TestMintOnRevertedDeposit(t *testing.T) { ...@@ -425,19 +345,12 @@ func TestMintOnRevertedDeposit(t *testing.T) {
toAddr := common.Address{0xff, 0xff} toAddr := common.Address{0xff, 0xff}
mintAmount := big.NewInt(9_000_000) mintAmount := big.NewInt(9_000_000)
opts.Value = mintAmount opts.Value = mintAmount
value := new(big.Int).Mul(common.Big2, startBalance) // trigger a revert by transferring more than we have available SendDepositTx(t, cfg, l1Client, l2Verif, opts, func(l2Opts *DepositTxOpts) {
tx, err := depositContract.DepositTransaction(opts, toAddr, value, 1_000_000, false, nil) l2Opts.ToAddr = toAddr
require.Nil(t, err, "with deposit tx") // trigger a revert by transferring more than we have available
l2Opts.Value = new(big.Int).Mul(common.Big2, startBalance)
receipt, err := waitForTransaction(tx.Hash(), l1Client, 3*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second) l2Opts.ExpectedStatus = types.ReceiptStatusFailed
require.Nil(t, err, "Waiting for deposit tx on L1") })
reconstructedDep, err := derive.UnmarshalDepositLogEvent(receipt.Logs[0])
require.NoError(t, err, "Could not reconstruct L2 Deposit")
tx = types.NewTx(reconstructedDep)
receipt, err = waitForTransaction(tx.Hash(), l2Verif, 10*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.NoError(t, err)
require.Equal(t, receipt.Status, types.ReceiptStatusFailed)
// Confirm balance // Confirm balance
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second) ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
...@@ -462,10 +375,7 @@ func TestMintOnRevertedDeposit(t *testing.T) { ...@@ -462,10 +375,7 @@ func TestMintOnRevertedDeposit(t *testing.T) {
} }
func TestMissingBatchE2E(t *testing.T) { func TestMissingBatchE2E(t *testing.T) {
parallel(t) InitParallel(t)
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
// Note this test zeroes the balance of the batch-submitter to make the batches unable to go into L1. // Note this test zeroes the balance of the batch-submitter to make the batches unable to go into L1.
// The test logs may look scary, but this is expected: // The test logs may look scary, but this is expected:
// 'batcher unable to publish transaction role=batcher err="insufficient funds for gas * price + value"' // 'batcher unable to publish transaction role=batcher err="insufficient funds for gas * price + value"'
...@@ -488,22 +398,10 @@ func TestMissingBatchE2E(t *testing.T) { ...@@ -488,22 +398,10 @@ func TestMissingBatchE2E(t *testing.T) {
ethPrivKey := cfg.Secrets.Alice ethPrivKey := cfg.Secrets.Alice
// Submit TX to L2 sequencer node // Submit TX to L2 sequencer node
toAddr := common.Address{0xff, 0xff} receipt := SendL2Tx(t, cfg, l2Seq, ethPrivKey, func(opts *TxOpts) {
tx := types.MustSignNewTx(ethPrivKey, types.LatestSignerForChainID(cfg.L2ChainIDBig()), &types.DynamicFeeTx{ opts.ToAddr = &common.Address{0xff, 0xff}
ChainID: cfg.L2ChainIDBig(), opts.Value = big.NewInt(1_000_000_000)
Nonce: 0,
To: &toAddr,
Value: big.NewInt(1_000_000_000),
GasTipCap: big.NewInt(10),
GasFeeCap: big.NewInt(200),
Gas: 21000,
}) })
err = l2Seq.SendTransaction(context.Background(), tx)
require.Nil(t, err, "Sending L2 tx to sequencer")
// Let it show up on the unsafe chain
receipt, err := waitForTransaction(tx.Hash(), l2Seq, 3*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.Nil(t, err, "Waiting for L2 tx on sequencer")
// Wait until the block it was first included in shows up in the safe chain on the verifier // Wait until the block it was first included in shows up in the safe chain on the verifier
_, err = waitForBlock(receipt.BlockNumber, l2Verif, time.Duration((sys.RollupConfig.SeqWindowSize+4)*cfg.DeployConfig.L1BlockTime)*time.Second) _, err = waitForBlock(receipt.BlockNumber, l2Verif, time.Duration((sys.RollupConfig.SeqWindowSize+4)*cfg.DeployConfig.L1BlockTime)*time.Second)
...@@ -512,7 +410,7 @@ func TestMissingBatchE2E(t *testing.T) { ...@@ -512,7 +410,7 @@ func TestMissingBatchE2E(t *testing.T) {
// Assert that the transaction is not found on the verifier // Assert that the transaction is not found on the verifier
ctx, cancel := context.WithTimeout(context.Background(), time.Second) ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel() defer cancel()
_, err = l2Verif.TransactionReceipt(ctx, tx.Hash()) _, err = l2Verif.TransactionReceipt(ctx, receipt.TxHash)
require.Equal(t, ethereum.NotFound, err, "Found transaction in verifier when it should not have been included") require.Equal(t, ethereum.NotFound, err, "Found transaction in verifier when it should not have been included")
// Wait a short time for the L2 reorg to occur on the sequencer as well. // Wait a short time for the L2 reorg to occur on the sequencer as well.
...@@ -585,10 +483,7 @@ func L1InfoFromState(ctx context.Context, contract *bindings.L1Block, l2Number * ...@@ -585,10 +483,7 @@ func L1InfoFromState(ctx context.Context, contract *bindings.L1Block, l2Number *
// TestSystemMockP2P sets up a L1 Geth node, a rollup node, and a L2 geth node and then confirms that // TestSystemMockP2P sets up a L1 Geth node, a rollup node, and a L2 geth node and then confirms that
// the nodes can sync L2 blocks before they are confirmed on L1. // the nodes can sync L2 blocks before they are confirmed on L1.
func TestSystemMockP2P(t *testing.T) { func TestSystemMockP2P(t *testing.T) {
parallel(t) InitParallel(t)
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
// Disable batcher, so we don't sync from L1 & set a large sequence window so we only have unsafe blocks // Disable batcher, so we don't sync from L1 & set a large sequence window so we only have unsafe blocks
...@@ -648,35 +543,20 @@ func TestSystemMockP2P(t *testing.T) { ...@@ -648,35 +543,20 @@ func TestSystemMockP2P(t *testing.T) {
ethPrivKey := cfg.Secrets.Alice ethPrivKey := cfg.Secrets.Alice
// Submit TX to L2 sequencer node // Submit TX to L2 sequencer node
toAddr := common.Address{0xff, 0xff} receiptSeq := SendL2Tx(t, cfg, l2Seq, ethPrivKey, func(opts *TxOpts) {
tx := types.MustSignNewTx(ethPrivKey, types.LatestSignerForChainID(cfg.L2ChainIDBig()), &types.DynamicFeeTx{ opts.ToAddr = &common.Address{0xff, 0xff}
ChainID: cfg.L2ChainIDBig(), opts.Value = big.NewInt(1_000_000_000)
Nonce: 0,
To: &toAddr,
Value: big.NewInt(1_000_000_000),
GasTipCap: big.NewInt(10),
GasFeeCap: big.NewInt(200),
Gas: 21000,
})
err = l2Seq.SendTransaction(context.Background(), tx)
require.Nil(t, err, "Sending L2 tx to sequencer")
// Wait for tx to be mined on the L2 sequencer chain // Wait until the block it was first included in shows up in the safe chain on the verifier
receiptSeq, err := waitForTransaction(tx.Hash(), l2Seq, 5*time.Minute) opts.VerifyOnClients(l2Verif)
require.Nil(t, err, "Waiting for L2 tx on sequencer") })
// Wait until the block it was first included in shows up in the safe chain on the verifier
receiptVerif, err := waitForTransaction(tx.Hash(), l2Verif, 5*time.Minute)
require.Nil(t, err, "Waiting for L2 tx on verifier")
require.Equal(t, receiptSeq, receiptVerif)
// Verify that everything that was received was published // Verify that everything that was received was published
require.GreaterOrEqual(t, len(published), len(received)) require.GreaterOrEqual(t, len(published), len(received))
require.ElementsMatch(t, received, published[:len(received)]) require.ElementsMatch(t, received, published[:len(received)])
// Verify that the tx was received via p2p // Verify that the tx was received via p2p
require.Contains(t, received, receiptVerif.BlockHash) require.Contains(t, received, receiptSeq.BlockHash)
} }
// TestSystemRPCAltSync sets up a L1 Geth node, a rollup node, and a L2 geth node and then confirms that // TestSystemRPCAltSync sets up a L1 Geth node, a rollup node, and a L2 geth node and then confirms that
...@@ -691,10 +571,7 @@ func TestSystemMockP2P(t *testing.T) { ...@@ -691,10 +571,7 @@ func TestSystemMockP2P(t *testing.T) {
// 7. Wait for the verifier to sync the unsafe chain into the safe chain. // 7. Wait for the verifier to sync the unsafe chain into the safe chain.
// 8. Verify that the TX is included in the verifier's safe chain. // 8. Verify that the TX is included in the verifier's safe chain.
func TestSystemRPCAltSync(t *testing.T) { func TestSystemRPCAltSync(t *testing.T) {
parallel(t) InitParallel(t)
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
// the default is nil, but this may change in the future. // the default is nil, but this may change in the future.
...@@ -736,31 +613,16 @@ func TestSystemRPCAltSync(t *testing.T) { ...@@ -736,31 +613,16 @@ func TestSystemRPCAltSync(t *testing.T) {
ethPrivKey := cfg.Secrets.Alice ethPrivKey := cfg.Secrets.Alice
// Submit a TX to L2 sequencer node // Submit a TX to L2 sequencer node
toAddr := common.Address{0xff, 0xff} receiptSeq := SendL2Tx(t, cfg, l2Seq, ethPrivKey, func(opts *TxOpts) {
tx := types.MustSignNewTx(ethPrivKey, types.LatestSignerForChainID(cfg.L2ChainIDBig()), &types.DynamicFeeTx{ opts.ToAddr = &common.Address{0xff, 0xff}
ChainID: cfg.L2ChainIDBig(), opts.Value = big.NewInt(1_000_000_000)
Nonce: 0,
To: &toAddr,
Value: big.NewInt(1_000_000_000),
GasTipCap: big.NewInt(10),
GasFeeCap: big.NewInt(200),
Gas: 21000,
})
err = l2Seq.SendTransaction(context.Background(), tx)
require.Nil(t, err, "Sending L2 tx to sequencer")
// Wait for tx to be mined on the L2 sequencer chain
receiptSeq, err := waitForTransaction(tx.Hash(), l2Seq, 6*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
require.Nil(t, err, "Waiting for L2 tx on sequencer")
// Wait for alt RPC sync to pick up the blocks on the sequencer chain // Wait for alt RPC sync to pick up the blocks on the sequencer chain
receiptVerif, err := waitForTransaction(tx.Hash(), l2Verif, 12*time.Duration(sys.RollupConfig.BlockTime)*time.Second) opts.VerifyOnClients(l2Verif)
require.Nil(t, err, "Waiting for L2 tx on verifier") })
require.Equal(t, receiptSeq, receiptVerif)
// Verify that the tx was received via RPC sync (P2P is disabled) // Verify that the tx was received via RPC sync (P2P is disabled)
require.Contains(t, received, eth.BlockID{Hash: receiptVerif.BlockHash, Number: receiptVerif.BlockNumber.Uint64()}.String()) require.Contains(t, received, eth.BlockID{Hash: receiptSeq.BlockHash, Number: receiptSeq.BlockNumber.Uint64()}.String())
// Verify that everything that was received was published // Verify that everything that was received was published
require.GreaterOrEqual(t, len(published), len(received)) require.GreaterOrEqual(t, len(published), len(received))
...@@ -768,10 +630,7 @@ func TestSystemRPCAltSync(t *testing.T) { ...@@ -768,10 +630,7 @@ func TestSystemRPCAltSync(t *testing.T) {
} }
func TestSystemP2PAltSync(t *testing.T) { func TestSystemP2PAltSync(t *testing.T) {
parallel(t) InitParallel(t)
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
...@@ -828,22 +687,10 @@ func TestSystemP2PAltSync(t *testing.T) { ...@@ -828,22 +687,10 @@ func TestSystemP2PAltSync(t *testing.T) {
ethPrivKey := cfg.Secrets.Alice ethPrivKey := cfg.Secrets.Alice
// Submit a TX to L2 sequencer node // Submit a TX to L2 sequencer node
toAddr := common.Address{0xff, 0xff} receiptSeq := SendL2Tx(t, cfg, l2Seq, ethPrivKey, func(opts *TxOpts) {
tx := types.MustSignNewTx(ethPrivKey, types.LatestSignerForChainID(cfg.L2ChainIDBig()), &types.DynamicFeeTx{ opts.ToAddr = &common.Address{0xff, 0xff}
ChainID: cfg.L2ChainIDBig(), opts.Value = big.NewInt(1_000_000_000)
Nonce: 0,
To: &toAddr,
Value: big.NewInt(1_000_000_000),
GasTipCap: big.NewInt(10),
GasFeeCap: big.NewInt(200),
Gas: 21000,
}) })
err = l2Seq.SendTransaction(context.Background(), tx)
require.Nil(t, err, "Sending L2 tx to sequencer")
// Wait for tx to be mined on the L2 sequencer chain
receiptSeq, err := waitForTransaction(tx.Hash(), l2Seq, 6*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
require.Nil(t, err, "Waiting for L2 tx on sequencer")
// Gossip is able to respond to IWANT messages for the duration of heartbeat_time * message_window = 0.5 * 12 = 6 // Gossip is able to respond to IWANT messages for the duration of heartbeat_time * message_window = 0.5 * 12 = 6
// Wait till we pass that, and then we'll have missed some blocks that cannot be retrieved in any way from gossip // Wait till we pass that, and then we'll have missed some blocks that cannot be retrieved in any way from gossip
...@@ -907,7 +754,7 @@ func TestSystemP2PAltSync(t *testing.T) { ...@@ -907,7 +754,7 @@ func TestSystemP2PAltSync(t *testing.T) {
l2Verif := ethclient.NewClient(rpc) l2Verif := ethclient.NewClient(rpc)
// It may take a while to sync, but eventually we should see the sequenced data show up // It may take a while to sync, but eventually we should see the sequenced data show up
receiptVerif, err := waitForTransaction(tx.Hash(), l2Verif, 100*time.Duration(sys.RollupConfig.BlockTime)*time.Second) receiptVerif, err := waitForTransaction(receiptSeq.TxHash, l2Verif, 100*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
require.Nil(t, err, "Waiting for L2 tx on verifier") require.Nil(t, err, "Waiting for L2 tx on verifier")
require.Equal(t, receiptSeq, receiptVerif) require.Equal(t, receiptSeq, receiptVerif)
...@@ -924,10 +771,7 @@ func TestSystemP2PAltSync(t *testing.T) { ...@@ -924,10 +771,7 @@ func TestSystemP2PAltSync(t *testing.T) {
func TestSystemDenseTopology(t *testing.T) { func TestSystemDenseTopology(t *testing.T) {
t.Skip("Skipping dense topology test to avoid flakiness. @refcell address in p2p scoring pr.") t.Skip("Skipping dense topology test to avoid flakiness. @refcell address in p2p scoring pr.")
parallel(t) InitParallel(t)
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
// slow down L1 blocks so we can see the L2 blocks arrive well before the L1 blocks do. // slow down L1 blocks so we can see the L2 blocks arrive well before the L1 blocks do.
...@@ -1003,35 +847,13 @@ func TestSystemDenseTopology(t *testing.T) { ...@@ -1003,35 +847,13 @@ func TestSystemDenseTopology(t *testing.T) {
ethPrivKey := cfg.Secrets.Alice ethPrivKey := cfg.Secrets.Alice
// Submit TX to L2 sequencer node // Submit TX to L2 sequencer node
toAddr := common.Address{0xff, 0xff} receiptSeq := SendL2Tx(t, cfg, l2Seq, ethPrivKey, func(opts *TxOpts) {
tx := types.MustSignNewTx(ethPrivKey, types.LatestSignerForChainID(cfg.L2ChainIDBig()), &types.DynamicFeeTx{ opts.ToAddr = &common.Address{0xff, 0xff}
ChainID: cfg.L2ChainIDBig(), opts.Value = big.NewInt(1_000_000_000)
Nonce: 0,
To: &toAddr,
Value: big.NewInt(1_000_000_000),
GasTipCap: big.NewInt(10),
GasFeeCap: big.NewInt(200),
Gas: 21000,
})
err = l2Seq.SendTransaction(context.Background(), tx)
require.NoError(t, err, "Sending L2 tx to sequencer")
// Wait for tx to be mined on the L2 sequencer chain
receiptSeq, err := waitForTransaction(tx.Hash(), l2Seq, 10*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
require.NoError(t, err, "Waiting for L2 tx on sequencer")
// Wait until the block it was first included in shows up in the safe chain on the verifier // Wait until the block it was first included in shows up in the safe chain on the verifiers
receiptVerif, err := waitForTransaction(tx.Hash(), l2Verif, 10*time.Duration(sys.RollupConfig.BlockTime)*time.Second) opts.VerifyOnClients(l2Verif, l2Verif2, l2Verif3)
require.NoError(t, err, "Waiting for L2 tx on verifier") })
require.Equal(t, receiptSeq, receiptVerif)
receiptVerif, err = waitForTransaction(tx.Hash(), l2Verif2, 10*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
require.NoError(t, err, "Waiting for L2 tx on verifier2")
require.Equal(t, receiptSeq, receiptVerif)
receiptVerif, err = waitForTransaction(tx.Hash(), l2Verif3, 10*time.Duration(sys.RollupConfig.BlockTime)*time.Second)
require.NoError(t, err, "Waiting for L2 tx on verifier3")
require.Equal(t, receiptSeq, receiptVerif)
// Verify that everything that was received was published // Verify that everything that was received was published
require.GreaterOrEqual(t, len(published), len(received1)) require.GreaterOrEqual(t, len(published), len(received1))
...@@ -1042,16 +864,13 @@ func TestSystemDenseTopology(t *testing.T) { ...@@ -1042,16 +864,13 @@ func TestSystemDenseTopology(t *testing.T) {
require.ElementsMatch(t, published, received3[:len(published)]) require.ElementsMatch(t, published, received3[:len(published)])
// Verify that the tx was received via p2p // Verify that the tx was received via p2p
require.Contains(t, received1, receiptVerif.BlockHash) require.Contains(t, received1, receiptSeq.BlockHash)
require.Contains(t, received2, receiptVerif.BlockHash) require.Contains(t, received2, receiptSeq.BlockHash)
require.Contains(t, received3, receiptVerif.BlockHash) require.Contains(t, received3, receiptSeq.BlockHash)
} }
func TestL1InfoContract(t *testing.T) { func TestL1InfoContract(t *testing.T) {
parallel(t) InitParallel(t)
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
...@@ -1176,10 +995,7 @@ func calcL1GasUsed(data []byte, overhead *big.Int) *big.Int { ...@@ -1176,10 +995,7 @@ func calcL1GasUsed(data []byte, overhead *big.Int) *big.Int {
// balance changes on L1 and L2 and has to include gas fees in the balance checks. // balance changes on L1 and L2 and has to include gas fees in the balance checks.
// It does not check that the withdrawal can be executed prior to the end of the finality period. // It does not check that the withdrawal can be executed prior to the end of the finality period.
func TestWithdrawals(t *testing.T) { func TestWithdrawals(t *testing.T) {
parallel(t) InitParallel(t)
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
cfg.DeployConfig.FinalizationPeriodSeconds = 2 // 2s finalization period cfg.DeployConfig.FinalizationPeriodSeconds = 2 // 2s finalization period
...@@ -1196,10 +1012,6 @@ func TestWithdrawals(t *testing.T) { ...@@ -1196,10 +1012,6 @@ func TestWithdrawals(t *testing.T) {
ethPrivKey := cfg.Secrets.Alice ethPrivKey := cfg.Secrets.Alice
fromAddr := crypto.PubkeyToAddress(ethPrivKey.PublicKey) fromAddr := crypto.PubkeyToAddress(ethPrivKey.PublicKey)
// Find deposit contract
depositContract, err := bindings.NewOptimismPortal(predeploys.DevOptimismPortalAddr, l1Client)
require.Nil(t, err)
// Create L1 signer // Create L1 signer
opts, err := bind.NewKeyedTransactorWithChainID(ethPrivKey, cfg.L1ChainIDBig()) opts, err := bind.NewKeyedTransactorWithChainID(ethPrivKey, cfg.L1ChainIDBig())
require.Nil(t, err) require.Nil(t, err)
...@@ -1210,26 +1022,12 @@ func TestWithdrawals(t *testing.T) { ...@@ -1210,26 +1022,12 @@ func TestWithdrawals(t *testing.T) {
startBalance, err := l2Verif.BalanceAt(ctx, fromAddr, nil) startBalance, err := l2Verif.BalanceAt(ctx, fromAddr, nil)
require.Nil(t, err) require.Nil(t, err)
// Finally send TX // Send deposit tx
mintAmount := big.NewInt(1_000_000_000_000) mintAmount := big.NewInt(1_000_000_000_000)
opts.Value = mintAmount opts.Value = mintAmount
tx, err := depositContract.DepositTransaction(opts, fromAddr, common.Big0, 1_000_000, false, nil) SendDepositTx(t, cfg, l1Client, l2Verif, opts, func(l2Opts *DepositTxOpts) {
require.Nil(t, err, "with deposit tx") l2Opts.Value = common.Big0
})
receipt, err := waitForTransaction(tx.Hash(), l1Client, 3*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.Nil(t, err, "Waiting for deposit tx on L1")
// Bind L2 Withdrawer Contract
l2withdrawer, err := bindings.NewL2ToL1MessagePasser(predeploys.L2ToL1MessagePasserAddr, l2Seq)
require.Nil(t, err, "binding withdrawer on L2")
// Wait for deposit to arrive
reconstructedDep, err := derive.UnmarshalDepositLogEvent(receipt.Logs[0])
require.NoError(t, err, "Could not reconstruct L2 Deposit")
tx = types.NewTx(reconstructedDep)
receipt, err = waitForTransaction(tx.Hash(), l2Verif, 10*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.NoError(t, err)
require.Equal(t, receipt.Status, types.ReceiptStatusSuccessful)
// Confirm L2 balance // Confirm L2 balance
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second) ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
...@@ -1247,17 +1045,11 @@ func TestWithdrawals(t *testing.T) { ...@@ -1247,17 +1045,11 @@ func TestWithdrawals(t *testing.T) {
startBalance, err = l2Seq.BalanceAt(ctx, fromAddr, nil) startBalance, err = l2Seq.BalanceAt(ctx, fromAddr, nil)
require.Nil(t, err) require.Nil(t, err)
// Intiate Withdrawal
withdrawAmount := big.NewInt(500_000_000_000) withdrawAmount := big.NewInt(500_000_000_000)
l2opts, err := bind.NewKeyedTransactorWithChainID(ethPrivKey, cfg.L2ChainIDBig()) tx, receipt := SendWithdrawal(t, cfg, l2Seq, ethPrivKey, func(opts *WithdrawalTxOpts) {
require.Nil(t, err) opts.Value = withdrawAmount
l2opts.Value = withdrawAmount opts.VerifyOnClients(l2Verif)
tx, err = l2withdrawer.InitiateWithdrawal(l2opts, fromAddr, big.NewInt(21000), nil) })
require.Nil(t, err, "sending initiate withdraw tx")
receipt, err = waitForTransaction(tx.Hash(), l2Verif, 10*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.Nil(t, err, "withdrawal initiated on L2 sequencer")
require.Equal(t, receipt.Status, types.ReceiptStatusSuccessful, "transaction failed")
// Verify L2 balance after withdrawal // Verify L2 balance after withdrawal
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second) ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
...@@ -1283,80 +1075,7 @@ func TestWithdrawals(t *testing.T) { ...@@ -1283,80 +1075,7 @@ func TestWithdrawals(t *testing.T) {
startBalance, err = l1Client.BalanceAt(ctx, fromAddr, nil) startBalance, err = l1Client.BalanceAt(ctx, fromAddr, nil)
require.Nil(t, err) require.Nil(t, err)
// Get l2BlockNumber for proof generation proveReceipt, finalizeReceipt := ProveAndFinalizeWithdrawal(t, cfg, l1Client, sys.Nodes["verifier"], ethPrivKey, receipt)
ctx, cancel = context.WithTimeout(context.Background(), 40*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
defer cancel()
blockNumber, err := withdrawals.WaitForFinalizationPeriod(ctx, l1Client, predeploys.DevOptimismPortalAddr, receipt.BlockNumber)
require.Nil(t, err)
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
header, err = l2Verif.HeaderByNumber(ctx, new(big.Int).SetUint64(blockNumber))
require.Nil(t, err)
rpcClient, err := rpc.Dial(sys.Nodes["verifier"].WSEndpoint())
require.Nil(t, err)
proofCl := gethclient.New(rpcClient)
receiptCl := ethclient.NewClient(rpcClient)
// Now create withdrawal
oracle, err := bindings.NewL2OutputOracleCaller(predeploys.DevL2OutputOracleAddr, l1Client)
require.Nil(t, err)
params, err := withdrawals.ProveWithdrawalParameters(context.Background(), proofCl, receiptCl, tx.Hash(), header, oracle)
require.Nil(t, err)
portal, err := bindings.NewOptimismPortal(predeploys.DevOptimismPortalAddr, l1Client)
require.Nil(t, err)
opts.Value = nil
// Prove withdrawal
tx, err = portal.ProveWithdrawalTransaction(
opts,
bindings.TypesWithdrawalTransaction{
Nonce: params.Nonce,
Sender: params.Sender,
Target: params.Target,
Value: params.Value,
GasLimit: params.GasLimit,
Data: params.Data,
},
params.L2OutputIndex,
params.OutputRootProof,
params.WithdrawalProof,
)
require.Nil(t, err)
// Ensure that our withdrawal was proved successfully
proveReceipt, err := waitForTransaction(tx.Hash(), l1Client, 3*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.Nil(t, err, "prove withdrawal")
require.Equal(t, types.ReceiptStatusSuccessful, proveReceipt.Status)
// Wait for finalization and then create the Finalized Withdrawal Transaction
ctx, cancel = context.WithTimeout(context.Background(), 30*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
defer cancel()
_, err = withdrawals.WaitForFinalizationPeriod(ctx, l1Client, predeploys.DevOptimismPortalAddr, header.Number)
require.Nil(t, err)
// Finalize withdrawal
tx, err = portal.FinalizeWithdrawalTransaction(
opts,
bindings.TypesWithdrawalTransaction{
Nonce: params.Nonce,
Sender: params.Sender,
Target: params.Target,
Value: params.Value,
GasLimit: params.GasLimit,
Data: params.Data,
},
)
require.Nil(t, err)
// Ensure that our withdrawal was finalized successfully
finalizeReceipt, err := waitForTransaction(tx.Hash(), l1Client, 3*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.Nil(t, err, "finalize withdrawal")
require.Equal(t, types.ReceiptStatusSuccessful, finalizeReceipt.Status)
// Verify balance after withdrawal // Verify balance after withdrawal
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second) ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
...@@ -1380,10 +1099,7 @@ func TestWithdrawals(t *testing.T) { ...@@ -1380,10 +1099,7 @@ func TestWithdrawals(t *testing.T) {
// TestFees checks that L1/L2 fees are handled. // TestFees checks that L1/L2 fees are handled.
func TestFees(t *testing.T) { func TestFees(t *testing.T) {
parallel(t) InitParallel(t)
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
// TODO: after we have the system config contract and new op-geth L1 cost utils, // TODO: after we have the system config contract and new op-geth L1 cost utils,
...@@ -1435,30 +1151,16 @@ func TestFees(t *testing.T) { ...@@ -1435,30 +1151,16 @@ func TestFees(t *testing.T) {
startBalance, err := l2Verif.BalanceAt(ctx, fromAddr, nil) startBalance, err := l2Verif.BalanceAt(ctx, fromAddr, nil)
require.Nil(t, err) require.Nil(t, err)
toAddr := common.Address{0xff, 0xff}
transferAmount := big.NewInt(1_000_000_000) transferAmount := big.NewInt(1_000_000_000)
gasTip := big.NewInt(10) gasTip := big.NewInt(10)
tx := types.MustSignNewTx(ethPrivKey, types.LatestSignerForChainID(cfg.L2ChainIDBig()), &types.DynamicFeeTx{ receipt := SendL2Tx(t, cfg, l2Seq, ethPrivKey, func(opts *TxOpts) {
ChainID: cfg.L2ChainIDBig(), opts.ToAddr = &common.Address{0xff, 0xff}
Nonce: 0, opts.Value = transferAmount
To: &toAddr, opts.GasTipCap = gasTip
Value: transferAmount, opts.Gas = 21000
GasTipCap: gasTip, opts.GasFeeCap = big.NewInt(200)
GasFeeCap: big.NewInt(200), opts.VerifyOnClients(l2Verif)
Gas: 21000,
}) })
sender, err := types.LatestSignerForChainID(cfg.L2ChainIDBig()).Sender(tx)
require.NoError(t, err)
t.Logf("waiting for tx %s from %s to %s", tx.Hash(), sender, tx.To())
err = l2Seq.SendTransaction(context.Background(), tx)
require.Nil(t, err, "Sending L2 tx to sequencer")
_, err = waitForTransaction(tx.Hash(), l2Seq, 4*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.Nil(t, err, "Waiting for L2 tx on sequencer")
receipt, err := waitForTransaction(tx.Hash(), l2Verif, 4*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.Nil(t, err, "Waiting for L2 tx on verifier")
require.Equal(t, types.ReceiptStatusSuccessful, receipt.Status, "TX should have succeeded")
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second) ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
defer cancel() defer cancel()
...@@ -1507,6 +1209,8 @@ func TestFees(t *testing.T) { ...@@ -1507,6 +1209,8 @@ func TestFees(t *testing.T) {
require.Equal(t, baseFee, baseFeeRecipientDiff, "base fee fee mismatch") require.Equal(t, baseFee, baseFeeRecipientDiff, "base fee fee mismatch")
// Tally L1 Fee // Tally L1 Fee
tx, _, err := l2Seq.TransactionByHash(ctx, receipt.TxHash)
require.NoError(t, err, "Should be able to get transaction")
bytes, err := tx.MarshalBinary() bytes, err := tx.MarshalBinary()
require.Nil(t, err) require.Nil(t, err)
l1GasUsed := calcL1GasUsed(bytes, overhead) l1GasUsed := calcL1GasUsed(bytes, overhead)
...@@ -1531,10 +1235,7 @@ func TestFees(t *testing.T) { ...@@ -1531,10 +1235,7 @@ func TestFees(t *testing.T) {
} }
func TestStopStartSequencer(t *testing.T) { func TestStopStartSequencer(t *testing.T) {
parallel(t) InitParallel(t)
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
sys, err := cfg.Start() sys, err := cfg.Start()
...@@ -1575,10 +1276,7 @@ func TestStopStartSequencer(t *testing.T) { ...@@ -1575,10 +1276,7 @@ func TestStopStartSequencer(t *testing.T) {
} }
func TestStopStartBatcher(t *testing.T) { func TestStopStartBatcher(t *testing.T) {
parallel(t) InitParallel(t)
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
sys, err := cfg.Start() sys, err := cfg.Start()
...@@ -1599,23 +1297,12 @@ func TestStopStartBatcher(t *testing.T) { ...@@ -1599,23 +1297,12 @@ func TestStopStartBatcher(t *testing.T) {
nonce := uint64(0) nonce := uint64(0)
sendTx := func() *types.Receipt { sendTx := func() *types.Receipt {
// Submit TX to L2 sequencer node // Submit TX to L2 sequencer node
tx := types.MustSignNewTx(cfg.Secrets.Alice, types.LatestSignerForChainID(cfg.L2ChainIDBig()), &types.DynamicFeeTx{ receipt := SendL2Tx(t, cfg, l2Seq, cfg.Secrets.Alice, func(opts *TxOpts) {
ChainID: cfg.L2ChainIDBig(), opts.ToAddr = &common.Address{0xff, 0xff}
Nonce: nonce, opts.Value = big.NewInt(1_000_000_000)
To: &common.Address{0xff, 0xff}, opts.Nonce = nonce
Value: big.NewInt(1_000_000_000),
GasTipCap: big.NewInt(10),
GasFeeCap: big.NewInt(200),
Gas: 21000,
}) })
nonce++ nonce++
err = l2Seq.SendTransaction(context.Background(), tx)
require.Nil(t, err, "Sending L2 tx to sequencer")
// Let it show up on the unsafe chain
receipt, err := waitForTransaction(tx.Hash(), l2Seq, 3*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.Nil(t, err, "Waiting for L2 tx on sequencer")
return receipt return receipt
} }
// send a transaction // send a transaction
......
...@@ -24,7 +24,6 @@ import ( ...@@ -24,7 +24,6 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/ethclient/gethclient" "github.com/ethereum/go-ethereum/ethclient/gethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
fuzz "github.com/google/gofuzz" fuzz "github.com/google/gofuzz"
...@@ -33,18 +32,13 @@ import ( ...@@ -33,18 +32,13 @@ import (
// TestGasPriceOracleFeeUpdates checks that the gas price oracle cannot be locked by mis-configuring parameters. // TestGasPriceOracleFeeUpdates checks that the gas price oracle cannot be locked by mis-configuring parameters.
func TestGasPriceOracleFeeUpdates(t *testing.T) { func TestGasPriceOracleFeeUpdates(t *testing.T) {
parallel(t) InitParallel(t)
// Define our values to set in the GasPriceOracle (we set them high to see if it can lock L2 or stop bindings // Define our values to set in the GasPriceOracle (we set them high to see if it can lock L2 or stop bindings
// from updating the prices once again. // from updating the prices once again.
overheadValue := abi.MaxUint256 overheadValue := abi.MaxUint256
scalarValue := abi.MaxUint256 scalarValue := abi.MaxUint256
var cancel context.CancelFunc var cancel context.CancelFunc
// Setup our logger handler
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
// Create our system configuration for L1/L2 and start it // Create our system configuration for L1/L2 and start it
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
sys, err := cfg.Start() sys, err := cfg.Start()
...@@ -126,11 +120,7 @@ func TestGasPriceOracleFeeUpdates(t *testing.T) { ...@@ -126,11 +120,7 @@ func TestGasPriceOracleFeeUpdates(t *testing.T) {
// TestL2SequencerRPCDepositTx checks that the L2 sequencer will not accept DepositTx type transactions. // TestL2SequencerRPCDepositTx checks that the L2 sequencer will not accept DepositTx type transactions.
// The acceptance of these transactions would allow for arbitrary minting of ETH in L2. // The acceptance of these transactions would allow for arbitrary minting of ETH in L2.
func TestL2SequencerRPCDepositTx(t *testing.T) { func TestL2SequencerRPCDepositTx(t *testing.T) {
parallel(t) InitParallel(t)
// Setup our logger handler
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
// Create our system configuration for L1/L2 and start it // Create our system configuration for L1/L2 and start it
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
...@@ -233,7 +223,7 @@ func startConfigWithTestAccounts(cfg *SystemConfig, accountsToGenerate int) (*Sy ...@@ -233,7 +223,7 @@ func startConfigWithTestAccounts(cfg *SystemConfig, accountsToGenerate int) (*Sy
// TestMixedDepositValidity makes a number of deposit transactions, some which will succeed in transferring value, // TestMixedDepositValidity makes a number of deposit transactions, some which will succeed in transferring value,
// while others do not. It ensures that the expected nonces/balances match after several interactions. // while others do not. It ensures that the expected nonces/balances match after several interactions.
func TestMixedDepositValidity(t *testing.T) { func TestMixedDepositValidity(t *testing.T) {
parallel(t) InitParallel(t)
// Define how many deposit txs we'll make. Each deposit mints a fixed amount and transfers up to 1/3 of the user's // Define how many deposit txs we'll make. Each deposit mints a fixed amount and transfers up to 1/3 of the user's
// balance. As such, this number cannot be too high or else the test will always fail due to lack of balance in L1. // balance. As such, this number cannot be too high or else the test will always fail due to lack of balance in L1.
const depositTxCount = 15 const depositTxCount = 15
...@@ -241,11 +231,6 @@ func TestMixedDepositValidity(t *testing.T) { ...@@ -241,11 +231,6 @@ func TestMixedDepositValidity(t *testing.T) {
// Define how many accounts we'll use to deposit funds // Define how many accounts we'll use to deposit funds
const accountUsedToDeposit = 5 const accountUsedToDeposit = 5
// Setup our logger handler
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
// Create our system configuration, funding all accounts we created for L1/L2, and start it // Create our system configuration, funding all accounts we created for L1/L2, and start it
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
sys, testAccounts, err := startConfigWithTestAccounts(&cfg, accountUsedToDeposit) sys, testAccounts, err := startConfigWithTestAccounts(&cfg, accountUsedToDeposit)
...@@ -415,17 +400,13 @@ func TestMixedDepositValidity(t *testing.T) { ...@@ -415,17 +400,13 @@ func TestMixedDepositValidity(t *testing.T) {
// TestMixedWithdrawalValidity makes a number of withdrawal transactions and ensures ones with modified parameters are // TestMixedWithdrawalValidity makes a number of withdrawal transactions and ensures ones with modified parameters are
// rejected while unmodified ones are accepted. This runs test cases in different systems. // rejected while unmodified ones are accepted. This runs test cases in different systems.
func TestMixedWithdrawalValidity(t *testing.T) { func TestMixedWithdrawalValidity(t *testing.T) {
parallel(t) InitParallel(t)
// Setup our logger handler
if !verboseGethNodes {
log.Root().SetHandler(log.DiscardHandler())
}
// There are 7 different fields we try modifying to cause a failure, plus one "good" test result we test. // There are 7 different fields we try modifying to cause a failure, plus one "good" test result we test.
for i := 0; i <= 8; i++ { for i := 0; i <= 8; i++ {
i := i // avoid loop var capture i := i // avoid loop var capture
t.Run(fmt.Sprintf("withdrawal test#%d", i+1), func(t *testing.T) { t.Run(fmt.Sprintf("withdrawal test#%d", i+1), func(t *testing.T) {
parallel(t) InitParallel(t)
// Create our system configuration, funding all accounts we created for L1/L2, and start it // Create our system configuration, funding all accounts we created for L1/L2, and start it
cfg := DefaultSystemConfig(t) cfg := DefaultSystemConfig(t)
......
package op_e2e
import (
"context"
"crypto/ecdsa"
"math/big"
"testing"
"time"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/stretchr/testify/require"
)
// SendDepositTx creates and sends a deposit transaction.
// The L1 transaction, including sender, is configured by the l1Opts param.
// The L2 transaction options can be configured by modifying the DepositTxOps value supplied to applyL2Opts
// Will verify that the transaction is included with the expected status on L1 and L2
func SendDepositTx(t *testing.T, cfg SystemConfig, l1Client *ethclient.Client, l2Client *ethclient.Client, l1Opts *bind.TransactOpts, applyL2Opts DepositTxOptsFn) {
l2Opts := defaultDepositTxOpts(l1Opts)
applyL2Opts(l2Opts)
// Find deposit contract
depositContract, err := bindings.NewOptimismPortal(predeploys.DevOptimismPortalAddr, l1Client)
require.Nil(t, err)
// Finally send TX
tx, err := depositContract.DepositTransaction(l1Opts, l2Opts.ToAddr, l2Opts.Value, l2Opts.GasLimit, l2Opts.IsCreation, l2Opts.Data)
require.Nil(t, err, "with deposit tx")
// Wait for transaction on L1
receipt, err := waitForTransaction(tx.Hash(), l1Client, 10*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.Nil(t, err, "Waiting for deposit tx on L1")
// Wait for transaction to be included on L2
reconstructedDep, err := derive.UnmarshalDepositLogEvent(receipt.Logs[0])
require.NoError(t, err, "Could not reconstruct L2 Deposit")
tx = types.NewTx(reconstructedDep)
receipt, err = waitForTransaction(tx.Hash(), l2Client, 10*time.Duration(cfg.DeployConfig.L2BlockTime)*time.Second)
require.NoError(t, err)
require.Equal(t, l2Opts.ExpectedStatus, receipt.Status)
}
type DepositTxOptsFn func(l2Opts *DepositTxOpts)
type DepositTxOpts struct {
ToAddr common.Address
Value *big.Int
GasLimit uint64
IsCreation bool
Data []byte
ExpectedStatus uint64
}
func defaultDepositTxOpts(opts *bind.TransactOpts) *DepositTxOpts {
return &DepositTxOpts{
ToAddr: opts.From,
Value: opts.Value,
GasLimit: 1_000_000,
IsCreation: false,
Data: nil,
ExpectedStatus: types.ReceiptStatusSuccessful,
}
}
// SendL2Tx creates and sends a transaction.
// The supplied privKey is used to specify the account to send from and the transaction is sent to the supplied l2Client
// Transaction options and expected status can be configured in the applyTxOpts function by modifying the supplied TxOpts
// Will verify that the transaction is included with the expected status on l2Client and any clients added to TxOpts.VerifyClients
func SendL2Tx(t *testing.T, cfg SystemConfig, l2Client *ethclient.Client, privKey *ecdsa.PrivateKey, applyTxOpts TxOptsFn) *types.Receipt {
opts := defaultTxOpts()
applyTxOpts(opts)
tx := types.MustSignNewTx(privKey, types.LatestSignerForChainID(cfg.L2ChainIDBig()), &types.DynamicFeeTx{
ChainID: cfg.L2ChainIDBig(),
Nonce: opts.Nonce, // Already have deposit
To: opts.ToAddr,
Value: opts.Value,
GasTipCap: opts.GasTipCap,
GasFeeCap: opts.GasFeeCap,
Gas: opts.Gas,
})
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
err := l2Client.SendTransaction(ctx, tx)
require.Nil(t, err, "Sending L2 tx")
receipt, err := waitForTransaction(tx.Hash(), l2Client, 10*time.Duration(cfg.DeployConfig.L2BlockTime)*time.Second)
require.Nil(t, err, "Waiting for L2 tx")
require.Equal(t, opts.ExpectedStatus, receipt.Status, "TX should have expected status")
for i, client := range opts.VerifyClients {
t.Logf("Waiting for tx %v on verification client %d", tx.Hash(), i)
receiptVerif, err := waitForTransaction(tx.Hash(), client, 10*time.Duration(cfg.DeployConfig.L2BlockTime)*time.Second)
require.Nilf(t, err, "Waiting for L2 tx on verification client %d", i)
require.Equalf(t, receipt, receiptVerif, "Receipts should be the same on sequencer and verification client %d", i)
}
return receipt
}
type TxOptsFn func(opts *TxOpts)
type TxOpts struct {
ToAddr *common.Address
Nonce uint64
Value *big.Int
Gas uint64
GasTipCap *big.Int
GasFeeCap *big.Int
Data []byte
ExpectedStatus uint64
VerifyClients []*ethclient.Client
}
// VerifyOnClients adds additional l2 clients that should sync the block the tx is included in
// Checks that the receipt received from these clients is equal to the receipt received from the sequencer
func (o *TxOpts) VerifyOnClients(clients ...*ethclient.Client) {
o.VerifyClients = append(o.VerifyClients, clients...)
}
func defaultTxOpts() *TxOpts {
return &TxOpts{
ToAddr: nil,
Nonce: 0,
Value: common.Big0,
GasTipCap: big.NewInt(10),
GasFeeCap: big.NewInt(200),
Gas: 21_000,
Data: nil,
ExpectedStatus: types.ReceiptStatusSuccessful,
}
}
package op_e2e
import (
"context"
"crypto/ecdsa"
"math/big"
"testing"
"time"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-node/withdrawals"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/ethclient/gethclient"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc"
"github.com/stretchr/testify/require"
)
func SendWithdrawal(t *testing.T, cfg SystemConfig, l2Client *ethclient.Client, privKey *ecdsa.PrivateKey, applyOpts WithdrawalTxOptsFn) (*types.Transaction, *types.Receipt) {
opts := defaultWithdrawalTxOpts()
applyOpts(opts)
// Bind L2 Withdrawer Contract
l2withdrawer, err := bindings.NewL2ToL1MessagePasser(predeploys.L2ToL1MessagePasserAddr, l2Client)
require.Nil(t, err, "binding withdrawer on L2")
// Initiate Withdrawal
l2opts, err := bind.NewKeyedTransactorWithChainID(privKey, cfg.L2ChainIDBig())
require.Nil(t, err)
l2opts.Value = opts.Value
tx, err := l2withdrawer.InitiateWithdrawal(l2opts, l2opts.From, big.NewInt(int64(opts.Gas)), opts.Data)
require.Nil(t, err, "sending initiate withdraw tx")
receipt, err := waitForTransaction(tx.Hash(), l2Client, 10*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.Nil(t, err, "withdrawal initiated on L2 sequencer")
require.Equal(t, opts.ExpectedStatus, receipt.Status, "transaction had incorrect status")
for i, client := range opts.VerifyClients {
t.Logf("Waiting for tx %v on verification client %d", tx.Hash(), i)
receiptVerif, err := waitForTransaction(tx.Hash(), client, 10*time.Duration(cfg.DeployConfig.L2BlockTime)*time.Second)
require.Nilf(t, err, "Waiting for L2 tx on verification client %d", i)
require.Equalf(t, receipt, receiptVerif, "Receipts should be the same on sequencer and verification client %d", i)
}
return tx, receipt
}
type WithdrawalTxOptsFn func(opts *WithdrawalTxOpts)
type WithdrawalTxOpts struct {
ToAddr *common.Address
Nonce uint64
Value *big.Int
Gas uint64
Data []byte
ExpectedStatus uint64
VerifyClients []*ethclient.Client
}
// VerifyOnClients adds additional l2 clients that should sync the block the tx is included in
// Checks that the receipt received from these clients is equal to the receipt received from the sequencer
func (o *WithdrawalTxOpts) VerifyOnClients(clients ...*ethclient.Client) {
o.VerifyClients = append(o.VerifyClients, clients...)
}
func defaultWithdrawalTxOpts() *WithdrawalTxOpts {
return &WithdrawalTxOpts{
ToAddr: nil,
Nonce: 0,
Value: common.Big0,
Gas: 21_000,
Data: nil,
ExpectedStatus: types.ReceiptStatusSuccessful,
}
}
func ProveAndFinalizeWithdrawal(t *testing.T, cfg SystemConfig, l1Client *ethclient.Client, l2Node *node.Node, ethPrivKey *ecdsa.PrivateKey, l2WithdrawalReceipt *types.Receipt) (*types.Receipt, *types.Receipt) {
params, proveReceipt := ProveWithdrawal(t, cfg, l1Client, l2Node, ethPrivKey, l2WithdrawalReceipt)
finalizeReceipt := FinalizeWithdrawal(t, cfg, l1Client, ethPrivKey, l2WithdrawalReceipt, params)
return proveReceipt, finalizeReceipt
}
func ProveWithdrawal(t *testing.T, cfg SystemConfig, l1Client *ethclient.Client, l2Node *node.Node, ethPrivKey *ecdsa.PrivateKey, l2WithdrawalReceipt *types.Receipt) (withdrawals.ProvenWithdrawalParameters, *types.Receipt) {
// Get l2BlockNumber for proof generation
ctx, cancel := context.WithTimeout(context.Background(), 40*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
defer cancel()
blockNumber, err := withdrawals.WaitForFinalizationPeriod(ctx, l1Client, predeploys.DevOptimismPortalAddr, l2WithdrawalReceipt.BlockNumber)
require.Nil(t, err)
rpcClient, err := rpc.Dial(l2Node.WSEndpoint())
require.Nil(t, err)
proofCl := gethclient.New(rpcClient)
receiptCl := ethclient.NewClient(rpcClient)
ctx, cancel = context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
// Get the latest header
header, err := receiptCl.HeaderByNumber(ctx, new(big.Int).SetUint64(blockNumber))
require.Nil(t, err)
// Now create withdrawal
oracle, err := bindings.NewL2OutputOracleCaller(predeploys.DevL2OutputOracleAddr, l1Client)
require.Nil(t, err)
params, err := withdrawals.ProveWithdrawalParameters(context.Background(), proofCl, receiptCl, l2WithdrawalReceipt.TxHash, header, oracle)
require.Nil(t, err)
portal, err := bindings.NewOptimismPortal(predeploys.DevOptimismPortalAddr, l1Client)
require.Nil(t, err)
opts, err := bind.NewKeyedTransactorWithChainID(ethPrivKey, cfg.L1ChainIDBig())
require.Nil(t, err)
// Prove withdrawal
tx, err := portal.ProveWithdrawalTransaction(
opts,
bindings.TypesWithdrawalTransaction{
Nonce: params.Nonce,
Sender: params.Sender,
Target: params.Target,
Value: params.Value,
GasLimit: params.GasLimit,
Data: params.Data,
},
params.L2OutputIndex,
params.OutputRootProof,
params.WithdrawalProof,
)
require.Nil(t, err)
// Ensure that our withdrawal was proved successfully
proveReceipt, err := waitForTransaction(tx.Hash(), l1Client, 3*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.Nil(t, err, "prove withdrawal")
require.Equal(t, types.ReceiptStatusSuccessful, proveReceipt.Status)
return params, proveReceipt
}
func FinalizeWithdrawal(t *testing.T, cfg SystemConfig, l1Client *ethclient.Client, privKey *ecdsa.PrivateKey, withdrawalReceipt *types.Receipt, params withdrawals.ProvenWithdrawalParameters) *types.Receipt {
// Wait for finalization and then create the Finalized Withdrawal Transaction
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
defer cancel()
_, err := withdrawals.WaitForFinalizationPeriod(ctx, l1Client, predeploys.DevOptimismPortalAddr, withdrawalReceipt.BlockNumber)
require.Nil(t, err)
opts, err := bind.NewKeyedTransactorWithChainID(privKey, cfg.L1ChainIDBig())
require.Nil(t, err)
portal, err := bindings.NewOptimismPortal(predeploys.DevOptimismPortalAddr, l1Client)
require.Nil(t, err)
// Finalize withdrawal
tx, err := portal.FinalizeWithdrawalTransaction(
opts,
bindings.TypesWithdrawalTransaction{
Nonce: params.Nonce,
Sender: params.Sender,
Target: params.Target,
Value: params.Value,
GasLimit: params.GasLimit,
Data: params.Data,
},
)
require.Nil(t, err)
// Ensure that our withdrawal was finalized successfully
finalizeReceipt, err := waitForTransaction(tx.Hash(), l1Client, 3*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.Nil(t, err, "finalize withdrawal")
require.Equal(t, types.ReceiptStatusSuccessful, finalizeReceipt.Status)
return finalizeReceipt
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment