Merge branch 'master' into enhance-simulation-api

This commit is contained in:
Rez 2025-03-19 07:35:54 +11:00
commit ea7217b5dd
No known key found for this signature in database
21 changed files with 280 additions and 32 deletions

View file

@ -55,4 +55,17 @@ var (
AddFork("CAPELLA", 256, []byte{4, 1, 112, 0}).
AddFork("DENEB", 29696, []byte{5, 1, 112, 0}).
AddFork("ELECTRA", 115968, []byte{6, 1, 112, 0})
HoodiLightConfig = (&ChainConfig{
GenesisValidatorsRoot: common.HexToHash("0x212f13fc4df078b6cb7db228f1c8307566dcecf900867401a92023d7ba99cb5f"),
GenesisTime: 1742212800,
Checkpoint: common.HexToHash(""),
}).
AddFork("GENESIS", 0, common.FromHex("0x10000910")).
AddFork("ALTAIR", 0, common.FromHex("0x20000910")).
AddFork("BELLATRIX", 0, common.FromHex("0x30000910")).
AddFork("CAPELLA", 0, common.FromHex("0x40000910")).
AddFork("DENEB", 0, common.FromHex("0x50000910")).
AddFork("ELECTRA", 2048, common.FromHex("0x60000910")).
AddFork("FULU", 18446744073709551615, common.FromHex("0x70000910"))
)

View file

@ -47,6 +47,7 @@ func main() {
utils.MainnetFlag,
utils.SepoliaFlag,
utils.HoleskyFlag,
utils.HoodiFlag,
utils.BlsyncApiFlag,
utils.BlsyncJWTSecretFlag,
},

View file

@ -234,6 +234,8 @@ func ethFilter(args []string) (nodeFilter, error) {
filter = forkid.NewStaticFilter(params.SepoliaChainConfig, core.DefaultSepoliaGenesisBlock().ToBlock())
case "holesky":
filter = forkid.NewStaticFilter(params.HoleskyChainConfig, core.DefaultHoleskyGenesisBlock().ToBlock())
case "hoodi":
filter = forkid.NewStaticFilter(params.HoodiChainConfig, core.DefaultHoodiGenesisBlock().ToBlock())
default:
return nil, fmt.Errorf("unknown network %q", args[0])
}

View file

@ -296,6 +296,9 @@ func prepare(ctx *cli.Context) {
case ctx.IsSet(utils.HoleskyFlag.Name):
log.Info("Starting Geth on Holesky testnet...")
case ctx.IsSet(utils.HoodiFlag.Name):
log.Info("Starting Geth on Hoodi testnet...")
case ctx.IsSet(utils.DeveloperFlag.Name):
log.Info("Starting Geth in ephemeral dev mode...")
log.Warn(`You are running Geth in --dev mode. Please note the following:
@ -322,6 +325,7 @@ func prepare(ctx *cli.Context) {
// Make sure we're not on any supported preconfigured testnet either
if !ctx.IsSet(utils.HoleskyFlag.Name) &&
!ctx.IsSet(utils.SepoliaFlag.Name) &&
!ctx.IsSet(utils.HoodiFlag.Name) &&
!ctx.IsSet(utils.DeveloperFlag.Name) {
// Nope, we're really on mainnet. Bump that cache up!
log.Info("Bumping default cache on mainnet", "provided", ctx.Int(utils.CacheFlag.Name), "updated", 4096)

View file

@ -134,7 +134,7 @@ var (
}
NetworkIdFlag = &cli.Uint64Flag{
Name: "networkid",
Usage: "Explicitly set network id (integer)(For testnets: use --sepolia, --holesky instead)",
Usage: "Explicitly set network id (integer)(For testnets: use --sepolia, --holesky, --hoodi instead)",
Value: ethconfig.Defaults.NetworkId,
Category: flags.EthCategory,
}
@ -153,6 +153,11 @@ var (
Usage: "Holesky network: pre-configured proof-of-stake test network",
Category: flags.EthCategory,
}
HoodiFlag = &cli.BoolFlag{
Name: "hoodi",
Usage: "Hoodi network: pre-configured proof-of-stake test network",
Category: flags.EthCategory,
}
// Dev mode
DeveloperFlag = &cli.BoolFlag{
Name: "dev",
@ -958,6 +963,7 @@ var (
TestnetFlags = []cli.Flag{
SepoliaFlag,
HoleskyFlag,
HoodiFlag,
}
// NetworkFlags is the flag group of all built-in supported networks.
NetworkFlags = append([]cli.Flag{MainnetFlag}, TestnetFlags...)
@ -984,6 +990,9 @@ func MakeDataDir(ctx *cli.Context) string {
if ctx.Bool(HoleskyFlag.Name) {
return filepath.Join(path, "holesky")
}
if ctx.Bool(HoodiFlag.Name) {
return filepath.Join(path, "hoodi")
}
return path
}
Fatalf("Cannot determine default data directory, please set manually (--datadir)")
@ -1044,6 +1053,8 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
urls = params.HoleskyBootnodes
case ctx.Bool(SepoliaFlag.Name):
urls = params.SepoliaBootnodes
case ctx.Bool(HoodiFlag.Name):
urls = params.HoodiBootnodes
}
}
cfg.BootstrapNodes = mustParseBootnodes(urls)
@ -1428,6 +1439,8 @@ func SetDataDir(ctx *cli.Context, cfg *node.Config) {
cfg.DataDir = filepath.Join(node.DefaultDataDir(), "sepolia")
case ctx.Bool(HoleskyFlag.Name) && cfg.DataDir == node.DefaultDataDir():
cfg.DataDir = filepath.Join(node.DefaultDataDir(), "holesky")
case ctx.Bool(HoodiFlag.Name) && cfg.DataDir == node.DefaultDataDir():
cfg.DataDir = filepath.Join(node.DefaultDataDir(), "hoodi")
}
}
@ -1554,7 +1567,7 @@ func setRequiredBlocks(ctx *cli.Context, cfg *ethconfig.Config) {
// SetEthConfig applies eth-related command line flags to the config.
func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
// Avoid conflicting network flags
flags.CheckExclusive(ctx, MainnetFlag, DeveloperFlag, SepoliaFlag, HoleskyFlag)
flags.CheckExclusive(ctx, MainnetFlag, DeveloperFlag, SepoliaFlag, HoleskyFlag, HoodiFlag)
flags.CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer
// Set configurations from CLI flags
@ -1738,6 +1751,12 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
}
cfg.Genesis = core.DefaultSepoliaGenesisBlock()
SetDNSDiscoveryDefaults(cfg, params.SepoliaGenesisHash)
case ctx.Bool(HoodiFlag.Name):
if !ctx.IsSet(NetworkIdFlag.Name) {
cfg.NetworkId = 560048
}
cfg.Genesis = core.DefaultHoodiGenesisBlock()
SetDNSDiscoveryDefaults(cfg, params.HoodiGenesisHash)
case ctx.Bool(DeveloperFlag.Name):
if !ctx.IsSet(NetworkIdFlag.Name) {
cfg.NetworkId = 1337
@ -1852,6 +1871,8 @@ func MakeBeaconLightConfig(ctx *cli.Context) bparams.ClientConfig {
config.ChainConfig = *bparams.SepoliaLightConfig
case ctx.Bool(HoleskyFlag.Name):
config.ChainConfig = *bparams.HoleskyLightConfig
case ctx.Bool(HoodiFlag.Name):
config.ChainConfig = *bparams.HoodiLightConfig
default:
if !customConfig {
config.ChainConfig = *bparams.MainnetLightConfig
@ -2055,7 +2076,7 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb.
}
chainDb = remotedb.New(client)
default:
chainDb, err = stack.OpenDatabaseWithFreezer("chaindata", cache, handles, ctx.String(AncientFlag.Name), "", readonly)
chainDb, err = stack.OpenDatabaseWithFreezer("chaindata", cache, handles, ctx.String(AncientFlag.Name), "eth/db/chaindata/", readonly)
}
if err != nil {
Fatalf("Could not open database: %v", err)
@ -2118,6 +2139,8 @@ func MakeGenesis(ctx *cli.Context) *core.Genesis {
genesis = core.DefaultHoleskyGenesisBlock()
case ctx.Bool(SepoliaFlag.Name):
genesis = core.DefaultSepoliaGenesisBlock()
case ctx.Bool(HoodiFlag.Name):
genesis = core.DefaultHoodiGenesisBlock()
case ctx.Bool(DeveloperFlag.Name):
Fatalf("Developer chains are ephemeral")
}

View file

@ -46,6 +46,9 @@ var checkpointsSepoliaJSON []byte
//go:embed checkpoints_holesky.json
var checkpointsHoleskyJSON []byte
//go:embed checkpoints_hoodi.json
var checkpointsHoodiJSON []byte
// checkpoints lists sets of checkpoints for multiple chains. The matching
// checkpoint set is autodetected by the indexer once the canonical chain is
// known.
@ -53,6 +56,7 @@ var checkpoints = []checkpointList{
decodeCheckpoints(checkpointsMainnetJSON),
decodeCheckpoints(checkpointsSepoliaJSON),
decodeCheckpoints(checkpointsHoleskyJSON),
decodeCheckpoints(checkpointsHoodiJSON),
}
func decodeCheckpoints(encoded []byte) (result checkpointList) {

View file

@ -0,0 +1 @@
[]

View file

@ -346,6 +346,9 @@ func (f *FilterMaps) needTailEpoch(epoch uint32) bool {
if epoch > firstEpoch {
return true
}
if (epoch+1)<<f.logMapsPerEpoch >= f.indexedRange.maps.AfterLast() {
return true
}
if epoch+1 < firstEpoch {
return false
}

View file

@ -185,27 +185,30 @@ func (f *FilterMaps) lastCanonicalMapBoundaryBefore(renderBefore uint32) (nextMa
// lastMapBoundaryBefore returns the latest map boundary before the specified
// map index.
func (f *FilterMaps) lastMapBoundaryBefore(mapIndex uint32) (uint32, bool) {
if !f.indexedRange.initialized || f.indexedRange.maps.AfterLast() == 0 {
func (f *FilterMaps) lastMapBoundaryBefore(renderBefore uint32) (uint32, bool) {
if !f.indexedRange.initialized || f.indexedRange.maps.AfterLast() == 0 || renderBefore == 0 {
return 0, false
}
if mapIndex > f.indexedRange.maps.AfterLast() {
mapIndex = f.indexedRange.maps.AfterLast()
afterLastFullMap := f.indexedRange.maps.AfterLast()
if afterLastFullMap > 0 && f.indexedRange.headIndexed {
afterLastFullMap-- // last map is not full
}
if mapIndex > f.indexedRange.maps.First() {
return mapIndex - 1, true
firstRendered := min(renderBefore-1, afterLastFullMap)
if firstRendered == 0 {
return 0, false
}
if mapIndex+f.mapsPerEpoch > f.indexedRange.maps.First() {
if mapIndex > f.indexedRange.maps.First()-f.mapsPerEpoch+f.indexedRange.tailPartialEpoch {
mapIndex = f.indexedRange.maps.First() - f.mapsPerEpoch + f.indexedRange.tailPartialEpoch
if firstRendered >= f.indexedRange.maps.First() {
return firstRendered - 1, true
}
if firstRendered+f.mapsPerEpoch > f.indexedRange.maps.First() {
firstRendered = min(firstRendered, f.indexedRange.maps.First()-f.mapsPerEpoch+f.indexedRange.tailPartialEpoch)
} else {
mapIndex = (mapIndex >> f.logMapsPerEpoch) << f.logMapsPerEpoch
firstRendered = (firstRendered >> f.logMapsPerEpoch) << f.logMapsPerEpoch
}
if mapIndex == 0 {
if firstRendered == 0 {
return 0, false
}
return mapIndex - 1, true
return firstRendered - 1, true
}
// emptyFilterMap returns an empty filter map.

View file

@ -112,6 +112,17 @@ func TestCreation(t *testing.T) {
{123, 2740434112, ID{Hash: checksumToBytes(0xdfbd9bed), Next: 0}}, // Future Prague block
},
},
// Hoodi test cases
{
params.HoodiChainConfig,
core.DefaultHoodiGenesisBlock().ToBlock(),
[]testcase{
{0, 0, ID{Hash: checksumToBytes(0xbef71d30), Next: 1742999832}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople, Petersburg, Istanbul, Berlin, London, Paris, Shanghai, Cancun block
{123, 1742999831, ID{Hash: checksumToBytes(0xbef71d30), Next: 1742999832}}, // Last Cancun block
{123, 1742999832, ID{Hash: checksumToBytes(0x0929e24e), Next: 0}}, // First Prague block
{123, 2740434112, ID{Hash: checksumToBytes(0x0929e24e), Next: 0}}, // Future Prague block
},
},
}
for i, tt := range tests {
for j, ttt := range tt.cases {

View file

@ -221,6 +221,8 @@ func getGenesisState(db ethdb.Database, blockhash common.Hash) (alloc types.Gene
genesis = DefaultSepoliaGenesisBlock()
case params.HoleskyGenesisHash:
genesis = DefaultHoleskyGenesisBlock()
case params.HoodiGenesisHash:
genesis = DefaultHoodiGenesisBlock()
}
if genesis != nil {
return genesis.Alloc, nil
@ -431,6 +433,8 @@ func (g *Genesis) chainConfigOrDefault(ghash common.Hash, stored *params.ChainCo
return params.HoleskyChainConfig
case ghash == params.SepoliaGenesisHash:
return params.SepoliaChainConfig
case ghash == params.HoodiGenesisHash:
return params.HoodiChainConfig
default:
return stored
}
@ -625,6 +629,18 @@ func DefaultHoleskyGenesisBlock() *Genesis {
}
}
// DefaultHoodiGenesisBlock returns the Hoodi network genesis block.
func DefaultHoodiGenesisBlock() *Genesis {
return &Genesis{
Config: params.HoodiChainConfig,
Nonce: 0x1234,
GasLimit: 0x2255100,
Difficulty: big.NewInt(0x01),
Timestamp: 1742212800,
Alloc: decodePrealloc(hoodiAllocData),
}
}
// DeveloperGenesisBlock returns the 'geth --dev' genesis block.
func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis {
// Override the default period to the user requested one

File diff suppressed because one or more lines are too long

View file

@ -104,6 +104,15 @@ func testSetupGenesis(t *testing.T, scheme string) {
},
wantErr: &GenesisMismatchError{Stored: customghash, New: params.SepoliaGenesisHash},
},
{
name: "custom block in DB, genesis == hoodi",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
customg.Commit(db, tdb)
return SetupGenesisBlock(db, tdb, DefaultHoodiGenesisBlock())
},
wantErr: &GenesisMismatchError{Stored: customghash, New: params.HoodiGenesisHash},
},
{
name: "compatible config in DB",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
@ -178,6 +187,8 @@ func TestGenesisHashes(t *testing.T) {
}{
{DefaultGenesisBlock(), params.MainnetGenesisHash},
{DefaultSepoliaGenesisBlock(), params.SepoliaGenesisHash},
{DefaultHoleskyGenesisBlock(), params.HoleskyGenesisHash},
{DefaultHoodiGenesisBlock(), params.HoodiGenesisHash},
} {
// Test via MustCommit
db := rawdb.NewMemoryDatabase()

View file

@ -119,6 +119,7 @@ func TestDeleteBloomBits(t *testing.T) {
for s := uint64(0); s < 2; s++ {
WriteBloomBits(db, i, s, params.MainnetGenesisHash, []byte{0x01, 0x02})
WriteBloomBits(db, i, s, params.SepoliaGenesisHash, []byte{0x01, 0x02})
WriteBloomBits(db, i, s, params.HoodiGenesisHash, []byte{0x01, 0x02})
}
}
check := func(bit uint, section uint64, head common.Hash, exist bool) {
@ -133,24 +134,31 @@ func TestDeleteBloomBits(t *testing.T) {
// Check the existence of written data.
check(0, 0, params.MainnetGenesisHash, true)
check(0, 0, params.SepoliaGenesisHash, true)
check(0, 0, params.HoodiGenesisHash, true)
// Check the existence of deleted data.
DeleteBloombits(db, 0, 0, 1)
check(0, 0, params.MainnetGenesisHash, false)
check(0, 0, params.SepoliaGenesisHash, false)
check(0, 0, params.HoodiGenesisHash, false)
check(0, 1, params.MainnetGenesisHash, true)
check(0, 1, params.SepoliaGenesisHash, true)
check(0, 1, params.HoodiGenesisHash, true)
// Check the existence of deleted data.
DeleteBloombits(db, 0, 0, 2)
check(0, 0, params.MainnetGenesisHash, false)
check(0, 0, params.SepoliaGenesisHash, false)
check(0, 0, params.HoodiGenesisHash, false)
check(0, 1, params.MainnetGenesisHash, false)
check(0, 1, params.SepoliaGenesisHash, false)
check(0, 1, params.HoodiGenesisHash, false)
// Bit1 shouldn't be affect.
check(1, 0, params.MainnetGenesisHash, true)
check(1, 0, params.SepoliaGenesisHash, true)
check(1, 0, params.HoodiGenesisHash, true)
check(1, 1, params.MainnetGenesisHash, true)
check(1, 1, params.SepoliaGenesisHash, true)
check(1, 1, params.HoodiGenesisHash, true)
}

View file

@ -279,7 +279,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
TxIndex: i,
TxHash: tx.Hash(),
}
res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, task.statedb, config)
res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, task.statedb, config, nil)
if err != nil {
task.results[i] = &txTraceResult{TxHash: tx.Hash(), Error: err.Error()}
log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
@ -632,7 +632,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
TxIndex: i,
TxHash: tx.Hash(),
}
res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, statedb, config)
res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, statedb, config, nil)
if err != nil {
return nil, err
}
@ -676,7 +676,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat
// concurrent use.
// See: https://github.com/ethereum/go-ethereum/issues/29114
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
res, err := api.traceTx(ctx, txs[task.index], msg, txctx, blockCtx, task.statedb, config)
res, err := api.traceTx(ctx, txs[task.index], msg, txctx, blockCtx, task.statedb, config, nil)
if err != nil {
results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Error: err.Error()}
continue
@ -894,7 +894,7 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
TxIndex: int(index),
TxHash: hash,
}
return api.traceTx(ctx, tx, msg, txctx, vmctx, statedb, config)
return api.traceTx(ctx, tx, msg, txctx, vmctx, statedb, config, nil)
}
// TraceCall lets you trace a given eth_call. It collects the structured logs
@ -911,6 +911,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
block *types.Block
statedb *state.StateDB
release StateReleaseFunc
precompiles vm.PrecompiledContracts
)
if hash, ok := blockNrOrHash.Hash(); ok {
block, err = api.blockByHash(ctx, hash)
@ -952,7 +953,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
config.BlockOverrides.Apply(&vmctx)
rules := api.backend.ChainConfig().Rules(vmctx.BlockNumber, vmctx.Random != nil, vmctx.Time)
precompiles := vm.ActivePrecompiledContracts(rules)
precompiles = vm.ActivePrecompiledContracts(rules)
if err := config.StateOverrides.Apply(statedb, precompiles); err != nil {
return nil, err
}
@ -977,13 +978,13 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
if config != nil {
traceConfig = &config.TraceConfig
}
return api.traceTx(ctx, tx, msg, new(Context), vmctx, statedb, traceConfig)
return api.traceTx(ctx, tx, msg, new(Context), vmctx, statedb, traceConfig, precompiles)
}
// traceTx configures a new tracer according to the provided configuration, and
// executes the given message in the provided environment. The return value will
// be tracer dependent.
func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig, precompiles vm.PrecompiledContracts) (interface{}, error) {
var (
tracer *Tracer
err error
@ -1009,6 +1010,9 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor
}
tracingStateDB := state.NewHookedState(statedb, tracer.Hooks)
evm := vm.NewEVM(vmctx, tracingStateDB, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true})
if precompiles != nil {
evm.SetPrecompiles(precompiles)
}
// Define a meaningful timeout of a single transaction trace
if config.Timeout != nil {

View file

@ -642,6 +642,7 @@ func TestTracingWithOverrides(t *testing.T) {
t.Parallel()
// Initialize test accounts
accounts := newAccounts(3)
ecRecoverAddress := common.HexToAddress("0x0000000000000000000000000000000000000001")
storageAccount := common.Address{0x13, 37}
genesis := &core.Genesis{
Config: params.TestChainConfig,
@ -940,6 +941,48 @@ func TestTracingWithOverrides(t *testing.T) {
},
want: `{"gas":25288,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000055"}`,
},
{ // Call to precompile ECREC (0x01), but code was modified to add 1 to input
blockNumber: rpc.LatestBlockNumber,
call: ethapi.TransactionArgs{
From: &randomAccounts[0].addr,
To: &ecRecoverAddress,
Data: newRPCBytes(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")),
},
config: &TraceCallConfig{
StateOverrides: &override.StateOverride{
randomAccounts[0].addr: override.OverrideAccount{
Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether))),
},
ecRecoverAddress: override.OverrideAccount{
// The code below adds one to input
Code: newRPCBytes(common.Hex2Bytes("60003560010160005260206000f3")),
MovePrecompileTo: &randomAccounts[2].addr,
},
},
},
want: `{"gas":21167,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000002"}`,
},
{ // Call to ECREC Precompiled on a different address, expect the original behaviour of ECREC precompile
blockNumber: rpc.LatestBlockNumber,
call: ethapi.TransactionArgs{
From: &randomAccounts[0].addr,
To: &randomAccounts[2].addr, // Moved EcRecover
Data: newRPCBytes(common.Hex2Bytes("82f3df49d3645876de6313df2bbe9fbce593f21341a7b03acdb9423bc171fcc9000000000000000000000000000000000000000000000000000000000000001cba13918f50da910f2d55a7ea64cf716ba31dad91856f45908dde900530377d8a112d60f36900d18eb8f9d3b4f85a697b545085614509e3520e4b762e35d0d6bd")),
},
config: &TraceCallConfig{
StateOverrides: &override.StateOverride{
randomAccounts[0].addr: override.OverrideAccount{
Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether))),
},
ecRecoverAddress: override.OverrideAccount{
// The code below adds one to input
Code: newRPCBytes(common.Hex2Bytes("60003560010160005260206000f3")),
MovePrecompileTo: &randomAccounts[2].addr, // Move EcRecover to this address
},
},
},
want: `{"gas":25664,"failed":false,"returnValue":"000000000000000000000000c6e93f4c1920eaeaa1e699f76a7a8c18e3056074"}`,
},
}
for i, tc := range testSuite {
result, err := api.TraceCall(context.Background(), tc.call, rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, tc.config)

View file

@ -640,9 +640,13 @@ func (ec *Client) FeeHistory(ctx context.Context, blockCount uint64, lastBlock *
}
// EstimateGas tries to estimate the gas needed to execute a specific transaction based on
// the current pending state of the backend blockchain. There is no guarantee that this is
// the true gas limit requirement as other transactions may be added or removed by miners,
// but it should provide a basis for setting a reasonable default.
// the current state of the backend blockchain. There is no guarantee that this is the
// true gas limit requirement as other transactions may be added or removed by miners, but
// it should provide a basis for setting a reasonable default.
//
// Note that the state used by this method is implementation-defined by the remote RPC
// server, but it's reasonable to assume that it will either be the pending or latest
// state.
func (ec *Client) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64, error) {
var hex hexutil.Uint64
err := ec.c.CallContext(ctx, &hex, "eth_estimateGas", toCallArg(msg))
@ -652,6 +656,28 @@ func (ec *Client) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64
return uint64(hex), nil
}
// EstimateGasAtBlock is almost the same as EstimateGas except that it selects the block height
// instead of using the remote RPC's default state for gas estimation.
func (ec *Client) EstimateGasAtBlock(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) (uint64, error) {
var hex hexutil.Uint64
err := ec.c.CallContext(ctx, &hex, "eth_estimateGas", toCallArg(msg), toBlockNumArg(blockNumber))
if err != nil {
return 0, err
}
return uint64(hex), nil
}
// EstimateGasAtBlockHash is almost the same as EstimateGas except that it selects the block
// hash instead of using the remote RPC's default state for gas estimation.
func (ec *Client) EstimateGasAtBlockHash(ctx context.Context, msg ethereum.CallMsg, blockHash common.Hash) (uint64, error) {
var hex hexutil.Uint64
err := ec.c.CallContext(ctx, &hex, "eth_estimateGas", toCallArg(msg), rpc.BlockNumberOrHashWithHash(blockHash, false))
if err != nil {
return 0, err
}
return uint64(hex), nil
}
// SendTransaction injects a signed transaction into the pending pool for execution.
//
// If the transaction was a contract creation use the TransactionReceipt method to get the

View file

@ -592,6 +592,33 @@ func testAtFunctions(t *testing.T, client *rpc.Client) {
if !bytes.Equal(code, penCode) {
t.Fatalf("unexpected code: %v %v", code, penCode)
}
// Use HeaderByNumber to get a header for EstimateGasAtBlock and EstimateGasAtBlockHash
latestHeader, err := ec.HeaderByNumber(context.Background(), nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
// EstimateGasAtBlock
msg := ethereum.CallMsg{
From: testAddr,
To: &common.Address{},
Gas: 21000,
Value: big.NewInt(1),
}
gas, err := ec.EstimateGasAtBlock(context.Background(), msg, latestHeader.Number)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if gas != 21000 {
t.Fatalf("unexpected gas limit: %v", gas)
}
// EstimateGasAtBlockHash
gas, err = ec.EstimateGasAtBlockHash(context.Background(), msg, latestHeader.Hash())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if gas != 21000 {
t.Fatalf("unexpected gas limit: %v", gas)
}
}
func testTransactionSender(t *testing.T, client *rpc.Client) {

View file

@ -257,9 +257,13 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
if err := sim.sanitizeCall(&call, sim.state, header, blockContext, &gasUsed); err != nil {
return nil, nil, err
}
tx := call.ToTransaction(types.DynamicFeeTxType)
var (
tx = call.ToTransaction(types.DynamicFeeTxType)
txHash = tx.Hash()
)
txes[i] = tx
tracer.reset(tx.Hash(), uint(i))
tracer.reset(txHash, uint(i))
sim.state.SetTxContext(txHash, i)
// EoA check is always skipped, even in validation mode.
msg := call.ToMessage(header.BaseFee, !sim.validate, true)
result, err := applyMessageWithEVM(ctx, evm, msg, timeout, sim.gp)

View file

@ -28,6 +28,15 @@ var MainnetBootnodes = []string{
"enode://4aeb4ab6c14b23e2c4cfdce879c04b0748a20d8e9b59e25ded2a08143e265c6c25936e74cbc8e641e3312ca288673d91f2f93f8e277de3cfa444ecdaaf982052@157.90.35.166:30303", // bootnode-hetzner-fsn
}
// HoodiBootnodes are the enode URLs of the P2P bootstrap nodes running on the
// Hoodi test network.
var HoodiBootnodes = []string{
// EF DevOps
"enode://2112dd3839dd752813d4df7f40936f06829fc54c0e051a93967c26e5f5d27d99d886b57b4ffcc3c475e930ec9e79c56ef1dbb7d86ca5ee83a9d2ccf36e5c240c@134.209.138.84:30303",
"enode://60203fcb3524e07c5df60a14ae1c9c5b24023ea5d47463dfae051d2c9f3219f309657537576090ca0ae641f73d419f53d8e8000d7a464319d4784acd7d2abc41@209.38.124.160:30303",
"enode://8ae4a48101b2299597341263da0deb47cc38aa4d3ef4b7430b897d49bfa10eb1ccfe1655679b1ed46928ef177fbf21b86837bd724400196c508427a6f41602cd@134.199.184.23:30303",
}
// HoleskyBootnodes are the enode URLs of the P2P bootstrap nodes running on the
// Holesky test network.
var HoleskyBootnodes = []string{
@ -84,6 +93,8 @@ func KnownDNSNetwork(genesis common.Hash, protocol string) string {
net = "sepolia"
case HoleskyGenesisHash:
net = "holesky"
case HoodiGenesisHash:
net = "hoodi"
default:
return ""
}

View file

@ -31,6 +31,7 @@ var (
MainnetGenesisHash = common.HexToHash("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3")
HoleskyGenesisHash = common.HexToHash("0xb5f7f912443c940f21fd611f12828d75b534364ed9e95ca4e307729a4661bde4")
SepoliaGenesisHash = common.HexToHash("0x25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9")
HoodiGenesisHash = common.HexToHash("0xbbe312868b376a3001692a646dd2d7d1e4406380dfd86b98aa8a34d1557c971b")
)
func newUint64(val uint64) *uint64 { return &val }
@ -125,6 +126,36 @@ var (
Prague: DefaultPragueBlobConfig,
},
}
// HoodiChainConfig contains the chain parameters to run a node on the Hoodi test network.
HoodiChainConfig = &ChainConfig{
ChainID: big.NewInt(560048),
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: true,
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
MuirGlacierBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0),
LondonBlock: big.NewInt(0),
ArrowGlacierBlock: nil,
GrayGlacierBlock: nil,
TerminalTotalDifficulty: big.NewInt(0),
MergeNetsplitBlock: big.NewInt(0),
ShanghaiTime: newUint64(0),
CancunTime: newUint64(0),
PragueTime: newUint64(1742999832),
DepositContractAddress: common.HexToAddress("0x00000000219ab540356cBB839Cbe05303d7705Fa"),
Ethash: new(EthashConfig),
BlobScheduleConfig: &BlobScheduleConfig{
Cancun: DefaultCancunBlobConfig,
Prague: DefaultPragueBlobConfig,
},
}
// AllEthashProtocolChanges contains every protocol change (EIPs) introduced
// and accepted by the Ethereum core developers into the Ethash consensus.
AllEthashProtocolChanges = &ChainConfig{
@ -338,6 +369,7 @@ var NetworkNames = map[string]string{
MainnetChainConfig.ChainID.String(): "mainnet",
SepoliaChainConfig.ChainID.String(): "sepolia",
HoleskyChainConfig.ChainID.String(): "holesky",
HoodiChainConfig.ChainID.String(): "hoodi",
}
// ChainConfig is the core config which determines the blockchain settings.