Commit b1c38583 authored by protolambda's avatar protolambda

op-e2e: change L1 mock from clique to fake proof of stake to update to op-geth v1.11.5 draft

parent d4cac8b0
...@@ -9,7 +9,7 @@ require ( ...@@ -9,7 +9,7 @@ require (
github.com/docker/docker v20.10.21+incompatible github.com/docker/docker v20.10.21+incompatible
github.com/docker/go-connections v0.4.0 github.com/docker/go-connections v0.4.0
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3
github.com/ethereum/go-ethereum v1.11.4 github.com/ethereum/go-ethereum v1.11.5
github.com/fsnotify/fsnotify v1.6.0 github.com/fsnotify/fsnotify v1.6.0
github.com/golang/snappy v0.0.4 github.com/golang/snappy v0.0.4
github.com/google/go-cmp v0.5.9 github.com/google/go-cmp v0.5.9
...@@ -189,6 +189,6 @@ require ( ...@@ -189,6 +189,6 @@ require (
nhooyr.io/websocket v1.8.7 // indirect nhooyr.io/websocket v1.8.7 // indirect
) )
replace github.com/ethereum/go-ethereum v1.11.4 => github.com/ethereum-optimism/op-geth v1.11.2-de8c5df46.0.20230322010758-876919e42d47 replace github.com/ethereum/go-ethereum v1.11.5 => github.com/ethereum-optimism/op-geth v1.11.2-de8c5df46.0.20230324105532-555b76f39878
//replace github.com/ethereum/go-ethereum v1.11.4 => ../go-ethereum //replace github.com/ethereum/go-ethereum v1.11.5 => ../go-ethereum
...@@ -184,8 +184,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 ...@@ -184,8 +184,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z8veEq5ZO3DfIhZ7xgRP9WTc= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z8veEq5ZO3DfIhZ7xgRP9WTc=
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs=
github.com/ethereum-optimism/op-geth v1.11.2-de8c5df46.0.20230322010758-876919e42d47 h1:xrBiXPH8nviEeG7s6Llsfk4/cw+nRkSzgH0/UChu+cE= github.com/ethereum-optimism/op-geth v1.11.2-de8c5df46.0.20230324105532-555b76f39878 h1:pk3lFrP6zay7+jT+yoFAWxvGbP1Z/5lsorimXGrQoxE=
github.com/ethereum-optimism/op-geth v1.11.2-de8c5df46.0.20230322010758-876919e42d47/go.mod h1:SGLXBOtu2JlKrNoUG76EatI2uJX/WZRY4nmEyvE9Q38= github.com/ethereum-optimism/op-geth v1.11.2-de8c5df46.0.20230324105532-555b76f39878/go.mod h1:SGLXBOtu2JlKrNoUG76EatI2uJX/WZRY4nmEyvE9Q38=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ= github.com/fjl/memsize v0.0.1 h1:+zhkb+dhUgx0/e+M8sF0QqiouvMQUiKR+QYvdxIOKcQ=
......
...@@ -72,6 +72,7 @@ func NewL1Replica(t Testing, log log.Logger, genesis *core.Genesis) *L1Replica { ...@@ -72,6 +72,7 @@ func NewL1Replica(t Testing, log log.Logger, genesis *core.Genesis) *L1Replica {
backend, err := eth.New(n, ethCfg) backend, err := eth.New(n, ethCfg)
require.NoError(t, err) require.NoError(t, err)
backend.Merger().FinalizePoS()
n.RegisterAPIs(tracers.APIs(backend.APIBackend)) n.RegisterAPIs(tracers.APIs(backend.APIBackend))
......
...@@ -11,6 +11,7 @@ import ( ...@@ -11,6 +11,7 @@ import (
"github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/beacon/engine"
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
...@@ -21,6 +22,7 @@ import ( ...@@ -21,6 +22,7 @@ import (
"github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
) )
...@@ -112,7 +114,6 @@ func initL1Geth(cfg *SystemConfig, genesis *core.Genesis, opts ...GethOption) (* ...@@ -112,7 +114,6 @@ func initL1Geth(cfg *SystemConfig, genesis *core.Genesis, opts ...GethOption) (*
ethConfig := &ethconfig.Config{ ethConfig := &ethconfig.Config{
NetworkId: cfg.DeployConfig.L1ChainID, NetworkId: cfg.DeployConfig.L1ChainID,
Genesis: genesis, Genesis: genesis,
Miner: miner.Config{Etherbase: cfg.DeployConfig.CliqueSignerAddress},
} }
nodeConfig := &node.Config{ nodeConfig := &node.Config{
Name: "l1-geth", Name: "l1-geth",
...@@ -128,44 +129,107 @@ func initL1Geth(cfg *SystemConfig, genesis *core.Genesis, opts ...GethOption) (* ...@@ -128,44 +129,107 @@ func initL1Geth(cfg *SystemConfig, genesis *core.Genesis, opts ...GethOption) (*
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
// Activate merge
l1Eth.Merger().FinalizePoS()
// Clique does not have safe/finalized block info. But we do want to test the usage of that, // Instead of running a whole beacon node, we run this fake-proof-of-stake sidecar that sequences L1 blocks using the Engine API.
// since post-merge L1 has it (incl. Goerli testnet which is already upgraded). So we mock it on top of clique. l1Node.RegisterLifecycle(&fakePoS{
l1Node.RegisterLifecycle(&fakeSafeFinalizedL1{ eth: l1Eth,
eth: l1Eth, log: log.Root(), // geth logger is global anyway. Would be nice to replace with a local logger though.
blockTime: cfg.DeployConfig.L1BlockTime,
// for testing purposes we make it really fast, otherwise we don't see it finalize in short tests // for testing purposes we make it really fast, otherwise we don't see it finalize in short tests
finalizedDistance: 8, finalizedDistance: 8,
safeDistance: 4, safeDistance: 4,
engineAPI: catalyst.NewConsensusAPI(l1Eth),
}) })
return l1Node, l1Eth, nil return l1Node, l1Eth, nil
} }
type fakeSafeFinalizedL1 struct { // fakePoS is a testing-only utility to attach to Geth,
eth *eth.Ethereum // to build a fake proof-of-stake L1 chain with fixed block time and basic lagging safe/finalized blocks.
type fakePoS struct {
eth *eth.Ethereum
log log.Logger
blockTime uint64
finalizedDistance uint64 finalizedDistance uint64
safeDistance uint64 safeDistance uint64
sub ethereum.Subscription
}
var _ node.Lifecycle = (*fakeSafeFinalizedL1)(nil) engineAPI *catalyst.ConsensusAPI
sub ethereum.Subscription
}
func (f *fakeSafeFinalizedL1) Start() error { func (f *fakePoS) Start() error {
headChanges := make(chan core.ChainHeadEvent, 10)
headsSub := f.eth.BlockChain().SubscribeChainHeadEvent(headChanges)
f.sub = event.NewSubscription(func(quit <-chan struct{}) error { f.sub = event.NewSubscription(func(quit <-chan struct{}) error {
defer headsSub.Unsubscribe() // poll every half a second: enough to catch up with any block time when ticks are missed
t := time.NewTicker(time.Second / 2)
for { for {
select { select {
case head := <-headChanges: case now := <-t.C:
num := head.Block.NumberU64() chain := f.eth.BlockChain()
if num > f.finalizedDistance { head := chain.CurrentBlock()
toFinalize := f.eth.BlockChain().GetHeaderByNumber(num - f.finalizedDistance) finalized := chain.CurrentFinalBlock()
f.eth.BlockChain().SetFinalized(toFinalize) if finalized == nil { // fallback to genesis if nothing is finalized
finalized = chain.Genesis().Header()
}
safe := chain.CurrentSafeBlock()
if safe == nil { // fallback to finalized if nothing is safe
safe = finalized
}
if head.Number.Uint64() > f.finalizedDistance { // progress finalized block, if we can
finalized = f.eth.BlockChain().GetHeaderByNumber(head.Number.Uint64() - f.finalizedDistance)
}
if head.Number.Uint64() > f.safeDistance { // progress safe block, if we can
safe = f.eth.BlockChain().GetHeaderByNumber(head.Number.Uint64() - f.safeDistance)
}
// start building the block as soon as we are past the current head time
if head.Time >= uint64(now.Unix()) {
continue
}
res, err := f.engineAPI.ForkchoiceUpdatedV1(engine.ForkchoiceStateV1{
HeadBlockHash: head.Hash(),
SafeBlockHash: safe.Hash(),
FinalizedBlockHash: finalized.Hash(),
}, &engine.PayloadAttributes{
Timestamp: head.Time + f.blockTime,
Random: common.Hash{},
SuggestedFeeRecipient: head.Coinbase,
})
if err != nil {
f.log.Error("failed to start building L1 block", "err", err)
continue
}
if res.PayloadID == nil {
f.log.Error("failed to start block building", "res", res)
continue
}
// wait with sealing, if we are not behind already
delay := time.Until(time.Unix(int64(head.Time+f.blockTime), 0))
tim := time.NewTimer(delay)
select {
case <-tim.C:
// no-op
case <-quit:
tim.Stop()
return nil
}
payload, err := f.engineAPI.GetPayloadV1(*res.PayloadID)
if err != nil {
f.log.Error("failed to finish building L1 block", "err", err)
continue
}
if _, err := f.engineAPI.NewPayloadV1(*payload); err != nil {
f.log.Error("failed to insert built L1 block", "err", err)
continue
} }
if num > f.safeDistance { if _, err := f.engineAPI.ForkchoiceUpdatedV1(engine.ForkchoiceStateV1{
toSafe := f.eth.BlockChain().GetHeaderByNumber(num - f.safeDistance) HeadBlockHash: payload.BlockHash,
f.eth.BlockChain().SetSafe(toSafe) SafeBlockHash: safe.Hash(),
FinalizedBlockHash: finalized.Hash(),
}, nil); err != nil {
f.log.Error("failed to make built L1 block canonical", "err", err)
continue
} }
case <-quit: case <-quit:
return nil return nil
...@@ -175,7 +239,7 @@ func (f *fakeSafeFinalizedL1) Start() error { ...@@ -175,7 +239,7 @@ func (f *fakeSafeFinalizedL1) Start() error {
return nil return nil
} }
func (f *fakeSafeFinalizedL1) Stop() error { func (f *fakePoS) Stop() error {
f.sub.Unsubscribe() f.sub.Unsubscribe()
return nil return nil
} }
......
...@@ -73,7 +73,7 @@ func DefaultSystemConfig(t *testing.T) SystemConfig { ...@@ -73,7 +73,7 @@ func DefaultSystemConfig(t *testing.T) SystemConfig {
L1BlockTime: 2, L1BlockTime: 2,
L1GenesisBlockNonce: 4660, L1GenesisBlockNonce: 4660,
CliqueSignerAddress: addresses.CliqueSigner, CliqueSignerAddress: common.Address{}, // op-e2e used to run Clique, but now uses fake Proof of Stake.
L1GenesisBlockTimestamp: hexutil.Uint64(time.Now().Unix()), L1GenesisBlockTimestamp: hexutil.Uint64(time.Now().Unix()),
L1GenesisBlockGasLimit: 30_000_000, L1GenesisBlockGasLimit: 30_000_000,
L1GenesisBlockDifficulty: uint642big(1), L1GenesisBlockDifficulty: uint642big(1),
...@@ -381,11 +381,6 @@ func (cfg SystemConfig) Start(_opts ...SystemConfigOption) (*System, error) { ...@@ -381,11 +381,6 @@ func (cfg SystemConfig) Start(_opts ...SystemConfigOption) (*System, error) {
didErrAfterStart = true didErrAfterStart = true
return nil, err return nil, err
} }
err = l1Backend.StartMining(1)
if err != nil {
didErrAfterStart = true
return nil, err
}
for name, node := range sys.Nodes { for name, node := range sys.Nodes {
if name == "l1" { if name == "l1" {
continue continue
......
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