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

Merge branch 'develop' into clabby/ctb/loosen-reprove-reqs

parents e6e819fc e09468b2
...@@ -2,4 +2,4 @@ ...@@ -2,4 +2,4 @@
This is a utility for running a local Bedrock devnet. It is designed to replace the legacy Bash-based devnet runner as part of a progressive migration away from Bash automation. This is a utility for running a local Bedrock devnet. It is designed to replace the legacy Bash-based devnet runner as part of a progressive migration away from Bash automation.
The easiest way to invoke this script is to run `make devnet-up-deploy` from the root of this repository. Otherwise, to use this script run `python3 main.py --monorepo-path=<path to the monorepo>`. You may need to set `PYTHONPATH` to this directory if you are invoking the script from somewhere other than `bedrock-devnet`. The easiest way to invoke this script is to run `make devnet-up-deploy` from the root of this repository. Otherwise, to use this script run `python3 main.py --monorepo-dir=<path to the monorepo>`. You may need to set `PYTHONPATH` to this directory if you are invoking the script from somewhere other than `bedrock-devnet`.
\ No newline at end of file
...@@ -5,6 +5,8 @@ import ( ...@@ -5,6 +5,8 @@ import (
"fmt" "fmt"
"os" "os"
"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/crossdomain"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
...@@ -120,6 +122,9 @@ type MigrationData struct { ...@@ -120,6 +122,9 @@ type MigrationData struct {
func (m *MigrationData) ToWithdrawals() ([]*crossdomain.LegacyWithdrawal, error) { func (m *MigrationData) ToWithdrawals() ([]*crossdomain.LegacyWithdrawal, error) {
messages := make([]*crossdomain.LegacyWithdrawal, 0) messages := make([]*crossdomain.LegacyWithdrawal, 0)
for _, msg := range m.OvmMessages { for _, msg := range m.OvmMessages {
if msg.Who != predeploys.L2CrossDomainMessengerAddr {
continue
}
wd, err := msg.ToLegacyWithdrawal() wd, err := msg.ToLegacyWithdrawal()
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -130,6 +135,9 @@ func (m *MigrationData) ToWithdrawals() ([]*crossdomain.LegacyWithdrawal, error) ...@@ -130,6 +135,9 @@ func (m *MigrationData) ToWithdrawals() ([]*crossdomain.LegacyWithdrawal, error)
} }
} }
for _, msg := range m.EvmMessages { for _, msg := range m.EvmMessages {
if msg.Who != predeploys.L2CrossDomainMessengerAddr {
continue
}
wd, err := msg.ToLegacyWithdrawal() wd, err := msg.ToLegacyWithdrawal()
if err != nil { if err != nil {
return nil, err return nil, err
......
...@@ -4,8 +4,11 @@ import ( ...@@ -4,8 +4,11 @@ import (
"context" "context"
"fmt" "fmt"
"net" "net"
"sync"
"time" "time"
"github.com/libp2p/go-libp2p/core/network"
lconf "github.com/libp2p/go-libp2p/config" lconf "github.com/libp2p/go-libp2p/config"
"github.com/libp2p/go-libp2p/core/connmgr" "github.com/libp2p/go-libp2p/core/connmgr"
"github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/host"
...@@ -34,6 +37,11 @@ type extraHost struct { ...@@ -34,6 +37,11 @@ type extraHost struct {
host.Host host.Host
gater ConnectionGater gater ConnectionGater
connMgr connmgr.ConnManager connMgr connmgr.ConnManager
log log.Logger
staticPeers []*peer.AddrInfo
quitC chan struct{}
} }
func (e *extraHost) ConnectionGater() ConnectionGater { func (e *extraHost) ConnectionGater() ConnectionGater {
...@@ -44,6 +52,73 @@ func (e *extraHost) ConnectionManager() connmgr.ConnManager { ...@@ -44,6 +52,73 @@ func (e *extraHost) ConnectionManager() connmgr.ConnManager {
return e.connMgr return e.connMgr
} }
func (e *extraHost) Close() error {
close(e.quitC)
return e.Host.Close()
}
func (e *extraHost) initStaticPeers() {
for _, addr := range e.staticPeers {
e.Peerstore().AddAddrs(addr.ID, addr.Addrs, time.Hour*24*7)
// We protect the peer, so the connection manager doesn't decide to prune it.
// We tag it with "static" so other protects/unprotects with different tags don't affect this protection.
e.connMgr.Protect(addr.ID, "static")
// Try to dial the node in the background
go func(addr *peer.AddrInfo) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
defer cancel()
if err := e.dialStaticPeer(ctx, addr); err != nil {
e.log.Warn("error dialing static peer", "peer", addr.ID, "err", err)
}
}(addr)
}
}
func (e *extraHost) dialStaticPeer(ctx context.Context, addr *peer.AddrInfo) error {
e.log.Info("dialing static peer", "peer", addr.ID, "addrs", addr.Addrs)
if _, err := e.Network().DialPeer(ctx, addr.ID); err != nil {
return err
}
return nil
}
func (e *extraHost) monitorStaticPeers() {
tick := time.NewTicker(time.Minute)
defer tick.Stop()
for {
select {
case <-tick.C:
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
var wg sync.WaitGroup
e.log.Debug("polling static peers", "peers", len(e.staticPeers))
for _, addr := range e.staticPeers {
connectedness := e.Network().Connectedness(addr.ID)
e.log.Trace("static peer connectedness", "peer", addr.ID, "connectedness", connectedness)
if connectedness == network.Connected {
continue
}
wg.Add(1)
go func(addr *peer.AddrInfo) {
e.log.Warn("static peer disconnected, reconnecting", "peer", addr.ID)
if err := e.dialStaticPeer(ctx, addr); err != nil {
e.log.Warn("error reconnecting to static peer", "peer", addr.ID, "err", err)
}
wg.Done()
}(addr)
}
wg.Wait()
cancel()
case <-e.quitC:
return
}
}
}
var _ ExtraHostFeatures = (*extraHost)(nil) var _ ExtraHostFeatures = (*extraHost)(nil)
func (conf *Config) Host(log log.Logger, reporter metrics.Reporter) (host.Host, error) { func (conf *Config) Host(log log.Logger, reporter metrics.Reporter) (host.Host, error) {
...@@ -142,26 +217,28 @@ func (conf *Config) Host(log log.Logger, reporter metrics.Reporter) (host.Host, ...@@ -142,26 +217,28 @@ func (conf *Config) Host(log log.Logger, reporter metrics.Reporter) (host.Host,
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, peerAddr := range conf.StaticPeers {
staticPeers := make([]*peer.AddrInfo, len(conf.StaticPeers))
for i, peerAddr := range conf.StaticPeers {
addr, err := peer.AddrInfoFromP2pAddr(peerAddr) addr, err := peer.AddrInfoFromP2pAddr(peerAddr)
if err != nil { if err != nil {
return nil, fmt.Errorf("bad peer address: %w", err) return nil, fmt.Errorf("bad peer address: %w", err)
} }
h.Peerstore().AddAddrs(addr.ID, addr.Addrs, time.Hour*24*7) staticPeers[i] = addr
// We protect the peer, so the connection manager doesn't decide to prune it.
// We tag it with "static" so other protects/unprotects with different tags don't affect this protection.
connMngr.Protect(addr.ID, "static")
// Try to dial the node in the background
go func() {
log.Info("Dialing static peer", "peer", addr.ID, "addrs", addr.Addrs)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
defer cancel()
if _, err := h.Network().DialPeer(ctx, addr.ID); err != nil {
log.Warn("Failed to dial static peer", "peer", addr.ID, "addrs", addr.Addrs)
}
}()
} }
out := &extraHost{Host: h, connMgr: connMngr}
out := &extraHost{
Host: h,
connMgr: connMngr,
log: log,
staticPeers: staticPeers,
quitC: make(chan struct{}),
}
out.initStaticPeers()
if len(conf.StaticPeers) > 0 {
go out.monitorStaticPeers()
}
// Only add the connection gater if it offers the full interface we're looking for. // Only add the connection gater if it offers the full interface we're looking for.
if g, ok := connGtr.(ConnectionGater); ok { if g, ok := connGtr.(ConnectionGater); ok {
out.gater = g out.gater = g
......
...@@ -5,13 +5,16 @@ import ( ...@@ -5,13 +5,16 @@ import (
"fmt" "fmt"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/op-node/eth" "github.com/ethereum-optimism/optimism/op-node/eth"
) )
// AttributesMatchBlock checks if the L2 attributes pre-inputs match the output // AttributesMatchBlock checks if the L2 attributes pre-inputs match the output
// nil if it is a match. If err is not nil, the error contains the reason for the mismatch // nil if it is a match. If err is not nil, the error contains the reason for the mismatch
func AttributesMatchBlock(attrs *eth.PayloadAttributes, parentHash common.Hash, block *eth.ExecutionPayload) error { func AttributesMatchBlock(attrs *eth.PayloadAttributes, parentHash common.Hash, block *eth.ExecutionPayload, l log.Logger) error {
if parentHash != block.ParentHash { if parentHash != block.ParentHash {
return fmt.Errorf("parent hash field does not match. expected: %v. got: %v", parentHash, block.ParentHash) return fmt.Errorf("parent hash field does not match. expected: %v. got: %v", parentHash, block.ParentHash)
} }
...@@ -26,6 +29,9 @@ func AttributesMatchBlock(attrs *eth.PayloadAttributes, parentHash common.Hash, ...@@ -26,6 +29,9 @@ func AttributesMatchBlock(attrs *eth.PayloadAttributes, parentHash common.Hash,
} }
for i, otx := range attrs.Transactions { for i, otx := range attrs.Transactions {
if expect := block.Transactions[i]; !bytes.Equal(otx, expect) { if expect := block.Transactions[i]; !bytes.Equal(otx, expect) {
if i == 0 {
logL1InfoTxns(l, uint64(block.BlockNumber), uint64(block.Timestamp), otx, block.Transactions[i])
}
return fmt.Errorf("transaction %d does not match. expected: %v. got: %v", i, expect, otx) return fmt.Errorf("transaction %d does not match. expected: %v. got: %v", i, expect, otx)
} }
} }
...@@ -37,3 +43,35 @@ func AttributesMatchBlock(attrs *eth.PayloadAttributes, parentHash common.Hash, ...@@ -37,3 +43,35 @@ func AttributesMatchBlock(attrs *eth.PayloadAttributes, parentHash common.Hash,
} }
return nil return nil
} }
// logL1InfoTxns reports the values from the L1 info tx when they differ to aid
// debugging. This check is the one that has been most frequently triggered.
func logL1InfoTxns(l log.Logger, l2Number, l2Timestamp uint64, safeTx, unsafeTx hexutil.Bytes) {
// First decode into *types.Transaction to get the tx data.
var safeTxValue, unsafeTxValue types.Transaction
errSafe := (&safeTxValue).UnmarshalBinary(safeTx)
errUnsafe := (&unsafeTxValue).UnmarshalBinary(unsafeTx)
if errSafe != nil || errUnsafe != nil {
l.Error("failed to umarshal tx", "errSafe", errSafe, "errUnsafe", errUnsafe)
return
}
// Then decode the ABI encoded parameters
var safeInfo, unsafeInfo L1BlockInfo
errSafe = (&safeInfo).UnmarshalBinary(safeTxValue.Data())
errUnsafe = (&unsafeInfo).UnmarshalBinary(unsafeTxValue.Data())
if errSafe != nil || errUnsafe != nil {
l.Error("failed to umarshal l1 info", "errSafe", errSafe, "errUnsafe", errUnsafe)
return
}
l.Error("L1 Info transaction differs", "number", l2Number, "time", l2Timestamp,
"safe_l1_number", safeInfo.Number, "safe_l1_hash", safeInfo.BlockHash,
"safe_l1_time", safeInfo.Time, "safe_seq_num", safeInfo.SequenceNumber,
"safe_l1_basefee", safeInfo.BaseFee, "safe_batcher_add", safeInfo.BlockHash,
"safe_gpo_scalar", safeInfo.L1FeeScalar, "safe_gpo_overhead", safeInfo.L1FeeOverhead,
"unsafe_l1_number", unsafeInfo.Number, "unsafe_l1_hash", unsafeInfo.BlockHash,
"unsafe_l1_time", unsafeInfo.Time, "unsafe_seq_num", unsafeInfo.SequenceNumber,
"unsafe_l1_basefee", unsafeInfo.BaseFee, "unsafe_batcher_add", unsafeInfo.BlockHash,
"unsafe_gpo_scalar", unsafeInfo.L1FeeScalar, "unsafe_gpo_overhead", unsafeInfo.L1FeeOverhead)
}
...@@ -422,7 +422,7 @@ func (eq *EngineQueue) consolidateNextSafeAttributes(ctx context.Context) error ...@@ -422,7 +422,7 @@ func (eq *EngineQueue) consolidateNextSafeAttributes(ctx context.Context) error
} }
return NewTemporaryError(fmt.Errorf("failed to get existing unsafe payload to compare against derived attributes from L1: %w", err)) return NewTemporaryError(fmt.Errorf("failed to get existing unsafe payload to compare against derived attributes from L1: %w", err))
} }
if err := AttributesMatchBlock(eq.safeAttributes[0], eq.safeHead.Hash, payload); err != nil { if err := AttributesMatchBlock(eq.safeAttributes[0], eq.safeHead.Hash, payload, eq.log); err != nil {
eq.log.Warn("L2 reorg: existing unsafe block does not match derived attributes from L1", "err", err) eq.log.Warn("L2 reorg: existing unsafe block does not match derived attributes from L1", "err", err)
// geth cannot wind back a chain without reorging to a new, previously non-canonical, block // geth cannot wind back a chain without reorging to a new, previously non-canonical, block
return eq.forceNextSafeAttributes(ctx) return eq.forceNextSafeAttributes(ctx)
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
"l1ChainID": 900, "l1ChainID": 900,
"l2ChainID": 901, "l2ChainID": 901,
"l2BlockTime": 2, "l2BlockTime": 2,
"maxSequencerDrift": 300, "maxSequencerDrift": 10,
"sequencerWindowSize": 15, "sequencerWindowSize": 15,
"channelTimeout": 40, "channelTimeout": 40,
"p2pSequencerAddress": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc", "p2pSequencerAddress": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc",
......
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