Skip to content

Commit

Permalink
cmd/geth: implement dev mode for post-merge (#27327)
Browse files Browse the repository at this point in the history
This change adds back the 'geth --dev' mode of operation, using a cl-mocker. 

---------

Co-authored-by: Martin Holst Swende <martin@swende.se>
Co-authored-by: rjl493456442 <garyrong0905@gmail.com>
Co-authored-by: lightclient <14004106+lightclient@users.noreply.github.com>
  • Loading branch information
4 people authored Jul 6, 2023
1 parent ab0e0f3 commit ea78280
Show file tree
Hide file tree
Showing 14 changed files with 543 additions and 31 deletions.
18 changes: 18 additions & 0 deletions cmd/geth/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import (
"github.com/ethereum/go-ethereum/accounts/scwallet"
"github.com/ethereum/go-ethereum/accounts/usbwallet"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/eth/catalyst"
ethcatalyst "github.com/ethereum/go-ethereum/eth/catalyst"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/internal/ethapi"
Expand Down Expand Up @@ -193,6 +195,22 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
if ctx.IsSet(utils.SyncTargetFlag.Name) && cfg.Eth.SyncMode == downloader.FullSync {
utils.RegisterFullSyncTester(stack, eth, ctx.Path(utils.SyncTargetFlag.Name))
}

// Start the dev mode if requested, or launch the engine API for
// interacting with external consensus client.
if ctx.IsSet(utils.DeveloperFlag.Name) {
simBeacon, err := catalyst.NewSimulatedBeacon(ctx.Uint64(utils.DeveloperPeriodFlag.Name), eth)
if err != nil {
utils.Fatalf("failed to register dev mode catalyst service: %v", err)
}
catalyst.RegisterSimulatedBeaconAPIs(stack, simBeacon)
stack.RegisterLifecycle(simBeacon)
} else if cfg.Eth.SyncMode != downloader.LightSync {
err := ethcatalyst.Register(stack, eth)
if err != nil {
utils.Fatalf("failed to register catalyst service: %v", err)
}
}
return stack, backend
}

Expand Down
4 changes: 2 additions & 2 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ var (
utils.NodeKeyHexFlag,
utils.DNSDiscoveryFlag,
utils.DeveloperFlag,
utils.DeveloperPeriodFlag,
utils.DeveloperGasLimitFlag,
utils.DeveloperPeriodFlag,
utils.VMEnableDebugFlag,
utils.NetworkIdFlag,
utils.EthStatsURLFlag,
Expand Down Expand Up @@ -408,7 +408,7 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isCon
}

// Start auxiliary services if enabled
if ctx.Bool(utils.MiningEnabledFlag.Name) || ctx.Bool(utils.DeveloperFlag.Name) {
if ctx.Bool(utils.MiningEnabledFlag.Name) {
// Mining only makes sense if a full Ethereum node is running
if ctx.String(utils.SyncModeFlag.Name) == "light" {
utils.Fatalf("Light clients do not support mining")
Expand Down
7 changes: 2 additions & 5 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ var (
Usage: "Ephemeral proof-of-authority network with a pre-funded developer account, mining enabled",
Category: flags.DevCategory,
}
DeveloperPeriodFlag = &cli.IntFlag{
DeveloperPeriodFlag = &cli.Uint64Flag{
Name: "dev.period",
Usage: "Block period to use in developer mode (0 = mine only if transaction pending)",
Category: flags.DevCategory,
Expand Down Expand Up @@ -1817,7 +1817,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
log.Info("Using developer account", "address", developer.Address)

// Create a new developer genesis block or reuse existing one
cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.Int(DeveloperPeriodFlag.Name)), ctx.Uint64(DeveloperGasLimitFlag.Name), developer.Address)
cfg.Genesis = core.DeveloperGenesisBlock(ctx.Uint64(DeveloperGasLimitFlag.Name), developer.Address)
if ctx.IsSet(DataDirFlag.Name) {
// If datadir doesn't exist we need to open db in write-mode
// so leveldb can create files.
Expand Down Expand Up @@ -1892,9 +1892,6 @@ func RegisterEthService(stack *node.Node, cfg *ethconfig.Config) (ethapi.Backend
Fatalf("Failed to create the LES server: %v", err)
}
}
if err := ethcatalyst.Register(stack, backend); err != nil {
Fatalf("Failed to register the Engine API service: %v", err)
}
stack.RegisterAPIs(tracers.APIs(backend.APIBackend))
return backend.APIBackend, backend
}
Expand Down
2 changes: 1 addition & 1 deletion console/console_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func newTester(t *testing.T, confOverride func(*ethconfig.Config)) *tester {
t.Fatalf("failed to create node: %v", err)
}
ethConf := &ethconfig.Config{
Genesis: core.DeveloperGenesisBlock(15, 11_500_000, common.Address{}),
Genesis: core.DeveloperGenesisBlock(11_500_000, common.Address{}),
Miner: miner.Config{
Etherbase: common.HexToAddress(testAddress),
},
Expand Down
11 changes: 3 additions & 8 deletions core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -554,21 +554,16 @@ func DefaultSepoliaGenesisBlock() *Genesis {
}

// DeveloperGenesisBlock returns the 'geth --dev' genesis block.
func DeveloperGenesisBlock(period uint64, gasLimit uint64, faucet common.Address) *Genesis {
func DeveloperGenesisBlock(gasLimit uint64, faucet common.Address) *Genesis {
// Override the default period to the user requested one
config := *params.AllCliqueProtocolChanges
config.Clique = &params.CliqueConfig{
Period: period,
Epoch: config.Clique.Epoch,
}
config := *params.AllDevChainProtocolChanges

// Assemble and return the genesis with the precompiles and faucet pre-funded
return &Genesis{
Config: &config,
ExtraData: append(append(make([]byte, 32), faucet[:]...), make([]byte, crypto.SignatureLength)...),
GasLimit: gasLimit,
BaseFee: big.NewInt(params.InitialBaseFee),
Difficulty: big.NewInt(1),
Difficulty: big.NewInt(0),
Alloc: map[common.Address]GenesisAccount{
common.BytesToAddress([]byte{1}): {Balance: big.NewInt(1)}, // ECRecover
common.BytesToAddress([]byte{2}): {Balance: big.NewInt(1)}, // SHA256
Expand Down
29 changes: 20 additions & 9 deletions eth/catalyst/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,22 @@ func (api *ConsensusAPI) GetPayloadV2(payloadID engine.PayloadID) (*engine.Execu

func (api *ConsensusAPI) getPayload(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) {
log.Trace("Engine API request received", "method", "GetPayload", "id", payloadID)
data := api.localBlocks.get(payloadID)
data := api.localBlocks.get(payloadID, false)
if data == nil {
return nil, engine.UnknownPayload
}
return data, nil
}

// getFullPayload returns a cached payload by it. The difference is that this
// function always expects a non-empty payload, but can also return empty one
// if no transaction is executable.
//
// Note, this function is not a part of standard engine API, meant to be used
// by consensus client mock in dev mode.
func (api *ConsensusAPI) getFullPayload(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) {
log.Trace("Engine API request received", "method", "GetFullPayload", "id", payloadID)
data := api.localBlocks.get(payloadID, true)
if data == nil {
return nil, engine.UnknownPayload
}
Expand Down Expand Up @@ -715,8 +730,8 @@ func (api *ConsensusAPI) ExchangeCapabilities([]string) []string {
return caps
}

// GetPayloadBodiesV1 implements engine_getPayloadBodiesByHashV1 which allows for retrieval of a list
// of block bodies by the engine api.
// GetPayloadBodiesByHashV1 implements engine_getPayloadBodiesByHashV1 which
// allows for retrieval of a list of block bodies by the engine api.
func (api *ConsensusAPI) GetPayloadBodiesByHashV1(hashes []common.Hash) []*engine.ExecutionPayloadBodyV1 {
var bodies = make([]*engine.ExecutionPayloadBodyV1, len(hashes))
for i, hash := range hashes {
Expand All @@ -726,8 +741,8 @@ func (api *ConsensusAPI) GetPayloadBodiesByHashV1(hashes []common.Hash) []*engin
return bodies
}

// GetPayloadBodiesByRangeV1 implements engine_getPayloadBodiesByRangeV1 which allows for retrieval of a range
// of block bodies by the engine api.
// GetPayloadBodiesByRangeV1 implements engine_getPayloadBodiesByRangeV1 which
// allows for retrieval of a range of block bodies by the engine api.
func (api *ConsensusAPI) GetPayloadBodiesByRangeV1(start, count hexutil.Uint64) ([]*engine.ExecutionPayloadBodyV1, error) {
if start == 0 || count == 0 {
return nil, engine.InvalidParams.With(fmt.Errorf("invalid start or count, start: %v count: %v", start, count))
Expand All @@ -753,23 +768,19 @@ func getBody(block *types.Block) *engine.ExecutionPayloadBodyV1 {
if block == nil {
return nil
}

var (
body = block.Body()
txs = make([]hexutil.Bytes, len(body.Transactions))
withdrawals = body.Withdrawals
)

for j, tx := range body.Transactions {
data, _ := tx.MarshalBinary()
txs[j] = hexutil.Bytes(data)
}

// Post-shanghai withdrawals MUST be set to empty slice instead of nil
if withdrawals == nil && block.Header().WithdrawalsHash != nil {
withdrawals = make([]*types.Withdrawal, 0)
}

return &engine.ExecutionPayloadBodyV1{
TransactionData: txs,
Withdrawals: withdrawals,
Expand Down
7 changes: 5 additions & 2 deletions eth/catalyst/queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func (q *payloadQueue) put(id engine.PayloadID, payload *miner.Payload) {
}

// get retrieves a previously stored payload item or nil if it does not exist.
func (q *payloadQueue) get(id engine.PayloadID) *engine.ExecutionPayloadEnvelope {
func (q *payloadQueue) get(id engine.PayloadID, full bool) *engine.ExecutionPayloadEnvelope {
q.lock.RLock()
defer q.lock.RUnlock()

Expand All @@ -82,7 +82,10 @@ func (q *payloadQueue) get(id engine.PayloadID) *engine.ExecutionPayloadEnvelope
return nil // no more items
}
if item.id == id {
return item.payload.Resolve()
if !full {
return item.payload.Resolve()
}
return item.payload.ResolveFull()
}
}
return nil
Expand Down
Loading

0 comments on commit ea78280

Please sign in to comment.