Commit 234d6863 authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into clabby/update-forge-and-forge-std

parents de7ba3ca e9045720
......@@ -9,7 +9,7 @@ require (
github.com/docker/docker v20.10.21+incompatible
github.com/docker/go-connections v0.4.0
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3
github.com/ethereum/go-ethereum v1.10.26
github.com/ethereum/go-ethereum v1.11.2
github.com/fsnotify/fsnotify v1.6.0
github.com/golang/snappy v0.0.4
github.com/google/go-cmp v0.5.9
......@@ -31,11 +31,12 @@ require (
github.com/stretchr/testify v1.8.1
github.com/urfave/cli v1.22.9
github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa
golang.org/x/crypto v0.4.0
golang.org/x/crypto v0.6.0
golang.org/x/term v0.5.0
)
require (
github.com/DataDog/zstd v1.5.2 // indirect
github.com/Microsoft/go-winio v0.6.0 // indirect
github.com/VictoriaMetrics/fastcache v1.10.0 // indirect
github.com/allegro/bigcache v1.2.1 // indirect
......@@ -45,12 +46,16 @@ require (
github.com/btcsuite/btcd/btcutil v1.1.0 // indirect
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/containerd/cgroups v1.0.4 // indirect
github.com/cockroachdb/errors v1.9.1 // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 // indirect
github.com/cockroachdb/redact v1.1.3 // indirect
github.com/containerd/cgroups v1.1.0 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
github.com/deckarep/golang-set v1.8.0 // indirect
github.com/deckarep/golang-set/v2 v2.1.0 // indirect
github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect
github.com/deepmap/oapi-codegen v1.8.2 // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect
......@@ -62,6 +67,7 @@ require (
github.com/flynn/noise v1.0.0 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect
github.com/getsentry/sentry-go v0.18.0 // indirect
github.com/go-kit/kit v0.10.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-stack/stack v1.8.1 // indirect
......@@ -72,7 +78,7 @@ require (
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/gopacket v1.1.19 // indirect
github.com/google/pprof v0.0.0-20221203041831-ce31453925ec // indirect
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/graph-gophers/graphql-go v1.3.0 // indirect
......@@ -81,7 +87,7 @@ require (
github.com/hashicorp/golang-lru/v2 v2.0.1 // indirect
github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e // indirect
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
github.com/huin/goupnp v1.0.3 // indirect
github.com/huin/goupnp v1.1.0 // indirect
github.com/influxdata/influxdb v1.8.3 // indirect
github.com/influxdata/influxdb-client-go/v2 v2.4.0 // indirect
github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect
......@@ -95,6 +101,7 @@ require (
github.com/klauspost/cpuid/v2 v2.2.3 // indirect
github.com/koron/go-ssdp v0.0.3 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/libp2p/go-cidranger v1.1.0 // indirect
github.com/libp2p/go-flow-metrics v0.1.0 // indirect
......@@ -106,7 +113,7 @@ require (
github.com/libp2p/go-reuseport v0.2.0 // indirect
github.com/libp2p/go-yamux/v4 v4.0.0 // indirect
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/miekg/dns v1.1.50 // indirect
......@@ -148,13 +155,13 @@ require (
github.com/quic-go/webtransport-go v0.5.1 // indirect
github.com/raulk/go-watchdog v1.3.0 // indirect
github.com/rivo/uniseg v0.4.3 // indirect
github.com/rjeczalik/notify v0.9.2 // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/rs/cors v1.8.2 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/status-im/keycard-go v0.0.0-20211109104530-b0e0482ba91d // indirect
github.com/status-im/keycard-go v0.2.0 // indirect
github.com/stretchr/objx v0.5.0 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect
......@@ -184,4 +191,6 @@ require (
nhooyr.io/websocket v1.8.7 // indirect
)
replace github.com/ethereum/go-ethereum v1.10.26 => github.com/ethereum-optimism/op-geth v0.0.0-20230214215134-401b7fd3309b
replace github.com/ethereum/go-ethereum v1.11.2 => github.com/ethereum-optimism/op-geth v0.0.0-20230222154945-12d211246519
//replace github.com/ethereum/go-ethereum v1.11.2 => ../go-ethereum
This diff is collapsed.
......@@ -120,7 +120,7 @@ func (t *TransactionManager) CraftTx(ctx context.Context, data []byte) (*types.T
}
t.log.Info("creating tx", "to", rawTx.To, "from", t.senderAddress)
gas, err := core.IntrinsicGas(rawTx.Data, nil, false, true, true)
gas, err := core.IntrinsicGas(rawTx.Data, nil, false, true, true, false)
if err != nil {
return nil, fmt.Errorf("failed to calculate intrinsic gas: %w", err)
}
......
......@@ -284,11 +284,11 @@ func main() {
if !isFinalized {
// Get the ETH balance of the withdrawal target *before* the finalization
targetBalBefore, err := clients.L1Client.BalanceAt(context.Background(), *wd.Target, nil)
targetBalBefore, err := clients.L1Client.BalanceAt(context.Background(), wd.XDomainTarget, nil)
if err != nil {
return err
}
log.Debug("Balance before finalization", "balance", targetBalBefore, "account", *wd.Target)
log.Debug("Balance before finalization", "balance", targetBalBefore, "account", wd.XDomainTarget)
log.Info("Finalizing withdrawal")
receipt, err := finalizeWithdrawalTransaction(contracts, clients, opts, wd, withdrawal)
......@@ -369,14 +369,14 @@ func main() {
if method != nil {
log.Info("withdrawal action", "function", method.Name, "value", wdValue)
} else {
log.Info("unknown method", "to", wd.Target, "data", hexutil.Encode(wd.Data))
log.Info("unknown method", "to", wd.XDomainTarget, "data", hexutil.Encode(wd.XDomainData))
if err := writeSuspicious(f, withdrawal, wd, finalizationTrace, i, "unknown method"); err != nil {
return err
}
}
// check that the user's intents are actually executed
if common.HexToAddress(callFrame.To) != *wd.Target {
if common.HexToAddress(callFrame.To) != wd.XDomainTarget {
log.Info("target mismatch", "index", i)
if err := writeSuspicious(f, withdrawal, wd, finalizationTrace, i, "target mismatch"); err != nil {
......@@ -384,7 +384,7 @@ func main() {
}
continue
}
if !bytes.Equal(hexutil.MustDecode(callFrame.Input), wd.Data) {
if !bytes.Equal(hexutil.MustDecode(callFrame.Input), wd.XDomainData) {
log.Info("calldata mismatch", "index", i)
if err := writeSuspicious(f, withdrawal, wd, finalizationTrace, i, "calldata mismatch"); err != nil {
......@@ -401,7 +401,7 @@ func main() {
}
// Get the ETH balance of the withdrawal target *after* the finalization
targetBalAfter, err := clients.L1Client.BalanceAt(context.Background(), *wd.Target, nil)
targetBalAfter, err := clients.L1Client.BalanceAt(context.Background(), wd.XDomainTarget, nil)
if err != nil {
return err
}
......@@ -621,7 +621,7 @@ func finalizeWithdrawalTransaction(
wd *crossdomain.LegacyWithdrawal,
withdrawal *crossdomain.Withdrawal,
) (*types.Receipt, error) {
if wd.Target == nil {
if wd.XDomainTarget == (common.Address{}) {
return nil, errors.New("withdrawal target is nil, should never happen")
}
......@@ -833,7 +833,7 @@ func newTransactor(ctx *cli.Context) (*bind.TransactOpts, error) {
// represents the user's intent.
func findWithdrawalCall(trace *callFrame, wd *crossdomain.LegacyWithdrawal, l1xdm common.Address) *callFrame {
isCall := trace.Type == "CALL"
isTarget := common.HexToAddress(trace.To) == *wd.Target
isTarget := common.HexToAddress(trace.To) == wd.XDomainTarget
isFrom := common.HexToAddress(trace.From) == l1xdm
if isCall && isTarget && isFrom {
return trace
......
......@@ -37,8 +37,8 @@ func init() {
// EncodeCrossDomainMessageV0 will encode the calldata for
// "relayMessage(address,address,bytes,uint256)",
func EncodeCrossDomainMessageV0(
target *common.Address,
sender *common.Address,
target common.Address,
sender common.Address,
message []byte,
nonce *big.Int,
) ([]byte, error) {
......@@ -49,8 +49,8 @@ func EncodeCrossDomainMessageV0(
// "relayMessage(uint256,address,address,uint256,uint256,bytes)",
func EncodeCrossDomainMessageV1(
nonce *big.Int,
sender *common.Address,
target *common.Address,
sender common.Address,
target common.Address,
value *big.Int,
gasLimit *big.Int,
data []byte,
......
......@@ -10,8 +10,8 @@ import (
// HashCrossDomainMessageV0 computes the pre bedrock cross domain messaging
// hashing scheme.
func HashCrossDomainMessageV0(
target *common.Address,
sender *common.Address,
target common.Address,
sender common.Address,
data []byte,
nonce *big.Int,
) (common.Hash, error) {
......@@ -27,8 +27,8 @@ func HashCrossDomainMessageV0(
// messaging hashing scheme.
func HashCrossDomainMessageV1(
nonce *big.Int,
sender *common.Address,
target *common.Address,
sender common.Address,
target common.Address,
value *big.Int,
gasLimit *big.Int,
data []byte,
......
......@@ -16,21 +16,28 @@ import (
// LegacyWithdrawal represents a pre bedrock upgrade withdrawal.
type LegacyWithdrawal struct {
Target *common.Address `json:"target"`
Sender *common.Address `json:"sender"`
Data hexutil.Bytes `json:"data"`
Nonce *big.Int `json:"nonce"`
// MessageSender is the caller of the message passer
MessageSender common.Address `json:"who"`
// XDomainTarget is the L1 target of the withdrawal message
XDomainTarget common.Address `json:"target"`
// XDomainSender is the L2 withdrawing account
XDomainSender common.Address `json:"sender"`
// XDomainData represents the calldata of the withdrawal message
XDomainData hexutil.Bytes `json:"data"`
// XDomainNonce represents the nonce of the withdrawal
XDomainNonce *big.Int `json:"nonce"`
}
var _ WithdrawalMessage = (*LegacyWithdrawal)(nil)
// NewLegacyWithdrawal will construct a LegacyWithdrawal
func NewLegacyWithdrawal(target, sender *common.Address, data []byte, nonce *big.Int) *LegacyWithdrawal {
func NewLegacyWithdrawal(msgSender, target, sender common.Address, data []byte, nonce *big.Int) *LegacyWithdrawal {
return &LegacyWithdrawal{
Target: target,
Sender: sender,
Data: data,
Nonce: nonce,
MessageSender: msgSender,
XDomainTarget: target,
XDomainSender: sender,
XDomainData: data,
XDomainNonce: nonce,
}
}
......@@ -39,7 +46,7 @@ func NewLegacyWithdrawal(target, sender *common.Address, data []byte, nonce *big
// through the standard optimism cross domain messaging system by hashing in
// the L2CrossDomainMessenger address.
func (w *LegacyWithdrawal) Encode() ([]byte, error) {
enc, err := EncodeCrossDomainMessageV0(w.Target, w.Sender, []byte(w.Data), w.Nonce)
enc, err := EncodeCrossDomainMessageV0(w.XDomainTarget, w.XDomainSender, []byte(w.XDomainData), w.XDomainNonce)
if err != nil {
return nil, fmt.Errorf("cannot encode LegacyWithdrawal: %w", err)
}
......@@ -62,9 +69,6 @@ func (w *LegacyWithdrawal) Decode(data []byte) error {
}
msgSender := data[len(data)-len(predeploys.L2CrossDomainMessengerAddr):]
if !bytes.Equal(msgSender, predeploys.L2CrossDomainMessengerAddr.Bytes()) {
return errors.New("invalid msg.sender")
}
raw := data[4 : len(data)-len(predeploys.L2CrossDomainMessengerAddr)]
......@@ -97,10 +101,11 @@ func (w *LegacyWithdrawal) Decode(data []byte) error {
return errors.New("cannot abi decode nonce")
}
w.Target = &target
w.Sender = &sender
w.Data = hexutil.Bytes(msgData)
w.Nonce = nonce
w.MessageSender = common.BytesToAddress(msgSender)
w.XDomainTarget = target
w.XDomainSender = sender
w.XDomainData = msgData
w.XDomainNonce = nonce
return nil
}
......@@ -142,19 +147,15 @@ func (w *LegacyWithdrawal) Value() (*big.Int, error) {
value := new(big.Int)
// Parse the 4byte selector
method, err := abi.MethodById(w.Data)
method, err := abi.MethodById(w.XDomainData)
// If it is an unknown selector, there is no value
if err != nil {
return value, nil
}
if w.Sender == nil {
return nil, errors.New("sender is nil")
}
isFromL2StandardBridge := *w.Sender == predeploys.L2StandardBridgeAddr
isFromL2StandardBridge := w.XDomainSender == predeploys.L2StandardBridgeAddr
if isFromL2StandardBridge && method.Name == "finalizeETHWithdrawal" {
data, err := method.Inputs.Unpack(w.Data[4:])
data, err := method.Inputs.Unpack(w.XDomainData[4:])
if err != nil {
return nil, err
}
......@@ -177,11 +178,11 @@ func (w *LegacyWithdrawal) Value() (*big.Int, error) {
// the concept of value or gaslimit, so set them to 0.
func (w *LegacyWithdrawal) CrossDomainMessage() *CrossDomainMessage {
return &CrossDomainMessage{
Nonce: w.Nonce,
Sender: w.Sender,
Target: w.Target,
Nonce: w.XDomainNonce,
Sender: w.XDomainSender,
Target: w.XDomainTarget,
Value: new(big.Int),
GasLimit: new(big.Int),
Data: []byte(w.Data),
Data: []byte(w.XDomainData),
}
}
......@@ -133,8 +133,7 @@ func TestWithdrawalLegacyStorageSlot(t *testing.T) {
// Cast the cross domain message to a withdrawal. Note that
// this only works for legacy style messages
withdrawal, err := msg.ToWithdrawal()
require.Nil(t, err)
withdrawal := toWithdrawal(t, common.HexToAddress(call.From), msg)
// Compute the legacy storage slot for the withdrawal
slot, err := withdrawal.StorageSlot()
......@@ -160,12 +159,13 @@ func TestWithdrawalLegacyStorageSlot(t *testing.T) {
}
func FuzzEncodeDecodeLegacyWithdrawal(f *testing.F) {
f.Fuzz(func(t *testing.T, _target, _sender, _nonce, data []byte) {
f.Fuzz(func(t *testing.T, _msgSender, _target, _sender, _nonce, data []byte) {
msgSender := common.BytesToAddress(_msgSender)
target := common.BytesToAddress(_target)
sender := common.BytesToAddress(_sender)
nonce := new(big.Int).SetBytes(_nonce)
withdrawal := crossdomain.NewLegacyWithdrawal(&target, &sender, data, nonce)
withdrawal := crossdomain.NewLegacyWithdrawal(msgSender, target, sender, data, nonce)
encoded, err := withdrawal.Encode()
require.Nil(t, err)
......@@ -174,10 +174,10 @@ func FuzzEncodeDecodeLegacyWithdrawal(f *testing.F) {
err = w.Decode(encoded)
require.Nil(t, err)
require.Equal(t, withdrawal.Nonce.Uint64(), w.Nonce.Uint64())
require.Equal(t, withdrawal.Sender, w.Sender)
require.Equal(t, withdrawal.Target, w.Target)
require.Equal(t, withdrawal.Data, w.Data)
require.Equal(t, withdrawal.XDomainNonce.Uint64(), w.XDomainNonce.Uint64())
require.Equal(t, withdrawal.XDomainSender, w.XDomainSender)
require.Equal(t, withdrawal.XDomainTarget, w.XDomainTarget)
require.Equal(t, withdrawal.XDomainData, w.XDomainData)
})
}
......@@ -221,8 +221,8 @@ func findCrossDomainMessage(receipt *types.Receipt) (*crossdomain.CrossDomainMes
// Parse the legacy event
if event.Name == "SentMessage" {
e, _ := l2xdm.ParseSentMessage(*log)
msg.Target = &e.Target
msg.Sender = &e.Sender
msg.Target = e.Target
msg.Sender = e.Sender
msg.Data = e.Message
msg.Nonce = e.MessageNonce
msg.GasLimit = e.GasLimit
......@@ -336,3 +336,30 @@ func readStateDiff(hash string) (stateDiff, error) {
}
return diff, nil
}
// ToWithdrawal will turn a CrossDomainMessage into a Withdrawal.
// This only works for version 0 CrossDomainMessages as not all of
// the data is present for version 1 CrossDomainMessages to be turned
// into Withdrawals.
func toWithdrawal(t *testing.T, msgSender common.Address, c *crossdomain.CrossDomainMessage) *crossdomain.LegacyWithdrawal {
version := c.Version()
switch version {
case 0:
if c.Value != nil && c.Value.Cmp(common.Big0) != 0 {
t.Fatalf("version 0 messages must have 0 value")
}
w := &crossdomain.LegacyWithdrawal{
MessageSender: msgSender,
XDomainTarget: c.Target,
XDomainSender: c.Sender,
XDomainData: c.Data,
XDomainNonce: c.Nonce,
}
return w
case 1:
t.Fatalf("cannot convert version 1 messages to withdrawals")
default:
t.Fatalf("unknown message version: %d", version)
}
return nil
}
package crossdomain
import (
"errors"
"fmt"
"math/big"
......@@ -14,18 +13,18 @@ import (
// version 1 messages have a value and the most significant
// byte of the nonce is a 1
type CrossDomainMessage struct {
Nonce *big.Int `json:"nonce"`
Sender *common.Address `json:"sender"`
Target *common.Address `json:"target"`
Value *big.Int `json:"value"`
GasLimit *big.Int `json:"gasLimit"`
Data []byte `json:"data"`
Nonce *big.Int `json:"nonce"`
Sender common.Address `json:"sender"`
Target common.Address `json:"target"`
Value *big.Int `json:"value"`
GasLimit *big.Int `json:"gasLimit"`
Data []byte `json:"data"`
}
// NewCrossDomainMessage creates a CrossDomainMessage.
func NewCrossDomainMessage(
nonce *big.Int,
sender, target *common.Address,
sender, target common.Address,
value, gasLimit *big.Int,
data []byte,
) *CrossDomainMessage {
......@@ -77,23 +76,3 @@ func (c *CrossDomainMessage) Hash() (common.Hash, error) {
func (c *CrossDomainMessage) HashV1() (common.Hash, error) {
return HashCrossDomainMessageV1(c.Nonce, c.Sender, c.Target, c.Value, c.GasLimit, c.Data)
}
// ToWithdrawal will turn a CrossDomainMessage into a Withdrawal.
// This only works for version 0 CrossDomainMessages as not all of
// the data is present for version 1 CrossDomainMessages to be turned
// into Withdrawals.
func (c *CrossDomainMessage) ToWithdrawal() (WithdrawalMessage, error) {
version := c.Version()
switch version {
case 0:
if c.Value != nil && c.Value.Cmp(common.Big0) != 0 {
return nil, errors.New("version 0 messages must have 0 value")
}
w := NewLegacyWithdrawal(c.Target, c.Sender, c.Data, c.Nonce)
return w, nil
case 1:
return nil, errors.New("version 1 messages cannot be turned into withdrawals")
default:
return nil, fmt.Errorf("unknown version %d", version)
}
}
......@@ -18,8 +18,8 @@ func TestEncode(t *testing.T) {
t.Run("V0", func(t *testing.T) {
msg := crossdomain.NewCrossDomainMessage(
crossdomain.EncodeVersionedNonce(common.Big0, common.Big0),
&common.Address{},
&common.Address{19: 0x01},
common.Address{},
common.Address{19: 0x01},
big.NewInt(0),
big.NewInt(5),
[]byte{},
......@@ -37,8 +37,8 @@ func TestEncode(t *testing.T) {
t.Run("V1", func(t *testing.T) {
msg := crossdomain.NewCrossDomainMessage(
crossdomain.EncodeVersionedNonce(common.Big1, common.Big1),
&common.Address{19: 0x01},
&common.Address{19: 0x02},
common.Address{19: 0x01},
common.Address{19: 0x02},
big.NewInt(100),
big.NewInt(555),
[]byte{},
......@@ -63,8 +63,8 @@ func TestHash(t *testing.T) {
t.Run("V0", func(t *testing.T) {
msg := crossdomain.NewCrossDomainMessage(
crossdomain.EncodeVersionedNonce(common.Big0, common.Big0),
&common.Address{},
&common.Address{19: 0x01},
common.Address{},
common.Address{19: 0x01},
big.NewInt(10),
big.NewInt(5),
[]byte{},
......@@ -82,8 +82,8 @@ func TestHash(t *testing.T) {
t.Run("V1", func(t *testing.T) {
msg := crossdomain.NewCrossDomainMessage(
crossdomain.EncodeVersionedNonce(common.Big0, common.Big1),
&common.Address{},
&common.Address{19: 0x01},
common.Address{},
common.Address{19: 0x01},
big.NewInt(0),
big.NewInt(5),
[]byte{},
......
......@@ -19,7 +19,7 @@ var (
)
// MigrateWithdrawals will migrate a list of pending withdrawals given a StateDB.
func MigrateWithdrawals(withdrawals []*LegacyWithdrawal, db vm.StateDB, l1CrossDomainMessenger *common.Address, noCheck bool) error {
func MigrateWithdrawals(withdrawals SafeFilteredWithdrawals, db vm.StateDB, l1CrossDomainMessenger *common.Address, noCheck bool) error {
for i, legacy := range withdrawals {
legacySlot, err := legacy.StorageSlot()
if err != nil {
......@@ -66,17 +66,17 @@ func MigrateWithdrawal(withdrawal *LegacyWithdrawal, l1CrossDomainMessenger *com
// Migrated withdrawals are specified as version 0. Both the
// L2ToL1MessagePasser and the CrossDomainMessenger use the same
// versioning scheme. Both should be set to version 0
versionedNonce := EncodeVersionedNonce(withdrawal.Nonce, new(big.Int))
versionedNonce := EncodeVersionedNonce(withdrawal.XDomainNonce, new(big.Int))
// Encode the call to `relayMessage` on the `CrossDomainMessenger`.
// The minGasLimit can safely be 0 here.
data, err := abi.Pack(
"relayMessage",
versionedNonce,
withdrawal.Sender,
withdrawal.Target,
withdrawal.XDomainSender,
withdrawal.XDomainTarget,
value,
new(big.Int),
[]byte(withdrawal.Data),
[]byte(withdrawal.XDomainData),
)
if err != nil {
return nil, fmt.Errorf("cannot abi encode relayMessage: %w", err)
......
......@@ -17,10 +17,7 @@ func TestMigrateWithdrawal(t *testing.T) {
for _, receipt := range receipts {
msg, err := findCrossDomainMessage(receipt)
require.Nil(t, err)
withdrawal, err := msg.ToWithdrawal()
require.Nil(t, err)
legacyWithdrawal, ok := withdrawal.(*crossdomain.LegacyWithdrawal)
require.True(t, ok)
legacyWithdrawal := toWithdrawal(t, predeploys.L2CrossDomainMessengerAddr, msg)
withdrawals = append(withdrawals, legacyWithdrawal)
}
......@@ -31,7 +28,7 @@ func TestMigrateWithdrawal(t *testing.T) {
require.Nil(t, err)
require.NotNil(t, withdrawal)
require.Equal(t, legacy.Nonce.Uint64(), withdrawal.Nonce.Uint64())
require.Equal(t, legacy.XDomainNonce.Uint64(), withdrawal.Nonce.Uint64())
require.Equal(t, *withdrawal.Sender, predeploys.L2CrossDomainMessengerAddr)
require.Equal(t, *withdrawal.Target, l1CrossDomainMessenger)
})
......
package crossdomain
import (
"errors"
"fmt"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/log"
)
var (
ErrUnknownSlotInMessagePasser = errors.New("unknown slot in legacy message passer")
ErrMissingSlotInWitness = errors.New("missing storage slot in witness data")
)
// PreCheckWithdrawals checks that the given list of withdrawals represents all withdrawals made
// in the legacy system and filters out any extra withdrawals not included in the legacy system.
func PreCheckWithdrawals(db *state.StateDB, withdrawals []*LegacyWithdrawal) ([]*LegacyWithdrawal, error) {
func PreCheckWithdrawals(db *state.StateDB, withdrawals DangerousUnfilteredWithdrawals) (SafeFilteredWithdrawals, error) {
// Convert each withdrawal into a storage slot, and build a map of those slots.
slotsInp := make(map[common.Hash]*LegacyWithdrawal)
for _, wd := range withdrawals {
......@@ -26,6 +31,7 @@ func PreCheckWithdrawals(db *state.StateDB, withdrawals []*LegacyWithdrawal) ([]
// Build a mapping of the slots of all messages actually sent in the legacy system.
var count int
var innerErr error
slotsAct := make(map[common.Hash]bool)
err := db.ForEachStorage(predeploys.LegacyMessagePasserAddr, func(key, value common.Hash) bool {
// When a message is inserted into the LegacyMessagePasser, it is stored with the value
......@@ -33,7 +39,7 @@ func PreCheckWithdrawals(db *state.StateDB, withdrawals []*LegacyWithdrawal) ([]
// can safely ignore anything that is not "true".
if value != abiTrue {
// Should not happen!
log.Error("found unknown slot in LegacyMessagePasser", "key", key.String(), "val", value.String())
innerErr = fmt.Errorf("%w: key: %s, val: %s", ErrUnknownSlotInMessagePasser, key.String(), value.String())
return true
}
......@@ -45,6 +51,9 @@ func PreCheckWithdrawals(db *state.StateDB, withdrawals []*LegacyWithdrawal) ([]
if err != nil {
return nil, fmt.Errorf("cannot iterate over LegacyMessagePasser: %w", err)
}
if innerErr != nil {
return nil, innerErr
}
// Log the number of messages we found.
log.Info("Iterated legacy messages", "count", count)
......@@ -53,13 +62,13 @@ func PreCheckWithdrawals(db *state.StateDB, withdrawals []*LegacyWithdrawal) ([]
for slot := range slotsAct {
_, ok := slotsInp[slot]
if !ok {
return nil, fmt.Errorf("unknown storage slot in state: %s", slot)
return nil, ErrMissingSlotInWitness
}
}
// Iterate over the list of input messages and check that we have a known slot for each one.
// We'll filter out any extra messages that are not in the legacy system.
filtered := make([]*LegacyWithdrawal, 0)
filtered := make(SafeFilteredWithdrawals, 0)
for slot := range slotsInp {
_, ok := slotsAct[slot]
if !ok {
......@@ -67,7 +76,13 @@ func PreCheckWithdrawals(db *state.StateDB, withdrawals []*LegacyWithdrawal) ([]
continue
}
filtered = append(filtered, slotsInp[slot])
wd := slotsInp[slot]
if wd.MessageSender != predeploys.L2CrossDomainMessengerAddr {
log.Info("filtering out message from sender other than the L2XDM", "sender", wd.MessageSender)
continue
}
filtered = append(filtered, wd)
}
// At this point, we know that the list of filtered withdrawals MUST be exactly the same as the
......
package crossdomain
import (
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/trie"
"github.com/stretchr/testify/require"
)
func TestPreCheckWithdrawals_Filtering(t *testing.T) {
dbWds := []*LegacyWithdrawal{
// Random legacy WD to something other than the L2XDM.
{
MessageSender: common.Address{19: 0xFF},
XDomainTarget: common.Address{19: 0x01},
XDomainSender: common.Address{19: 0x02},
XDomainData: []byte{0x01, 0x02, 0x03},
XDomainNonce: big.NewInt(0),
},
// Random legacy WD to the L2XDM. Should be the only thing
// returned by the prechecker.
{
MessageSender: predeploys.L2CrossDomainMessengerAddr,
XDomainTarget: common.Address{19: 0x01},
XDomainSender: common.Address{19: 0x02},
XDomainData: []byte{0x01, 0x02, 0x03},
XDomainNonce: big.NewInt(1),
},
}
// Add an additional witness to the witnesses list to
// test how the prechecker handles witness data that
// isn't in state.
witnessWds := append([]*LegacyWithdrawal{
{
MessageSender: common.Address{19: 0xAA},
XDomainTarget: common.Address{19: 0x03},
XDomainSender: predeploys.L2CrossDomainMessengerAddr,
XDomainData: []byte{0x01, 0x02, 0x03},
XDomainNonce: big.NewInt(0),
},
}, dbWds...)
filteredWds, err := runPrecheck(t, dbWds, witnessWds)
require.NoError(t, err)
require.EqualValues(t, []*LegacyWithdrawal{dbWds[1]}, filteredWds)
}
func TestPreCheckWithdrawals_InvalidSlotInStorage(t *testing.T) {
rawDB := rawdb.NewMemoryDatabase()
rawStateDB := state.NewDatabaseWithConfig(rawDB, &trie.Config{
Preimages: true,
Cache: 1024,
})
stateDB, err := state.New(common.Hash{}, rawStateDB, nil)
require.NoError(t, err)
// Create account, and set a random storage slot to a value
// other than abiTrue.
stateDB.CreateAccount(predeploys.LegacyMessagePasserAddr)
stateDB.SetState(predeploys.LegacyMessagePasserAddr, common.Hash{0: 0xff}, common.Hash{0: 0xff})
root, err := stateDB.Commit(false)
require.NoError(t, err)
err = stateDB.Database().TrieDB().Commit(root, true, nil)
require.NoError(t, err)
_, err = PreCheckWithdrawals(stateDB, nil)
require.ErrorIs(t, err, ErrUnknownSlotInMessagePasser)
}
func TestPreCheckWithdrawals_MissingStorageSlot(t *testing.T) {
// Add a legacy WD to state that does not appear in witness data.
dbWds := []*LegacyWithdrawal{
{
XDomainTarget: common.Address{19: 0x01},
XDomainSender: predeploys.L2CrossDomainMessengerAddr,
XDomainData: []byte{0x01, 0x02, 0x03},
XDomainNonce: big.NewInt(1),
},
}
// Create some witness data that includes both a valid
// and an invalid witness, but neither of which correspond
// to the value above in state.
witnessWds := []*LegacyWithdrawal{
{
XDomainTarget: common.Address{19: 0x01},
XDomainSender: common.Address{19: 0x02},
XDomainData: []byte{0x01, 0x02, 0x03},
XDomainNonce: big.NewInt(0),
},
{
XDomainTarget: common.Address{19: 0x03},
XDomainSender: predeploys.L2CrossDomainMessengerAddr,
XDomainData: []byte{0x01, 0x02, 0x03},
XDomainNonce: big.NewInt(0),
},
}
_, err := runPrecheck(t, dbWds, witnessWds)
require.ErrorIs(t, err, ErrMissingSlotInWitness)
}
func runPrecheck(t *testing.T, dbWds []*LegacyWithdrawal, witnessWds []*LegacyWithdrawal) ([]*LegacyWithdrawal, error) {
rawDB := rawdb.NewMemoryDatabase()
rawStateDB := state.NewDatabaseWithConfig(rawDB, &trie.Config{
Preimages: true,
Cache: 1024,
})
stateDB, err := state.New(common.Hash{}, rawStateDB, nil)
require.NoError(t, err)
stateDB.CreateAccount(predeploys.LegacyMessagePasserAddr)
for _, wd := range dbWds {
slot, err := wd.StorageSlot()
require.NoError(t, err)
stateDB.SetState(predeploys.LegacyMessagePasserAddr, slot, abiTrue)
}
root, err := stateDB.Commit(false)
require.NoError(t, err)
err = stateDB.Database().TrieDB().Commit(root, true, nil)
require.NoError(t, err)
return PreCheckWithdrawals(stateDB, witnessWds)
}
......@@ -5,6 +5,15 @@ import (
"github.com/ethereum/go-ethereum/common"
)
// DangerousUnfilteredWithdrawals is a list of raw withdrawal witness
// data. It has not been filtered for messages from sources other than
// the
type DangerousUnfilteredWithdrawals []*LegacyWithdrawal
// SafeFilteredWithdrawals is a list of withdrawals that have been filtered to only include
// withdrawals that were from the L2XDM.
type SafeFilteredWithdrawals []*LegacyWithdrawal
var (
// Standard ABI types
Uint256Type, _ = abi.NewType("uint256", "", nil)
......
......@@ -87,8 +87,8 @@ func GetPendingWithdrawals(messengers *Messengers, version *big.Int, start, end
msg := NewCrossDomainMessage(
event.MessageNonce,
&event.Sender,
&event.Target,
event.Sender,
event.Target,
common.Big0,
event.GasLimit,
event.Message,
......@@ -116,10 +116,10 @@ func GetPendingWithdrawals(messengers *Messengers, version *big.Int, start, end
withdrawal := PendingWithdrawal{
LegacyWithdrawal: LegacyWithdrawal{
Target: &event.Target,
Sender: &event.Sender,
Data: event.Message,
Nonce: event.MessageNonce,
XDomainTarget: event.Target,
XDomainSender: event.Sender,
XDomainData: event.Message,
XDomainNonce: event.MessageNonce,
},
TransactionHash: event.Raw.TxHash,
}
......
......@@ -146,8 +146,8 @@ func sendCrossDomainMessage(
// Parse the legacy event
if event.Name == "SentMessage" {
e, _ := l2xdm.ParseSentMessage(*log)
msg.Target = &e.Target
msg.Sender = &e.Sender
msg.Target = e.Target
msg.Sender = e.Sender
msg.Data = e.Message
msg.Nonce = e.MessageNonce
msg.GasLimit = e.GasLimit
......@@ -272,7 +272,7 @@ func TestGetPendingWithdrawals(t *testing.T) {
for i, msg := range msgs[3:] {
withdrawal := withdrawals[i]
require.Equal(t, msg.Target, *withdrawal.Target)
require.Equal(t, msg.Message, []byte(withdrawal.Data))
require.Equal(t, msg.Target, withdrawal.XDomainTarget)
require.Equal(t, msg.Message, []byte(withdrawal.XDomainData))
}
}
......@@ -10,7 +10,15 @@ import (
func Open(path string, cache int, handles int) (ethdb.Database, error) {
chaindataPath := filepath.Join(path, "geth", "chaindata")
ancientPath := filepath.Join(chaindataPath, "ancient")
ldb, err := rawdb.NewLevelDBDatabaseWithFreezer(chaindataPath, cache, handles, ancientPath, "", false)
ldb, err := rawdb.Open(rawdb.OpenOptions{
Type: "leveldb",
Directory: chaindataPath,
AncientsDirectory: ancientPath,
Namespace: "",
Cache: cache,
Handles: handles,
ReadOnly: false,
})
if err != nil {
return nil, err
}
......
......@@ -63,8 +63,6 @@ func NewBackendWithGenesisTimestamp(ts uint64) *backends.SimulatedBackend {
LondonBlock: big.NewInt(0),
ArrowGlacierBlock: big.NewInt(0),
GrayGlacierBlock: big.NewInt(0),
ShanghaiBlock: nil,
CancunBlock: nil,
// Activated proof of stake. We manually build/commit blocks in the simulator anyway,
// and the timestamp verification of PoS is not against the wallclock,
// preventing blocks from getting stuck temporarily in the future-blocks queue, decreasing setup time a lot.
......
......@@ -19,14 +19,15 @@ func MustOpenDB(dataDir string) ethdb.Database {
// the caller to pass in LevelDB cache parameters.
func MustOpenDBWithCacheOpts(dataDir string, cacheSize, handles int) ethdb.Database {
dir := filepath.Join(dataDir, "geth", "chaindata")
db, err := rawdb.NewLevelDBDatabaseWithFreezer(
dir,
cacheSize,
handles,
filepath.Join(dir, "ancient"),
"",
true,
)
db, err := rawdb.Open(rawdb.OpenOptions{
Type: "leveldb",
Directory: dir,
AncientsDirectory: filepath.Join(dir, "ancient"),
Namespace: "",
Cache: cacheSize,
Handles: handles,
ReadOnly: true,
})
if err != nil {
log.Crit("error opening raw DB", "err", err)
}
......
......@@ -7,20 +7,20 @@ import (
"fmt"
"math/big"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain"
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis/migration"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/trie"
"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/genesis/migration"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
)
// MaxSlotChecks is the maximum number of storage slots to check
......@@ -181,8 +181,25 @@ func PostCheckUntouchables(udb state.Database, currDB *state.StateDB, prevRoot c
log.Info("checked code hash", "address", addr, "hash", hash)
// Ensure that the current/previous roots match
prevRoot := prevDB.StorageTrie(addr).Hash()
currRoot := currDB.StorageTrie(addr).Hash()
var prevRoot, currRoot common.Hash
prevStorage, err := prevDB.StorageTrie(addr)
if err != nil {
return fmt.Errorf("failed to open previous-db storage trie of %s: %w", addr, err)
}
if prevStorage == nil {
prevRoot = types.EmptyRootHash
} else {
prevRoot = prevStorage.Hash()
}
currStorage, err := currDB.StorageTrie(addr)
if err != nil {
return fmt.Errorf("failed to open current-db storage trie of %s: %w", addr, err)
}
if currStorage == nil {
currRoot = types.EmptyRootHash
} else {
currRoot = currStorage.Hash()
}
if prevRoot != currRoot {
return fmt.Errorf("expected storage root for %s to be %s, but got %s", addr, prevRoot, currRoot)
}
......@@ -191,12 +208,11 @@ func PostCheckUntouchables(udb state.Database, currDB *state.StateDB, prevRoot c
// Sample storage slots to ensure that they are not modified.
var count int
expSlots := make(map[common.Hash]common.Hash)
err := prevDB.ForEachStorage(addr, func(key, value common.Hash) bool {
if err := prevDB.ForEachStorage(addr, func(key, value common.Hash) bool {
count++
expSlots[key] = value
return count < MaxSlotChecks
})
if err != nil {
}); err != nil {
return fmt.Errorf("error iterating over storage: %w", err)
}
......@@ -461,7 +477,8 @@ func CheckWithdrawalsAfter(db vm.StateDB, data migration.MigrationData, l1CrossD
// First, make a mapping between old withdrawal slots and new ones.
// This list can be a superset of what was actually migrated, since
// some witness data may references withdrawals that reverted.
oldToNew := make(map[common.Hash]common.Hash)
oldToNewSlots := make(map[common.Hash]common.Hash)
wdsByOldSlot := make(map[common.Hash]*crossdomain.LegacyWithdrawal)
for _, wd := range wds {
migrated, err := crossdomain.MigrateWithdrawal(wd, l1CrossDomainMessenger)
if err != nil {
......@@ -477,7 +494,8 @@ func CheckWithdrawalsAfter(db vm.StateDB, data migration.MigrationData, l1CrossD
return fmt.Errorf("cannot compute migrated storage slot: %w", err)
}
oldToNew[legacySlot] = migratedSlot
oldToNewSlots[legacySlot] = migratedSlot
wdsByOldSlot[legacySlot] = wd
}
// Now, iterate over each legacy withdrawal and check if there is a corresponding
......@@ -498,17 +516,29 @@ func CheckWithdrawalsAfter(db vm.StateDB, data migration.MigrationData, l1CrossD
}
// Grab the migrated slot.
migratedSlot := oldToNew[key]
migratedSlot := oldToNewSlots[key]
if migratedSlot == (common.Hash{}) {
innerErr = fmt.Errorf("no migrated slot found for legacy slot %s", key)
return false
}
// Look up the migrated slot in the DB, and make sure it is abiTrue.
// Look up the migrated slot in the DB.
migratedValue := db.GetState(predeploys.L2ToL1MessagePasserAddr, migratedSlot)
if migratedValue != abiTrue {
innerErr = fmt.Errorf("expected migrated value to be true, but got %s", migratedValue)
return false
// If the sender is _not_ the L2XDM, the value should not be migrated.
wd := wdsByOldSlot[key]
if wd.XDomainSender == predeploys.L2CrossDomainMessengerAddr {
// Make sure the value is abiTrue if this withdrawal should be migrated.
if migratedValue != abiTrue {
innerErr = fmt.Errorf("expected migrated value to be true, but got %s", migratedValue)
return false
}
} else {
// Otherwise, ensure that withdrawals from senders other than the L2XDM are _not_ migrated.
if migratedValue != abiFalse {
innerErr = fmt.Errorf("a migration from a sender other than the L2XDM was migrated")
return false
}
}
return true
......
......@@ -20,7 +20,8 @@ import (
)
var (
abiTrue = common.Hash{31: 0x01}
abiTrue = common.Hash{31: 0x01}
abiFalse = common.Hash{}
// BedrockTransitionBlockExtraData represents the extradata
// set in the very first bedrock block. This value must be
// less than 32 bytes long or it will create an invalid block.
......@@ -120,7 +121,7 @@ func MigrateDB(ldb ethdb.Database, config *DeployConfig, l1Block *types.Block, m
// We now need to check that we have all of the withdrawals that we expect to have. An error
// will be thrown if there are any missing messages, and any extra messages will be removed.
var filteredWithdrawals []*crossdomain.LegacyWithdrawal
var filteredWithdrawals crossdomain.SafeFilteredWithdrawals
if !noCheck {
log.Info("Checking withdrawals...")
filteredWithdrawals, err = crossdomain.PreCheckWithdrawals(db, unfilteredWithdrawals)
......@@ -129,7 +130,7 @@ func MigrateDB(ldb ethdb.Database, config *DeployConfig, l1Block *types.Block, m
}
} else {
log.Info("Skipping checking withdrawals")
filteredWithdrawals = unfilteredWithdrawals
filteredWithdrawals = crossdomain.SafeFilteredWithdrawals(unfilteredWithdrawals)
}
// We also need to verify that we have all of the storage slots for the LegacyERC20ETH contract
......@@ -255,7 +256,7 @@ func MigrateDB(ldb ethdb.Database, config *DeployConfig, l1Block *types.Block, m
// Otherwise we need to write the changes to disk. First we commit the state changes.
log.Info("Committing trie DB")
if err := db.Database().TrieDB().Commit(newRoot, true, nil); err != nil {
if err := db.Database().TrieDB().Commit(newRoot, true); err != nil {
return nil, err
}
......
......@@ -51,8 +51,6 @@ func NewL2Genesis(config *DeployConfig, block *types.Block) (*core.Genesis, erro
ArrowGlacierBlock: big.NewInt(0),
GrayGlacierBlock: big.NewInt(0),
MergeNetsplitBlock: big.NewInt(0),
ShanghaiBlock: nil,
CancunBlock: nil,
TerminalTotalDifficulty: big.NewInt(0),
TerminalTotalDifficultyPassed: true,
BedrockBlock: new(big.Int).SetUint64(uint64(config.L2GenesisBlockNumber)),
......@@ -121,8 +119,6 @@ func NewL1Genesis(config *DeployConfig) (*core.Genesis, error) {
LondonBlock: big.NewInt(0),
ArrowGlacierBlock: big.NewInt(0),
GrayGlacierBlock: big.NewInt(0),
ShanghaiBlock: nil,
CancunBlock: nil,
}
if config.CliqueSignerAddress != (common.Address{}) {
......
......@@ -216,7 +216,13 @@ func BuildL1DeveloperGenesis(config *DeployConfig) (*core.Genesis, error) {
}
for _, dep := range deployments {
st := stateDB.StorageTrie(dep.Address)
st, err := stateDB.StorageTrie(dep.Address)
if err != nil {
return nil, fmt.Errorf("failed to open storage trie of %s: %w", dep.Address, err)
}
if st == nil {
return nil, fmt.Errorf("missing account %s in state, address: %s", dep.Name, dep.Address)
}
iter := trie.NewIterator(st.NodeIterator(nil))
depAddr := dep.Address
......
......@@ -5,8 +5,6 @@ import (
"fmt"
"os"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
......@@ -119,12 +117,9 @@ type MigrationData struct {
EvmMessages []*SentMessage
}
func (m *MigrationData) ToWithdrawals() ([]*crossdomain.LegacyWithdrawal, error) {
messages := make([]*crossdomain.LegacyWithdrawal, 0)
func (m *MigrationData) ToWithdrawals() (crossdomain.DangerousUnfilteredWithdrawals, error) {
messages := make(crossdomain.DangerousUnfilteredWithdrawals, 0)
for _, msg := range m.OvmMessages {
if msg.Who != predeploys.L2CrossDomainMessengerAddr {
continue
}
wd, err := msg.ToLegacyWithdrawal()
if err != nil {
return nil, err
......@@ -135,9 +130,6 @@ func (m *MigrationData) ToWithdrawals() ([]*crossdomain.LegacyWithdrawal, error)
}
}
for _, msg := range m.EvmMessages {
if msg.Who != predeploys.L2CrossDomainMessengerAddr {
continue
}
wd, err := msg.ToLegacyWithdrawal()
if err != nil {
return nil, err
......
......@@ -76,7 +76,16 @@ func Migrate(cfg *Config) (*genesis.MigrationResult, error) {
chaindataPath := filepath.Join(cfg.L2DBPath, "geth", "chaindata")
ancientPath := filepath.Join(chaindataPath, "ancient")
ldb, err := rawdb.NewLevelDBDatabaseWithFreezer(chaindataPath, 4096, 120, ancientPath, "", false)
ldb, err := rawdb.Open(
rawdb.OpenOptions{
Type: "leveldb",
Directory: chaindataPath,
Cache: 4096,
Handles: 120,
AncientsDirectory: ancientPath,
Namespace: "",
ReadOnly: false,
})
if err != nil {
return nil, err
}
......
......@@ -11,6 +11,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
)
var _ vm.StateDB = (*MemoryStateDB)(nil)
......@@ -312,3 +313,15 @@ func (db *MemoryStateDB) ForEachStorage(addr common.Address, cb func(common.Hash
}
return nil
}
func (db *MemoryStateDB) GetTransientState(addr common.Address, key common.Hash) common.Hash {
panic("transient state is unsupported")
}
func (db *MemoryStateDB) SetTransientState(addr common.Address, key, value common.Hash) {
panic("transient state is unsupported")
}
func (db *MemoryStateDB) Prepare(rules params.Rules, sender, coinbase common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList) {
// no-op, no transient state to prepare, nor any access-list to set/prepare
}
......@@ -105,7 +105,7 @@ func (s *L1Miner) ActL1IncludeTx(from common.Address) Action {
return
}
s.pendingIndices[from] = i + 1 // won't retry the tx
s.l1BuildingState.Prepare(tx.Hash(), len(s.l1Transactions))
s.l1BuildingState.SetTxContext(tx.Hash(), len(s.l1Transactions))
receipt, err := core.ApplyTransaction(s.l1Cfg.Config, s.l1Chain, &s.l1BuildingHeader.Coinbase,
s.l1GasPool, s.l1BuildingState, s.l1BuildingHeader, tx, &s.l1BuildingHeader.GasUsed, *s.l1Chain.GetVMConfig())
if err != nil {
......@@ -141,7 +141,7 @@ func (s *L1Miner) ActL1EndBlock(t Testing) {
if err != nil {
t.Fatalf("l1 state write error: %v", err)
}
if err := s.l1BuildingState.Database().TrieDB().Commit(root, false, nil); err != nil {
if err := s.l1BuildingState.Database().TrieDB().Commit(root, false); err != nil {
t.Fatalf("l1 trie write error: %v", err)
}
......
......@@ -192,7 +192,7 @@ func (s *L2Batcher) ActL2BatchSubmit(t Testing) {
GasFeeCap: gasFeeCap,
Data: data.Bytes(),
}
gas, err := core.IntrinsicGas(rawTx.Data, nil, false, true, true)
gas, err := core.IntrinsicGas(rawTx.Data, nil, false, true, true, false)
require.NoError(t, err, "need to compute intrinsic gas")
rawTx.Gas = gas
......@@ -275,7 +275,7 @@ func (s *L2Batcher) ActL2BatchSubmitGarbage(t Testing, kind GarbageKind) {
GasFeeCap: gasFeeCap,
Data: outputFrame,
}
gas, err := core.IntrinsicGas(rawTx.Data, nil, false, true, true)
gas, err := core.IntrinsicGas(rawTx.Data, nil, false, true, true, false)
require.NoError(t, err, "need to compute intrinsic gas")
rawTx.Gas = gas
......
......@@ -3,18 +3,18 @@ package actions
import (
"errors"
"github.com/ethereum/go-ethereum/ethclient/gethclient"
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/beacon/engine"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/beacon"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
geth "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/ethclient/gethclient"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
......@@ -53,7 +53,7 @@ type L2Engine struct {
l2ForceEmpty bool // when no additional txs may be processed (i.e. when sequencer drift runs out)
l2TxFailed []*types.Transaction // log of failed transactions which could not be included
payloadID beacon.PayloadID // ID of payload that is currently being built
payloadID engine.PayloadID // ID of payload that is currently being built
failL2RPC error // mock error
}
......@@ -182,7 +182,7 @@ func (e *L2Engine) ActL2IncludeTx(from common.Address) Action {
return
}
e.pendingIndices[from] = i + 1 // won't retry the tx
e.l2BuildingState.Prepare(tx.Hash(), len(e.l2Transactions))
e.l2BuildingState.SetTxContext(tx.Hash(), len(e.l2Transactions))
receipt, err := core.ApplyTransaction(e.l2Cfg.Config, e.l2Chain, &e.l2BuildingHeader.Coinbase,
e.l2GasPool, e.l2BuildingState, e.l2BuildingHeader, tx, &e.l2BuildingHeader.GasUsed, *e.l2Chain.GetVMConfig())
if err != nil {
......
......@@ -9,16 +9,15 @@ import (
"math/big"
"time"
"github.com/ethereum/go-ethereum/consensus/misc"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/beacon/engine"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/misc"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/beacon"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum-optimism/optimism/op-node/eth"
)
......@@ -35,7 +34,7 @@ var (
)
// computePayloadId computes a pseudo-random payloadid, based on the parameters.
func computePayloadId(headBlockHash common.Hash, params *eth.PayloadAttributes) beacon.PayloadID {
func computePayloadId(headBlockHash common.Hash, params *eth.PayloadAttributes) engine.PayloadID {
// Hash
hasher := sha256.New()
hasher.Write(headBlockHash[:])
......@@ -49,7 +48,7 @@ func computePayloadId(headBlockHash common.Hash, params *eth.PayloadAttributes)
hasher.Write(tx)
}
_ = binary.Write(hasher, binary.BigEndian, *params.GasLimit)
var out beacon.PayloadID
var out engine.PayloadID
copy(out[:], hasher.Sum(nil)[:8])
return out
}
......@@ -96,7 +95,7 @@ func (ea *L2EngineAPI) startBlock(parent common.Hash, params *eth.PayloadAttribu
if err := tx.UnmarshalBinary(otx); err != nil {
return fmt.Errorf("transaction %d is not valid: %w", i, err)
}
ea.l2BuildingState.Prepare(tx.Hash(), i)
ea.l2BuildingState.SetTxContext(tx.Hash(), i)
receipt, err := core.ApplyTransaction(ea.l2Cfg.Config, ea.l2Chain, &ea.l2BuildingHeader.Coinbase,
ea.l2GasPool, ea.l2BuildingState, ea.l2BuildingHeader, &tx, &ea.l2BuildingHeader.GasUsed, *ea.l2Chain.GetVMConfig())
if err != nil {
......@@ -125,7 +124,7 @@ func (ea *L2EngineAPI) endBlock() (*types.Block, error) {
if err != nil {
return nil, fmt.Errorf("l2 state write error: %w", err)
}
if err := ea.l2BuildingState.Database().TrieDB().Commit(root, false, nil); err != nil {
if err := ea.l2BuildingState.Database().TrieDB().Commit(root, false); err != nil {
return nil, fmt.Errorf("l2 trie write error: %w", err)
}
return block, nil
......@@ -135,12 +134,12 @@ func (ea *L2EngineAPI) GetPayloadV1(ctx context.Context, payloadId eth.PayloadID
ea.log.Trace("L2Engine API request received", "method", "GetPayload", "id", payloadId)
if ea.payloadID != payloadId {
ea.log.Warn("unexpected payload ID requested for block building", "expected", ea.payloadID, "got", payloadId)
return nil, beacon.UnknownPayload
return nil, engine.UnknownPayload
}
bl, err := ea.endBlock()
if err != nil {
ea.log.Error("failed to finish block building", "err", err)
return nil, beacon.UnknownPayload
return nil, engine.UnknownPayload
}
return eth.BlockAsPayload(bl)
}
......@@ -180,7 +179,7 @@ func (ea *L2EngineAPI) ForkchoiceUpdatedV1(ctx context.Context, state *eth.Forkc
return &eth.ForkchoiceUpdatedResult{PayloadStatus: INVALID_TERMINAL_BLOCK, PayloadID: nil}, nil
}
}
valid := func(id *beacon.PayloadID) *eth.ForkchoiceUpdatedResult {
valid := func(id *engine.PayloadID) *eth.ForkchoiceUpdatedResult {
return &eth.ForkchoiceUpdatedResult{
PayloadStatus: eth.PayloadStatusV1{Status: eth.ExecutionValid, LatestValidHash: &state.HeadBlockHash},
PayloadID: id,
......@@ -206,10 +205,10 @@ func (ea *L2EngineAPI) ForkchoiceUpdatedV1(ctx context.Context, state *eth.Forkc
finalBlock := ea.l2Chain.GetBlockByHash(state.FinalizedBlockHash)
if finalBlock == nil {
ea.log.Warn("Final block not available in database", "hash", state.FinalizedBlockHash)
return STATUS_INVALID, beacon.InvalidForkChoiceState.With(errors.New("final block not available in database"))
return STATUS_INVALID, engine.InvalidForkChoiceState.With(errors.New("final block not available in database"))
} else if rawdb.ReadCanonicalHash(ea.l2Database, finalBlock.NumberU64()) != state.FinalizedBlockHash {
ea.log.Warn("Final block not in canonical chain", "number", block.NumberU64(), "hash", state.HeadBlockHash)
return STATUS_INVALID, beacon.InvalidForkChoiceState.With(errors.New("final block not in canonical chain"))
return STATUS_INVALID, engine.InvalidForkChoiceState.With(errors.New("final block not in canonical chain"))
}
// Set the finalized block
ea.l2Chain.SetFinalized(finalBlock)
......@@ -219,11 +218,11 @@ func (ea *L2EngineAPI) ForkchoiceUpdatedV1(ctx context.Context, state *eth.Forkc
safeBlock := ea.l2Chain.GetBlockByHash(state.SafeBlockHash)
if safeBlock == nil {
ea.log.Warn("Safe block not available in database")
return STATUS_INVALID, beacon.InvalidForkChoiceState.With(errors.New("safe block not available in database"))
return STATUS_INVALID, engine.InvalidForkChoiceState.With(errors.New("safe block not available in database"))
}
if rawdb.ReadCanonicalHash(ea.l2Database, safeBlock.NumberU64()) != state.SafeBlockHash {
ea.log.Warn("Safe block not in canonical chain")
return STATUS_INVALID, beacon.InvalidForkChoiceState.With(errors.New("safe block not in canonical chain"))
return STATUS_INVALID, engine.InvalidForkChoiceState.With(errors.New("safe block not in canonical chain"))
}
// Set the safe block
ea.l2Chain.SetSafe(safeBlock)
......@@ -235,7 +234,7 @@ func (ea *L2EngineAPI) ForkchoiceUpdatedV1(ctx context.Context, state *eth.Forkc
err := ea.startBlock(state.HeadBlockHash, attr)
if err != nil {
ea.log.Error("Failed to start block building", "err", err, "noTxPool", attr.NoTxPool, "txs", len(attr.Transactions), "timestamp", attr.Timestamp)
return STATUS_INVALID, beacon.InvalidPayloadAttributes.With(err)
return STATUS_INVALID, engine.InvalidPayloadAttributes.With(err)
}
return valid(&ea.payloadID), nil
......@@ -249,7 +248,7 @@ func (ea *L2EngineAPI) NewPayloadV1(ctx context.Context, payload *eth.ExecutionP
for i, tx := range payload.Transactions {
txs[i] = tx
}
block, err := beacon.ExecutableDataToBlock(beacon.ExecutableDataV1{
block, err := engine.ExecutableDataToBlock(engine.ExecutableData{
ParentHash: payload.ParentHash,
FeeRecipient: payload.FeeRecipient,
StateRoot: common.Hash(payload.StateRoot),
......
......@@ -112,6 +112,7 @@ func initL1Geth(cfg *SystemConfig, genesis *core.Genesis, opts ...GethOption) (*
ethConfig := &ethconfig.Config{
NetworkId: cfg.DeployConfig.L1ChainID,
Genesis: genesis,
Miner: miner.Config{Etherbase: cfg.DeployConfig.CliqueSignerAddress},
}
nodeConfig := &node.Config{
Name: "l1-geth",
......
......@@ -8,9 +8,9 @@ import (
"github.com/holiman/uint256"
"github.com/ethereum/go-ethereum/beacon/engine"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/beacon"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/trie"
)
......@@ -123,7 +123,7 @@ type Uint256Quantity = uint256.Int
type Data = hexutil.Bytes
type PayloadID = beacon.PayloadID
type PayloadID = engine.PayloadID
type ExecutionPayload struct {
ParentHash common.Hash `json:"parentHash"`
......
......@@ -16,12 +16,13 @@ import (
)
func randConfig() *Config {
rng := rand.New(rand.NewSource(1234))
randHash := func() (out [32]byte) {
rand.Read(out[:])
rng.Read(out[:])
return
}
randAddr := func() (out common.Address) { // we need generics...
rand.Read(out[:])
rng.Read(out[:])
return
}
return &Config{
......
......@@ -35,7 +35,15 @@ type Cheater struct {
func OpenGethRawDB(dataDirPath string, readOnly bool) (ethdb.Database, error) {
// don't use readonly mode in actual DB, it doesn't work with Geth.
db, err := rawdb.NewLevelDBDatabaseWithFreezer(dataDirPath, 2048, 500, filepath.Join(dataDirPath, "ancient"), "", readOnly)
db, err := rawdb.Open(rawdb.OpenOptions{
Type: "leveldb",
Directory: dataDirPath,
AncientsDirectory: filepath.Join(dataDirPath, "ancient"),
Namespace: "",
Cache: 2048,
Handles: 500,
ReadOnly: readOnly,
})
if err != nil {
return nil, fmt.Errorf("failed to open leveldb: %w", err)
}
......@@ -99,7 +107,7 @@ func (ch *Cheater) RunAndClose(fn HeadFn) error {
blockHash := header.Hash()
// We have to manually commit the updated state root to the database.
if err := state.Database().TrieDB().Commit(stateRoot, true, nil); err != nil {
if err := state.Database().TrieDB().Commit(stateRoot, true); err != nil {
return fmt.Errorf("error committing trie db: %w", err)
}
......@@ -178,7 +186,13 @@ func StorageGet(address common.Address, key common.Hash, w io.Writer) HeadFn {
// to another account (maybe even in a different database!).
func StorageReadAll(address common.Address, w io.Writer) HeadFn {
return func(headState *state.StateDB) error {
storage := headState.StorageTrie(address)
storage, err := headState.StorageTrie(address)
if err != nil {
return fmt.Errorf("failed to open storage trie of addr %s: %w", address, err)
}
if storage == nil {
return fmt.Errorf("no storage trie in state for account %s", address)
}
iter := trie.NewIterator(storage.NodeIterator(nil))
for iter.Next() {
if _, err := fmt.Fprintf(w, "+ %x = %x\n", iter.Key, dbValueToHash(iter.Value)); err != nil {
......@@ -205,8 +219,20 @@ func dbValueToHash(enc []byte) common.Hash {
// Each difference is expressed with 1 character + or - to indicate the change from a to b, followed by key = value.
func StorageDiff(out io.Writer, addressA, addressB common.Address) HeadFn {
return func(headState *state.StateDB) error {
aStorage := headState.StorageTrie(addressA)
bStorage := headState.StorageTrie(addressB)
aStorage, err := headState.StorageTrie(addressA)
if err != nil {
return fmt.Errorf("failed to open storage trie of addr A %s: %w", addressA, err)
}
if aStorage == nil {
return fmt.Errorf("no storage trie in state for account A %s", addressA)
}
bStorage, err := headState.StorageTrie(addressB)
if err != nil {
return fmt.Errorf("failed to open storage trie of addr B %s: %w", addressB, err)
}
if bStorage == nil {
return fmt.Errorf("no storage trie in state for account B %s", addressB)
}
aIter := trie.NewIterator(aStorage.NodeIterator(nil))
bIter := trie.NewIterator(bStorage.NodeIterator(nil))
hasA := aIter.Next()
......
......@@ -6,9 +6,9 @@ import (
"math/big"
"time"
"github.com/ethereum/go-ethereum/beacon/engine"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/beacon"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
......@@ -67,8 +67,8 @@ func headSafeFinalized(ctx context.Context, client client.RPC) (head *types.Bloc
return head, safe, finalized, nil
}
func insertBlock(ctx context.Context, client client.RPC, payload *beacon.ExecutableDataV1) error {
var payloadResult *beacon.PayloadStatusV1
func insertBlock(ctx context.Context, client client.RPC, payload *engine.ExecutableData) error {
var payloadResult *engine.PayloadStatusV1
if err := client.CallContext(ctx, &payloadResult, "engine_newPayloadV1", payload); err != nil {
return fmt.Errorf("failed to insert block %d: %w", payload.Number, err)
}
......@@ -79,9 +79,9 @@ func insertBlock(ctx context.Context, client client.RPC, payload *beacon.Executa
}
func updateForkchoice(ctx context.Context, client client.RPC, head, safe, finalized common.Hash) error {
var post beacon.ForkChoiceResponse
var post engine.ForkChoiceResponse
if err := client.CallContext(ctx, &post, "engine_forkchoiceUpdatedV1",
beacon.ForkchoiceStateV1{
engine.ForkchoiceStateV1{
HeadBlockHash: head,
SafeBlockHash: safe,
FinalizedBlockHash: finalized,
......@@ -101,14 +101,14 @@ type BlockBuildingSettings struct {
BuildTime time.Duration
}
func BuildBlock(ctx context.Context, client client.RPC, status *StatusData, settings *BlockBuildingSettings) (*beacon.ExecutableDataV1, error) {
var pre beacon.ForkChoiceResponse
func BuildBlock(ctx context.Context, client client.RPC, status *StatusData, settings *BlockBuildingSettings) (*engine.ExecutableData, error) {
var pre engine.ForkChoiceResponse
if err := client.CallContext(ctx, &pre, "engine_forkchoiceUpdatedV1",
beacon.ForkchoiceStateV1{
engine.ForkchoiceStateV1{
HeadBlockHash: status.Head.Hash,
SafeBlockHash: status.Safe.Hash,
FinalizedBlockHash: status.Finalized.Hash,
}, beacon.PayloadAttributesV1{
}, engine.PayloadAttributes{
Timestamp: status.Head.Time + settings.BlockTime,
Random: settings.Random,
SuggestedFeeRecipient: settings.FeeRecipient,
......@@ -130,7 +130,7 @@ func BuildBlock(ctx context.Context, client client.RPC, status *StatusData, sett
case <-time.After(settings.BuildTime):
}
var payload *beacon.ExecutableDataV1
var payload *engine.ExecutableData
if err := client.CallContext(ctx, &payload, "engine_getPayloadV1", pre.PayloadID); err != nil {
return nil, fmt.Errorf("failed to get payload %v, %d time after instructing engine to build it: %w", pre.PayloadID, settings.BuildTime, err)
}
......@@ -149,7 +149,7 @@ func Auto(ctx context.Context, metrics Metricer, client client.RPC, log log.Logg
ticker := time.NewTicker(time.Millisecond * 100)
defer ticker.Stop()
var lastPayload *beacon.ExecutableDataV1
var lastPayload *engine.ExecutableData
var buildErr error
for {
select {
......@@ -264,10 +264,11 @@ func Copy(ctx context.Context, copyFrom client.RPC, copyTo client.RPC) error {
if err != nil {
return err
}
payload := beacon.BlockToExecutableData(copyHead)
payloadEnv := engine.BlockToExecutableData(copyHead, nil)
if err := updateForkchoice(ctx, copyTo, copyHead.ParentHash(), copySafe.Hash(), copyFinalized.Hash()); err != nil {
return err
}
payload := payloadEnv.ExecutionPayload
if err := insertBlock(ctx, copyTo, payload); err != nil {
return err
}
......
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