Commit 2ef2087d authored by OptimismBot's avatar OptimismBot Committed by GitHub

Merge pull request #7107 from ethereum-optimism/aj/deposit-create-contract

op-e2e: Add test that deploys a contract using a deposit tx
parents ab7496c8 c7d53af8
package op_e2e
import (
"context"
"math/big"
"testing"
"time"
"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/core/vm"
"github.com/stretchr/testify/require"
)
func TestMintOnRevertedDeposit(t *testing.T) {
InitParallel(t)
cfg := DefaultSystemConfig(t)
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
l1Client := sys.Clients["l1"]
l2Verif := sys.Clients["verifier"]
// create signer
aliceKey := cfg.Secrets.Alice
opts, err := bind.NewKeyedTransactorWithChainID(aliceKey, cfg.L1ChainIDBig())
require.Nil(t, err)
fromAddr := opts.From
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
startBalance, err := l2Verif.BalanceAt(ctx, fromAddr, nil)
cancel()
require.Nil(t, err)
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
startNonce, err := l2Verif.NonceAt(ctx, fromAddr, nil)
require.NoError(t, err)
cancel()
toAddr := common.Address{0xff, 0xff}
mintAmount := big.NewInt(9_000_000)
opts.Value = mintAmount
SendDepositTx(t, cfg, l1Client, l2Verif, opts, func(l2Opts *DepositTxOpts) {
l2Opts.ToAddr = toAddr
// trigger a revert by transferring more than we have available
l2Opts.Value = new(big.Int).Mul(common.Big2, startBalance)
l2Opts.ExpectedStatus = types.ReceiptStatusFailed
})
// Confirm balance
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
endBalance, err := l2Verif.BalanceAt(ctx, fromAddr, nil)
cancel()
require.Nil(t, err)
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
toAddrBalance, err := l2Verif.BalanceAt(ctx, toAddr, nil)
require.NoError(t, err)
cancel()
diff := new(big.Int)
diff = diff.Sub(endBalance, startBalance)
require.Equal(t, mintAmount, diff, "Did not get expected balance change")
require.Equal(t, common.Big0.Int64(), toAddrBalance.Int64(), "The recipient account balance should be zero")
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
endNonce, err := l2Verif.NonceAt(ctx, fromAddr, nil)
require.NoError(t, err)
cancel()
require.Equal(t, startNonce+1, endNonce, "Nonce of deposit sender should increment on L2, even if the deposit fails")
}
func TestDepositTxCreateContract(t *testing.T) {
InitParallel(t)
cfg := DefaultSystemConfig(t)
delete(cfg.Nodes, "verifier")
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
l1Client := sys.Clients["l1"]
l2Client := sys.Clients["sequencer"]
opts, err := bind.NewKeyedTransactorWithChainID(cfg.Secrets.Alice, cfg.L1ChainIDBig())
require.Nil(t, err)
// Simple constructor that is prefixed to the actual contract code
// Results in the contract code being returned as the code for the new contract
deployPrefixSize := byte(16)
deployPrefix := []byte{
// Copy input data after this prefix into memory starting at address 0x00
// CODECOPY arg size
byte(vm.PUSH1), deployPrefixSize,
byte(vm.CODESIZE),
byte(vm.SUB),
// CODECOPY arg offset
byte(vm.PUSH1), deployPrefixSize,
// CODECOPY arg destOffset
byte(vm.PUSH1), 0x00,
byte(vm.CODECOPY),
// Return code from memory
// RETURN arg size
byte(vm.PUSH1), deployPrefixSize,
byte(vm.CODESIZE),
byte(vm.SUB),
// RETURN arg offset
byte(vm.PUSH1), 0x00,
byte(vm.RETURN),
}
// Stores the first word from call data code to storage slot 0
sstoreContract := []byte{
// Load first word from call data
byte(vm.PUSH1), 0x00,
byte(vm.CALLDATALOAD),
// Store it to slot 0
byte(vm.PUSH1), 0x00,
byte(vm.SSTORE),
}
deployData := append(deployPrefix, sstoreContract...)
l2Receipt := SendDepositTx(t, cfg, l1Client, l2Client, opts, func(l2Opts *DepositTxOpts) {
l2Opts.Data = deployData
l2Opts.Value = common.Big0
l2Opts.IsCreation = true
l2Opts.ToAddr = common.Address{}
l2Opts.GasLimit = 1_000_000
})
require.NotEqual(t, common.Address{}, l2Receipt.ContractAddress, "should not have zero address")
code, err := l2Client.CodeAt(context.Background(), l2Receipt.ContractAddress, nil)
require.NoError(t, err, "get deployed contract code")
require.Equal(t, sstoreContract, code, "should have deployed correct contract code")
}
......@@ -84,7 +84,7 @@ func DefaultSystemConfig(t *testing.T) SystemConfig {
require.NoError(t, err)
deployConfig := config.DeployConfig.Copy()
deployConfig.L1GenesisBlockTimestamp = hexutil.Uint64(time.Now().Unix())
require.NoError(t, deployConfig.Check())
require.NoError(t, deployConfig.Check(), "Deploy config is invalid, do you need to run make devnet-allocs?")
l1Deployments := config.L1Deployments.Copy()
require.NoError(t, l1Deployments.Check())
......
......@@ -11,7 +11,6 @@ import (
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
......@@ -337,67 +336,6 @@ func TestFinalize(t *testing.T) {
require.NotZerof(t, l2Finalized.NumberU64(), "must have finalized L2 block")
}
func TestMintOnRevertedDeposit(t *testing.T) {
InitParallel(t)
cfg := DefaultSystemConfig(t)
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
l1Client := sys.Clients["l1"]
l2Verif := sys.Clients["verifier"]
l1Node := sys.EthInstances["l1"].(*GethInstance).Node
// create signer
ks := l1Node.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
opts, err := bind.NewKeyStoreTransactorWithChainID(ks, ks.Accounts()[0], cfg.L1ChainIDBig())
require.Nil(t, err)
fromAddr := opts.From
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
startBalance, err := l2Verif.BalanceAt(ctx, fromAddr, nil)
cancel()
require.Nil(t, err)
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
startNonce, err := l2Verif.NonceAt(ctx, fromAddr, nil)
require.NoError(t, err)
cancel()
toAddr := common.Address{0xff, 0xff}
mintAmount := big.NewInt(9_000_000)
opts.Value = mintAmount
SendDepositTx(t, cfg, l1Client, l2Verif, opts, func(l2Opts *DepositTxOpts) {
l2Opts.ToAddr = toAddr
// trigger a revert by transferring more than we have available
l2Opts.Value = new(big.Int).Mul(common.Big2, startBalance)
l2Opts.ExpectedStatus = types.ReceiptStatusFailed
})
// Confirm balance
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
endBalance, err := l2Verif.BalanceAt(ctx, fromAddr, nil)
cancel()
require.Nil(t, err)
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
toAddrBalance, err := l2Verif.BalanceAt(ctx, toAddr, nil)
require.NoError(t, err)
cancel()
diff := new(big.Int)
diff = diff.Sub(endBalance, startBalance)
require.Equal(t, mintAmount, diff, "Did not get expected balance change")
require.Equal(t, common.Big0.Int64(), toAddrBalance.Int64(), "The recipient account balance should be zero")
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
endNonce, err := l2Verif.NonceAt(ctx, fromAddr, nil)
require.NoError(t, err)
cancel()
require.Equal(t, startNonce+1, endNonce, "Nonce of deposit sender should increment on L2, even if the deposit fails")
}
func TestMissingBatchE2E(t *testing.T) {
InitParallel(t)
// Note this test zeroes the balance of the batch-submitter to make the batches unable to go into L1.
......
......@@ -21,7 +21,8 @@ import (
// 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) {
// Returns the receipt of the L2 transaction
func SendDepositTx(t *testing.T, cfg SystemConfig, l1Client *ethclient.Client, l2Client *ethclient.Client, l1Opts *bind.TransactOpts, applyL2Opts DepositTxOptsFn) *types.Receipt {
l2Opts := defaultDepositTxOpts(l1Opts)
applyL2Opts(l2Opts)
......@@ -38,16 +39,17 @@ func SendDepositTx(t *testing.T, cfg SystemConfig, l1Client *ethclient.Client, l
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)
l1Receipt, 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])
reconstructedDep, err := derive.UnmarshalDepositLogEvent(l1Receipt.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)
l2Receipt, err := waitForTransaction(tx.Hash(), l2Client, 10*time.Duration(cfg.DeployConfig.L2BlockTime)*time.Second)
require.NoError(t, err)
require.Equal(t, l2Opts.ExpectedStatus, receipt.Status, "l2 transaction status")
require.Equal(t, l2Opts.ExpectedStatus, l2Receipt.Status, "l2 transaction status")
return l2Receipt
}
type DepositTxOptsFn func(l2Opts *DepositTxOpts)
......
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