Skip to content
Closed

Master #4002

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/giant-countries-brush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@eth-optimism/contracts-bedrock': minor
---

Deleted unused variables sendImpersonatedTx and FunAccount , cause they slipped in a recent PR
8 changes: 8 additions & 0 deletions .changeset/poor-dots-perform.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@eth-optimism/indexer': minor
'@eth-optimism/contracts-bedrock': minor
'@eth-optimism/integration-tests-bedrock': minor
'@eth-optimism/sdk': minor
---

Adds an implementation of the Two Step Withdrawals V2 proposal
5 changes: 5 additions & 0 deletions .changeset/poor-wolves-mate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@eth-optimism/contracts-bedrock': minor
---

Remove Unused Variables
6 changes: 3 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,6 @@ jobs:
type: string
docker:
- image: cimg/go:1.19
parallelism: 6
resource_class: xlarge
steps:
- checkout
Expand All @@ -436,9 +435,10 @@ jobs:
- run:
name: run tests
command: |
# Note: We don't use circle CI test splits because we need to split by test name, not by package. There is an additional
# constraint that gotestsum does not currently (nor likely will) accept files from different pacakges when building.
OP_TESTLOG_DISABLE_COLOR=true OP_E2E_DISABLE_PARALLEL=true OP_E2E_USE_HTTP=<<parameters.use_http>> gotestsum \
--format=standard-verbose --junitfile=/tmp/test-results/<<parameters.module>>_http_<<parameters.use_http>>.xml \
$(go list ./... | circleci tests split --split-by=timings)
--format=standard-verbose --junitfile=/tmp/test-results/<<parameters.module>>_http_<<parameters.use_http>>.xml ./...
working_directory: <<parameters.module>>
- store_test_results:
path: /tmp/test-results
Expand Down
31 changes: 29 additions & 2 deletions indexer/integration_tests/bedrock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,11 +201,12 @@ func TestBedrockIndexer(t *testing.T) {
require.NoError(t, err)
proofCl := gethclient.New(rpcClient)
receiptCl := ethclient.NewClient(rpcClient)
wParams, err := withdrawals.FinalizeWithdrawalParameters(context.Background(), proofCl, receiptCl, wdTx.Hash(), finHeader)
wParams, err := withdrawals.ProveWithdrawalParameters(context.Background(), proofCl, receiptCl, wdTx.Hash(), finHeader)
require.NoError(t, err)

l1Opts.Value = big.NewInt(0)
finTx, err := portal.FinalizeWithdrawalTransaction(
// Prove our withdrawal
proveTx, err := portal.ProveWithdrawalTransaction(
l1Opts,
bindings.TypesWithdrawalTransaction{
Nonce: wParams.Nonce,
Expand All @@ -221,6 +222,32 @@ func TestBedrockIndexer(t *testing.T) {
)
require.NoError(t, err)

_, err = e2eutils.WaitReceiptOK(e2eutils.TimeoutCtx(t, time.Minute), l1Client, proveTx.Hash())
require.NoError(t, err)

// Wait for the finalization period to elapse
_, err = withdrawals.WaitForFinalizationPeriod(
e2eutils.TimeoutCtx(t, time.Minute),
l1Client,
predeploys.DevOptimismPortalAddr,
wParams.BlockNumber,
)
require.NoError(t, err)

// Send our finalize withdrawal transaction
finTx, err := portal.FinalizeWithdrawalTransaction(
l1Opts,
bindings.TypesWithdrawalTransaction{
Nonce: wParams.Nonce,
Sender: wParams.Sender,
Target: wParams.Target,
Value: wParams.Value,
GasLimit: wParams.GasLimit,
Data: wParams.Data,
},
)
require.NoError(t, err)

finReceipt, err := e2eutils.WaitReceiptOK(e2eutils.TimeoutCtx(t, time.Minute), l1Client, finTx.Hash())
require.NoError(t, err)

Expand Down
261 changes: 247 additions & 14 deletions op-bindings/bindings/optimismportal.go

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions op-bindings/bindings/optimismportal_more.go

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion op-chain-ops/crossdomain/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/log"
)

var (
Expand All @@ -19,7 +20,7 @@ var (

// MigrateWithdrawals will migrate a list of pending withdrawals given a StateDB.
func MigrateWithdrawals(withdrawals []*LegacyWithdrawal, db vm.StateDB, l1CrossDomainMessenger, l1StandardBridge *common.Address) error {
for _, legacy := range withdrawals {
for i, legacy := range withdrawals {
legacySlot, err := legacy.StorageSlot()
if err != nil {
return err
Expand All @@ -46,6 +47,7 @@ func MigrateWithdrawals(withdrawals []*LegacyWithdrawal, db vm.StateDB, l1CrossD
}

db.SetState(predeploys.L2ToL1MessagePasserAddr, slot, abiTrue)
log.Info("Migrated withdrawal", "number", i, "slot", slot)
}
return nil
}
Expand Down
1 change: 1 addition & 0 deletions op-chain-ops/ether/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ func MigrateLegacyETH(db ethdb.Database, addresses []common.Address, allowances

// Set the total supply to 0
stateDB.SetState(predeploys.LegacyERC20ETHAddr, getOVMETHTotalSupplySlot(), common.Hash{})
log.Info("Set the totalSupply to 0")

if !commit {
log.Info("dry run, skipping commit")
Expand Down
11 changes: 8 additions & 3 deletions op-chain-ops/genesis/db_migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ import (
"fmt"
"math/big"

"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"

"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain"
"github.com/ethereum-optimism/optimism/op-chain-ops/ether"
Expand All @@ -17,6 +14,8 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
)

Expand Down Expand Up @@ -80,13 +79,18 @@ func MigrateDB(ldb ethdb.Database, config *DeployConfig, l1Block *types.Block, m
return nil, fmt.Errorf("cannot set implementations: %w", err)
}

log.Info("Starting to migrate withdrawals")
err = crossdomain.MigrateWithdrawals(withdrawals, db, &config.L1CrossDomainMessengerProxy, &config.L1StandardBridgeProxy)
if err != nil {
return nil, fmt.Errorf("cannot migrate withdrawals: %w", err)
}
log.Info("Completed withdrawal migration")

log.Info("Starting to migrate ERC20 ETH")
addrs := migrationData.Addresses()
newRoot, err := ether.MigrateLegacyETH(ldb, addrs, migrationData.OvmAllowances, int(config.L1ChainID), commit)
log.Info("Completed ERC20 ETH migration")

if err != nil {
return nil, fmt.Errorf("cannot migrate legacy eth: %w", err)
}
Expand Down Expand Up @@ -120,6 +124,7 @@ func MigrateDB(ldb ethdb.Database, config *DeployConfig, l1Block *types.Block, m
}

if !commit {
log.Info("Dry run complete")
return res, nil
}

Expand Down
6 changes: 6 additions & 0 deletions op-chain-ops/genesis/setters.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/ethereum-optimism/optimism/op-chain-ops/state"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/log"
)

// FundDevAccounts will fund each of the development accounts.
Expand Down Expand Up @@ -51,12 +52,14 @@ func setProxies(db vm.StateDB, proxyAdminAddr common.Address, namespace *big.Int
// the proxy admin address. LegacyERC20ETH lives in the
// 0xDead namespace so it can be ignored here
if addr == predeploys.GovernanceTokenAddr || addr == predeploys.ProxyAdminAddr {
log.Info("Skipping setting proxy", "address", addr)
continue
}

db.CreateAccount(addr)
db.SetCode(addr, depBytecode)
db.SetState(addr, AdminSlot, proxyAdminAddr.Hash())
log.Trace("Set proxy", "address", addr, "admin", proxyAdminAddr)
}
return nil
}
Expand Down Expand Up @@ -96,17 +99,20 @@ func SetImplementations(db vm.StateDB, storage state.StorageConfig, immutable im
// Use the genrated bytecode when there are immutables
// otherwise use the artifact deployed bytecode
if bytecode, ok := deployResults[name]; ok {
log.Info("Setting deployed bytecode with immutables", "name", name, "address", addr)
db.SetCode(addr, bytecode)
} else {
depBytecode, err := bindings.GetDeployedBytecode(name)
if err != nil {
return err
}
log.Info("Setting deployed bytecode from solc compiler output", "name", name, "address", addr)
db.SetCode(addr, depBytecode)
}

// Set the storage values
if storageConfig, ok := storage[name]; ok {
log.Info("Setting storage", "name", name, "address", *address)
if err := state.SetStorage(name, *address, storageConfig, db); err != nil {
return err
}
Expand Down
67 changes: 60 additions & 7 deletions op-e2e/actions/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -379,14 +379,68 @@ func (s *CrossLayerUser) Address() common.Address {
return s.L1.address
}

// ActCompleteWithdrawal creates a L1 withdrawal completion tx for latest withdrawal.
// ActCompleteWithdrawal creates a L1 proveWithdrawal tx for latest withdrawal.
// The tx hash is remembered as the last L1 tx, to check as L1 actor.
func (s *CrossLayerUser) ActProveWithdrawal(t Testing) {
s.L1.lastTxHash = s.ProveWithdrawal(t, s.lastL2WithdrawalTxHash)
}

// ProveWithdrawal creates a L1 proveWithdrawal tx for the given L2 withdrawal tx, returning the tx hash.
func (s *CrossLayerUser) ProveWithdrawal(t Testing, l2TxHash common.Hash) common.Hash {
// Figure out when our withdrawal was included
receipt := s.L2.CheckReceipt(t, true, l2TxHash)
l2WithdrawalBlock, err := s.L2.env.EthCl.BlockByNumber(t.Ctx(), receipt.BlockNumber)
require.NoError(t, err)

// Figure out what the Output oracle on L1 has seen so far
l2OutputBlockNr, err := s.L1.env.Bindings.L2OutputOracle.LatestBlockNumber(&bind.CallOpts{})
require.NoError(t, err)
l2OutputBlock, err := s.L2.env.EthCl.BlockByNumber(t.Ctx(), l2OutputBlockNr)
require.NoError(t, err)

// Check if the L2 output is even old enough to include the withdrawal
if l2OutputBlock.NumberU64() < l2WithdrawalBlock.NumberU64() {
t.InvalidAction("the latest L2 output is %d and is not past L2 block %d that includes the withdrawal yet, no withdrawal can be proved yet", l2OutputBlock.NumberU64(), l2WithdrawalBlock.NumberU64())
return common.Hash{}
}

// We generate a proof for the latest L2 output, which shouldn't require archive-node data if it's recent enough.
header, err := s.L2.env.EthCl.HeaderByNumber(t.Ctx(), l2OutputBlockNr)
require.NoError(t, err)
params, err := withdrawals.ProveWithdrawalParameters(t.Ctx(), s.L2.env.Bindings.ProofClient, s.L2.env.EthCl, s.lastL2WithdrawalTxHash, header)
require.NoError(t, err)

// Create the prove tx
tx, err := s.L1.env.Bindings.OptimismPortal.ProveWithdrawalTransaction(
&s.L1.txOpts,
bindings.TypesWithdrawalTransaction{
Nonce: params.Nonce,
Sender: params.Sender,
Target: params.Target,
Value: params.Value,
GasLimit: params.GasLimit,
Data: params.Data,
},
params.BlockNumber,
params.OutputRootProof,
params.WithdrawalProof,
)
require.NoError(t, err)

// Send the actual tx (since tx opts don't send by default)
err = s.L1.env.EthCl.SendTransaction(t.Ctx(), tx)
require.NoError(t, err, "must send prove tx")
return tx.Hash()
}

// ActCompleteWithdrawal creates a L1 withdrawal finalization tx for latest withdrawal.
// The tx hash is remembered as the last L1 tx, to check as L1 actor.
// The withdrawal functions like CompleteWithdrawal
func (s *CrossLayerUser) ActCompleteWithdrawal(t Testing) {
s.L1.lastTxHash = s.CompleteWithdrawal(t, s.lastL2WithdrawalTxHash)
}

// CompleteWithdrawal creates a L1 withdrawal completion tx for the given L2 withdrawal tx, returning the tx hash.
// CompleteWithdrawal creates a L1 withdrawal finalization tx for the given L2 withdrawal tx, returning the tx hash.
// It's an invalid action to attempt to complete a withdrawal that has not passed the L1 finalization period yet
func (s *CrossLayerUser) CompleteWithdrawal(t Testing, l2TxHash common.Hash) common.Hash {
finalizationPeriod, err := s.L1.env.Bindings.OptimismPortal.FINALIZATIONPERIODSECONDS(&bind.CallOpts{})
Expand Down Expand Up @@ -420,9 +474,11 @@ func (s *CrossLayerUser) CompleteWithdrawal(t Testing, l2TxHash common.Hash) com
}

// We generate a proof for the latest L2 output, which shouldn't require archive-node data if it's recent enough.
// Note that for the `FinalizeWithdrawalTransaction` function, this proof isn't needed. We simply use some of the
// params for the `WithdrawalTransaction` type generated in the bindings.
header, err := s.L2.env.EthCl.HeaderByNumber(t.Ctx(), l2OutputBlockNr)
require.NoError(t, err)
params, err := withdrawals.FinalizeWithdrawalParameters(t.Ctx(), s.L2.env.Bindings.ProofClient, s.L2.env.EthCl, s.lastL2WithdrawalTxHash, header)
params, err := withdrawals.ProveWithdrawalParameters(t.Ctx(), s.L2.env.Bindings.ProofClient, s.L2.env.EthCl, s.lastL2WithdrawalTxHash, header)
require.NoError(t, err)

// Create the withdrawal tx
Expand All @@ -436,14 +492,11 @@ func (s *CrossLayerUser) CompleteWithdrawal(t Testing, l2TxHash common.Hash) com
GasLimit: params.GasLimit,
Data: params.Data,
},
params.BlockNumber,
params.OutputRootProof,
params.WithdrawalProof,
)
require.NoError(t, err)

// Send the actual tx (since tx opts don't send by default)
err = s.L1.env.EthCl.SendTransaction(t.Ctx(), tx)
require.NoError(t, err, "must send tx")
require.NoError(t, err, "must send finalize tx")
return tx.Hash()
}
19 changes: 18 additions & 1 deletion op-e2e/actions/user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import (
// - transact on L2
// - deposit on L1
// - withdraw from L2
// - prove tx on L1
// - wait 1 week + 1 second
// - finalize withdrawal on L1
func TestCrossLayerUser(gt *testing.T) {
t := NewDefaultTesting(gt)
Expand Down Expand Up @@ -133,7 +135,22 @@ func TestCrossLayerUser(gt *testing.T) {
require.Equal(t, types.ReceiptStatusSuccessful, receipt.Status, "proposal failed")
}

// make the L1 side of the withdrawal tx
// prove our withdrawal on L1
alice.ActProveWithdrawal(t)
// include proved withdrawal in new L1 block
miner.ActL1StartBlock(12)(t)
miner.ActL1IncludeTx(alice.Address())(t)
miner.ActL1EndBlock(t)
// check withdrawal succeeded
alice.L1.ActCheckReceiptStatusOfLastTx(true)(t)

// A bit hacky- Mines an empty block with the time delta
// of the finalization period (12s) + 1 in order for the
// withdrawal to be finalized successfully.
miner.ActL1StartBlock(13)(t)
miner.ActL1EndBlock(t)

// make the L1 finalize withdrawal tx
alice.ActCompleteWithdrawal(t)
// include completed withdrawal in new L1 block
miner.ActL1StartBlock(12)(t)
Expand Down
1 change: 1 addition & 0 deletions op-e2e/e2eutils/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ func MakeDeployParams(t require.TestingT, tp *TestParams) *DeployParams {
L1GenesisBlockGasUsed: 0,
L1GenesisBlockParentHash: common.Hash{},
L1GenesisBlockBaseFeePerGas: uint64ToBig(1000_000_000), // 1 gwei
FinalizationPeriodSeconds: 12,

L2GenesisBlockNonce: 0,
L2GenesisBlockExtraData: []byte{},
Expand Down
Loading