Merge tag 'v1.14.13' into manav/upstream_merge_v1.14.13

This commit is contained in:
Manav Darji 2025-03-24 21:45:55 +05:30
commit 1acf5e6eb0
No known key found for this signature in database
GPG key ID: A426F0124435F36E
386 changed files with 26064 additions and 7627 deletions

24
.gitignore vendored
View file

@ -4,16 +4,11 @@
# or operating system, you probably want to add a global ignore instead: # or operating system, you probably want to add a global ignore instead:
# git config --global core.excludesfile ~/.gitignore_global # git config --global core.excludesfile ~/.gitignore_global
/tmp
*/**/*un~ */**/*un~
*/**/*.test */**/*.test
*un~ *un~
.DS_Store .DS_Store
*/**/.DS_Store */**/.DS_Store
.ethtest
*/**/*tx_database*
*/**/*dapps*
build/_vendor/pkg
cover.out cover.out
@ -48,23 +43,4 @@ profile.cov
# VS Code # VS Code
.vscode .vscode
# dashboard
/dashboard/assets/flow-typed
/dashboard/assets/node_modules
/dashboard/assets/stats.json
/dashboard/assets/bundle.js
/dashboard/assets/bundle.js.map
/dashboard/assets/package-lock.json
**/yarn-error.log
./test
./bor-debug-*
dist
.dccache
*.csv
logs/
tests/spec-tests/ tests/spec-tests/

View file

@ -21,10 +21,14 @@ linters:
- staticcheck - staticcheck
- bidichk - bidichk
- durationcheck - durationcheck
- exportloopref - copyloopvar
- whitespace - whitespace
- revive # only certain checks enabled - revive # only certain checks enabled
- durationcheck
- gocheckcompilerdirectives
- reassign
- mirror
- tenv
### linters we tried and will not be using: ### linters we tried and will not be using:
### ###
# - structcheck # lots of false positives # - structcheck # lots of false positives

View file

@ -25,7 +25,7 @@ jobs:
before_install: before_install:
- export DOCKER_CLI_EXPERIMENTAL=enabled - export DOCKER_CLI_EXPERIMENTAL=enabled
script: script:
- go run build/ci.go dockerx -platform "linux/amd64,linux/arm64" -upload ethereum/client-go - go run build/ci.go dockerx -platform "linux/amd64,linux/arm64,linux/riscv64" -upload ethereum/client-go
# This builder does the Ubuntu PPA upload # This builder does the Ubuntu PPA upload
- stage: build - stage: build

View file

@ -1304,7 +1304,6 @@ func TestUnpackRevert(t *testing.T) {
} }
for index, c := range cases { for index, c := range cases {
index, c := index, c
t.Run(fmt.Sprintf("case %d", index), func(t *testing.T) { t.Run(fmt.Sprintf("case %d", index), func(t *testing.T) {
t.Parallel() t.Parallel()
got, err := UnpackRevert(common.Hex2Bytes(c.input)) got, err := UnpackRevert(common.Hex2Bytes(c.input))

View file

@ -267,7 +267,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
} }
// Parse library references. // Parse library references.
for pattern, name := range libs { for pattern, name := range libs {
matched, err := regexp.Match("__\\$"+pattern+"\\$__", []byte(contracts[types[i]].InputBin)) matched, err := regexp.MatchString("__\\$"+pattern+"\\$__", contracts[types[i]].InputBin)
if err != nil { if err != nil {
log.Error("Could not search for pattern", "pattern", pattern, "contract", contracts[types[i]], "err", err) log.Error("Could not search for pattern", "pattern", pattern, "contract", contracts[types[i]], "err", err)
} }

View file

@ -335,7 +335,6 @@ func TestEventTupleUnpack(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
assert := assert.New(t) assert := assert.New(t)
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
err := unpackTestEventData(tc.dest, tc.data, tc.jsonLog, assert) err := unpackTestEventData(tc.dest, tc.data, tc.jsonLog, assert)
if tc.error == "" { if tc.error == "" {

View file

@ -34,7 +34,6 @@ import (
func TestPack(t *testing.T) { func TestPack(t *testing.T) {
t.Parallel() t.Parallel()
for i, test := range packUnpackTests { for i, test := range packUnpackTests {
i, test := i, test
t.Run(strconv.Itoa(i), func(t *testing.T) { t.Run(strconv.Itoa(i), func(t *testing.T) {
t.Parallel() t.Parallel()
encb, err := hex.DecodeString(test.packed) encb, err := hex.DecodeString(test.packed)

View file

@ -172,7 +172,6 @@ var reflectTests = []reflectTest{
func TestReflectNameToStruct(t *testing.T) { func TestReflectNameToStruct(t *testing.T) {
t.Parallel() t.Parallel()
for _, test := range reflectTests { for _, test := range reflectTests {
test := test
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
t.Parallel() t.Parallel()
m, err := mapArgNamesToStructFields(test.args, reflect.ValueOf(test.struc)) m, err := mapArgNamesToStructFields(test.args, reflect.ValueOf(test.struc))

View file

@ -138,7 +138,6 @@ func TestMakeTopics(t *testing.T) {
}, },
} }
for _, tt := range tests { for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
t.Parallel() t.Parallel()
got, err := MakeTopics(tt.args.query...) got, err := MakeTopics(tt.args.query...)
@ -375,7 +374,6 @@ func TestParseTopics(t *testing.T) {
tests := setupTopicsTests() tests := setupTopicsTests()
for _, tt := range tests { for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
t.Parallel() t.Parallel()
createObj := tt.args.createObj() createObj := tt.args.createObj()
@ -396,7 +394,6 @@ func TestParseTopicsIntoMap(t *testing.T) {
tests := setupTopicsTests() tests := setupTopicsTests()
for _, tt := range tests { for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
t.Parallel() t.Parallel()
outMap := make(map[string]interface{}) outMap := make(map[string]interface{})

View file

@ -409,7 +409,6 @@ func TestMethodMultiReturn(t *testing.T) {
}} }}
for _, tc := range testCases { for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
require := require.New(t) require := require.New(t)
err := abi.UnpackIntoInterface(tc.dest, "multi", data) err := abi.UnpackIntoInterface(tc.dest, "multi", data)

View file

@ -45,8 +45,7 @@ func byURL(a, b accounts.Account) int {
return a.URL.Cmp(b.URL) return a.URL.Cmp(b.URL)
} }
// AmbiguousAddrError is returned when attempting to unlock // AmbiguousAddrError is returned when an address matches multiple files.
// an address for which more than one file exists.
type AmbiguousAddrError struct { type AmbiguousAddrError struct {
Addr common.Address Addr common.Address
Matches []accounts.Account Matches []accounts.Account

View file

@ -1 +0,0 @@
{"address":"f466859ead1932d743d622cb74fc058882e8648a","crypto":{"cipher":"aes-128-ctr","ciphertext":"cb664472deacb41a2e995fa7f96fe29ce744471deb8d146a0e43c7898c9ddd4d","cipherparams":{"iv":"dfd9ee70812add5f4b8f89d0811c9158"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":8,"p":16,"r":8,"salt":"0d6769bf016d45c479213990d6a08d938469c4adad8a02ce507b4a4e7b7739f1"},"mac":"bac9af994b15a45dd39669fc66f9aa8a3b9dd8c22cb16e4d8d7ea089d0f1a1a9"},"id":"472e8b3d-afb6-45b5-8111-72c89895099a","version":3}

View file

@ -1 +0,0 @@
{"address":"f466859ead1932d743d622cb74fc058882e8648a","crypto":{"cipher":"aes-128-ctr","ciphertext":"cb664472deacb41a2e995fa7f96fe29ce744471deb8d146a0e43c7898c9ddd4d","cipherparams":{"iv":"dfd9ee70812add5f4b8f89d0811c9158"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":8,"p":16,"r":8,"salt":"0d6769bf016d45c479213990d6a08d938469c4adad8a02ce507b4a4e7b7739f1"},"mac":"bac9af994b15a45dd39669fc66f9aa8a3b9dd8c22cb16e4d8d7ea089d0f1a1a9"},"id":"472e8b3d-afb6-45b5-8111-72c89895099a","version":3}

View file

@ -1 +0,0 @@
{"address":"7ef5a6135f1fd6a02593eedc869c6d41d934aef8","crypto":{"cipher":"aes-128-ctr","ciphertext":"1d0839166e7a15b9c1333fc865d69858b22df26815ccf601b28219b6192974e1","cipherparams":{"iv":"8df6caa7ff1b00c4e871f002cb7921ed"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":8,"p":16,"r":8,"salt":"e5e6ef3f4ea695f496b643ebd3f75c0aa58ef4070e90c80c5d3fb0241bf1595c"},"mac":"6d16dfde774845e4585357f24bce530528bc69f4f84e1e22880d34fa45c273e5"},"id":"950077c7-71e3-4c44-a4a1-143919141ed4","version":3}

View file

@ -29,12 +29,9 @@ import (
// the manager will buffer in its channel. // the manager will buffer in its channel.
const managerSubBufferSize = 50 const managerSubBufferSize = 50
// Config contains the settings of the global account manager. // Config is a legacy struct which is not used
//
// TODO(rjl493456442, karalabe, holiman): Get rid of this when account management
// is removed in favor of Clef.
type Config struct { type Config struct {
InsecureUnlockAllowed bool // Whether account unlocking in insecure environment is allowed InsecureUnlockAllowed bool // Unused legacy-parameter
} }
// newBackendEvent lets the manager know it should // newBackendEvent lets the manager know it should
@ -47,7 +44,6 @@ type newBackendEvent struct {
// Manager is an overarching account manager that can communicate with various // Manager is an overarching account manager that can communicate with various
// backends for signing transactions. // backends for signing transactions.
type Manager struct { type Manager struct {
config *Config // Global account manager configurations
backends map[reflect.Type][]Backend // Index of backends currently registered backends map[reflect.Type][]Backend // Index of backends currently registered
updaters []event.Subscription // Wallet update subscriptions for all backends updaters []event.Subscription // Wallet update subscriptions for all backends
updates chan WalletEvent // Subscription sink for backend wallet changes updates chan WalletEvent // Subscription sink for backend wallet changes
@ -78,7 +74,6 @@ func NewManager(config *Config, backends ...Backend) *Manager {
} }
// Assemble the account manager and return // Assemble the account manager and return
am := &Manager{ am := &Manager{
config: config,
backends: make(map[reflect.Type][]Backend), backends: make(map[reflect.Type][]Backend),
updaters: subs, updaters: subs,
updates: updates, updates: updates,
@ -109,11 +104,6 @@ func (am *Manager) Close() error {
return <-errc return <-errc
} }
// Config returns the configuration of account manager.
func (am *Manager) Config() *Config {
return am.config
}
// AddBackend starts the tracking of an additional backend for wallet updates. // AddBackend starts the tracking of an additional backend for wallet updates.
// cmd/geth assumes once this func returns the backends have been already integrated. // cmd/geth assumes once this func returns the backends have been already integrated.
func (am *Manager) AddBackend(backend Backend) { func (am *Manager) AddBackend(backend Backend) {

View file

@ -353,8 +353,22 @@ func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction
return common.Address{}, nil, err return common.Address{}, nil, err
} }
} else { } else {
if txrlp, err = rlp.EncodeToBytes([]interface{}{tx.Nonce(), tx.GasPrice(), tx.Gas(), tx.To(), tx.Value(), tx.Data(), chainID, big.NewInt(0), big.NewInt(0)}); err != nil { if tx.Type() == types.DynamicFeeTxType {
return common.Address{}, nil, err if txrlp, err = rlp.EncodeToBytes([]interface{}{chainID, tx.Nonce(), tx.GasTipCap(), tx.GasFeeCap(), tx.Gas(), tx.To(), tx.Value(), tx.Data(), tx.AccessList()}); err != nil {
return common.Address{}, nil, err
}
// append type to transaction
txrlp = append([]byte{tx.Type()}, txrlp...)
} else if tx.Type() == types.AccessListTxType {
if txrlp, err = rlp.EncodeToBytes([]interface{}{chainID, tx.Nonce(), tx.GasPrice(), tx.Gas(), tx.To(), tx.Value(), tx.Data(), tx.AccessList()}); err != nil {
return common.Address{}, nil, err
}
// append type to transaction
txrlp = append([]byte{tx.Type()}, txrlp...)
} else if tx.Type() == types.LegacyTxType {
if txrlp, err = rlp.EncodeToBytes([]interface{}{tx.Nonce(), tx.GasPrice(), tx.Gas(), tx.To(), tx.Value(), tx.Data(), chainID, big.NewInt(0), big.NewInt(0)}); err != nil {
return common.Address{}, nil, err
}
} }
} }
@ -369,7 +383,9 @@ func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction
// Chunk size selection to mitigate an underlying RLP deserialization issue on the ledger app. // Chunk size selection to mitigate an underlying RLP deserialization issue on the ledger app.
// https://github.com/LedgerHQ/app-ethereum/issues/409 // https://github.com/LedgerHQ/app-ethereum/issues/409
chunk := 255 chunk := 255
for ; len(payload)%chunk <= ledgerEip155Size; chunk-- { if tx.Type() == types.LegacyTxType {
for ; len(payload)%chunk <= ledgerEip155Size; chunk-- {
}
} }
for len(payload) > 0 { for len(payload) > 0 {
@ -398,8 +414,11 @@ func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction
if chainID == nil { if chainID == nil {
signer = new(types.HomesteadSigner) signer = new(types.HomesteadSigner)
} else { } else {
signer = types.NewEIP155Signer(chainID) signer = types.LatestSignerForChainID(chainID)
signature[64] -= byte(chainID.Uint64()*2 + 35) // For non-legacy transactions, V is 0 or 1, no need to subtract here.
if tx.Type() == types.LegacyTxType {
signature[64] -= byte(chainID.Uint64()*2 + 35)
}
} }
signed, err := tx.WithSignature(signer, signature) signed, err := tx.WithSignature(signer, signature)

View file

@ -24,7 +24,9 @@ for:
- image: Ubuntu - image: Ubuntu
build_script: build_script:
- go run build/ci.go lint - go run build/ci.go lint
- go run build/ci.go generate -verify - go run build/ci.go check_tidy
- go run build/ci.go check_generate
- go run build/ci.go check_baddeps
- go run build/ci.go install -dlgo - go run build/ci.go install -dlgo
test_script: test_script:
- go run build/ci.go test -dlgo -short - go run build/ci.go test -dlgo -short

View file

@ -17,25 +17,22 @@
package blsync package blsync
import ( import (
"strings"
"github.com/ethereum/go-ethereum/beacon/light" "github.com/ethereum/go-ethereum/beacon/light"
"github.com/ethereum/go-ethereum/beacon/light/api" "github.com/ethereum/go-ethereum/beacon/light/api"
"github.com/ethereum/go-ethereum/beacon/light/request" "github.com/ethereum/go-ethereum/beacon/light/request"
"github.com/ethereum/go-ethereum/beacon/light/sync" "github.com/ethereum/go-ethereum/beacon/light/sync"
"github.com/ethereum/go-ethereum/beacon/params"
"github.com/ethereum/go-ethereum/beacon/types" "github.com/ethereum/go-ethereum/beacon/types"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/ethdb/memorydb"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/urfave/cli/v2"
) )
type Client struct { type Client struct {
urls []string urls []string
customHeader map[string]string customHeader map[string]string
chainConfig *lightClientConfig config *params.ClientConfig
scheduler *request.Scheduler scheduler *request.Scheduler
blockSync *beaconBlockSync blockSync *beaconBlockSync
engineRPC *rpc.Client engineRPC *rpc.Client
@ -44,34 +41,18 @@ type Client struct {
engineClient *engineClient engineClient *engineClient
} }
func NewClient(ctx *cli.Context) *Client { func NewClient(config params.ClientConfig) *Client {
if !ctx.IsSet(utils.BeaconApiFlag.Name) {
utils.Fatalf("Beacon node light client API URL not specified")
}
var (
chainConfig = makeChainConfig(ctx)
customHeader = make(map[string]string)
)
for _, s := range ctx.StringSlice(utils.BeaconApiHeaderFlag.Name) {
kv := strings.Split(s, ":")
if len(kv) != 2 {
utils.Fatalf("Invalid custom API header entry: %s", s)
}
customHeader[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1])
}
// create data structures // create data structures
var ( var (
db = memorydb.New() db = memorydb.New()
threshold = ctx.Int(utils.BeaconThresholdFlag.Name) committeeChain = light.NewCommitteeChain(db, &config.ChainConfig, config.Threshold, !config.NoFilter)
committeeChain = light.NewCommitteeChain(db, chainConfig.ChainConfig, threshold, !ctx.Bool(utils.BeaconNoFilterFlag.Name)) headTracker = light.NewHeadTracker(committeeChain, config.Threshold)
headTracker = light.NewHeadTracker(committeeChain, threshold)
) )
headSync := sync.NewHeadSync(headTracker, committeeChain) headSync := sync.NewHeadSync(headTracker, committeeChain)
// set up scheduler and sync modules // set up scheduler and sync modules
scheduler := request.NewScheduler() scheduler := request.NewScheduler()
checkpointInit := sync.NewCheckpointInit(committeeChain, chainConfig.Checkpoint) checkpointInit := sync.NewCheckpointInit(committeeChain, config.Checkpoint)
forwardSync := sync.NewForwardUpdateSync(committeeChain) forwardSync := sync.NewForwardUpdateSync(committeeChain)
beaconBlockSync := newBeaconBlockSync(headTracker) beaconBlockSync := newBeaconBlockSync(headTracker)
scheduler.RegisterTarget(headTracker) scheduler.RegisterTarget(headTracker)
@ -83,9 +64,9 @@ func NewClient(ctx *cli.Context) *Client {
return &Client{ return &Client{
scheduler: scheduler, scheduler: scheduler,
urls: ctx.StringSlice(utils.BeaconApiFlag.Name), urls: config.Apis,
customHeader: customHeader, customHeader: config.CustomHeader,
chainConfig: &chainConfig, config: &config,
blockSync: beaconBlockSync, blockSync: beaconBlockSync,
} }
} }
@ -97,7 +78,7 @@ func (c *Client) SetEngineRPC(engine *rpc.Client) {
func (c *Client) Start() error { func (c *Client) Start() error {
headCh := make(chan types.ChainHeadEvent, 16) headCh := make(chan types.ChainHeadEvent, 16)
c.chainHeadSub = c.blockSync.SubscribeChainHead(headCh) c.chainHeadSub = c.blockSync.SubscribeChainHead(headCh)
c.engineClient = startEngineClient(c.chainConfig, c.engineRPC, headCh) c.engineClient = startEngineClient(c.config, c.engineRPC, headCh)
c.scheduler.Start() c.scheduler.Start()
for _, url := range c.urls { for _, url := range c.urls {

View file

@ -1,114 +0,0 @@
// Copyright 2022 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package blsync
import (
"github.com/ethereum/go-ethereum/beacon/types"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/urfave/cli/v2"
)
// lightClientConfig contains beacon light client configuration
type lightClientConfig struct {
*types.ChainConfig
Checkpoint common.Hash
}
var (
MainnetConfig = lightClientConfig{
ChainConfig: (&types.ChainConfig{
GenesisValidatorsRoot: common.HexToHash("0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95"),
GenesisTime: 1606824023,
}).
AddFork("GENESIS", 0, []byte{0, 0, 0, 0}).
AddFork("ALTAIR", 74240, []byte{1, 0, 0, 0}).
AddFork("BELLATRIX", 144896, []byte{2, 0, 0, 0}).
AddFork("CAPELLA", 194048, []byte{3, 0, 0, 0}).
AddFork("DENEB", 269568, []byte{4, 0, 0, 0}),
Checkpoint: common.HexToHash("0x388be41594ec7d6a6894f18c73f3469f07e2c19a803de4755d335817ed8e2e5a"),
}
SepoliaConfig = lightClientConfig{
ChainConfig: (&types.ChainConfig{
GenesisValidatorsRoot: common.HexToHash("0xd8ea171f3c94aea21ebc42a1ed61052acf3f9209c00e4efbaaddac09ed9b8078"),
GenesisTime: 1655733600,
}).
AddFork("GENESIS", 0, []byte{144, 0, 0, 105}).
AddFork("ALTAIR", 50, []byte{144, 0, 0, 112}).
AddFork("BELLATRIX", 100, []byte{144, 0, 0, 113}).
AddFork("CAPELLA", 56832, []byte{144, 0, 0, 114}).
AddFork("DENEB", 132608, []byte{144, 0, 0, 115}),
Checkpoint: common.HexToHash("0x1005a6d9175e96bfbce4d35b80f468e9bff0b674e1e861d16e09e10005a58e81"),
}
)
func makeChainConfig(ctx *cli.Context) lightClientConfig {
var config lightClientConfig
customConfig := ctx.IsSet(utils.BeaconConfigFlag.Name)
utils.CheckExclusive(ctx, utils.MainnetFlag, utils.SepoliaFlag, utils.BeaconConfigFlag)
switch {
case ctx.Bool(utils.MainnetFlag.Name):
config = MainnetConfig
case ctx.Bool(utils.SepoliaFlag.Name):
config = SepoliaConfig
default:
if !customConfig {
config = MainnetConfig
}
}
// Genesis root and time should always be specified together with custom chain config
if customConfig {
if !ctx.IsSet(utils.BeaconGenesisRootFlag.Name) {
utils.Fatalf("Custom beacon chain config is specified but genesis root is missing")
}
if !ctx.IsSet(utils.BeaconGenesisTimeFlag.Name) {
utils.Fatalf("Custom beacon chain config is specified but genesis time is missing")
}
if !ctx.IsSet(utils.BeaconCheckpointFlag.Name) {
utils.Fatalf("Custom beacon chain config is specified but checkpoint is missing")
}
config.ChainConfig = &types.ChainConfig{
GenesisTime: ctx.Uint64(utils.BeaconGenesisTimeFlag.Name),
}
if c, err := hexutil.Decode(ctx.String(utils.BeaconGenesisRootFlag.Name)); err == nil && len(c) <= 32 {
copy(config.GenesisValidatorsRoot[:len(c)], c)
} else {
utils.Fatalf("Invalid hex string", "beacon.genesis.gvroot", ctx.String(utils.BeaconGenesisRootFlag.Name), "error", err)
}
if err := config.ChainConfig.LoadForks(ctx.String(utils.BeaconConfigFlag.Name)); err != nil {
utils.Fatalf("Could not load beacon chain config file", "file name", ctx.String(utils.BeaconConfigFlag.Name), "error", err)
}
} else {
if ctx.IsSet(utils.BeaconGenesisRootFlag.Name) {
utils.Fatalf("Genesis root is specified but custom beacon chain config is missing")
}
if ctx.IsSet(utils.BeaconGenesisTimeFlag.Name) {
utils.Fatalf("Genesis time is specified but custom beacon chain config is missing")
}
}
// Checkpoint is required with custom chain config and is optional with pre-defined config
if ctx.IsSet(utils.BeaconCheckpointFlag.Name) {
if c, err := hexutil.Decode(ctx.String(utils.BeaconCheckpointFlag.Name)); err == nil && len(c) <= 32 {
copy(config.Checkpoint[:len(c)], c)
} else {
utils.Fatalf("Invalid hex string", "beacon.checkpoint", ctx.String(utils.BeaconCheckpointFlag.Name), "error", err)
}
}
return config
}

View file

@ -23,6 +23,7 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/beacon/engine"
"github.com/ethereum/go-ethereum/beacon/params"
"github.com/ethereum/go-ethereum/beacon/types" "github.com/ethereum/go-ethereum/beacon/types"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
ctypes "github.com/ethereum/go-ethereum/core/types" ctypes "github.com/ethereum/go-ethereum/core/types"
@ -31,14 +32,14 @@ import (
) )
type engineClient struct { type engineClient struct {
config *lightClientConfig config *params.ClientConfig
rpc *rpc.Client rpc *rpc.Client
rootCtx context.Context rootCtx context.Context
cancelRoot context.CancelFunc cancelRoot context.CancelFunc
wg sync.WaitGroup wg sync.WaitGroup
} }
func startEngineClient(config *lightClientConfig, rpc *rpc.Client, headCh <-chan types.ChainHeadEvent) *engineClient { func startEngineClient(config *params.ClientConfig, rpc *rpc.Client, headCh <-chan types.ChainHeadEvent) *engineClient {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
ec := &engineClient{ ec := &engineClient{
config: config, config: config,
@ -92,7 +93,7 @@ func (ec *engineClient) updateLoop(headCh <-chan types.ChainHeadEvent) {
} }
func (ec *engineClient) callNewPayload(fork string, event types.ChainHeadEvent) (string, error) { func (ec *engineClient) callNewPayload(fork string, event types.ChainHeadEvent) (string, error) {
execData := engine.BlockToExecutableData(event.Block, nil, nil).ExecutionPayload execData := engine.BlockToExecutableData(event.Block, nil, nil, nil).ExecutionPayload
var ( var (
method string method string

View file

@ -34,7 +34,6 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
Withdrawals []*types.Withdrawal `json:"withdrawals"` Withdrawals []*types.Withdrawal `json:"withdrawals"`
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
Deposits types.Deposits `json:"depositRequests"`
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"` ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
} }
@ -63,7 +62,6 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
enc.Withdrawals = e.Withdrawals enc.Withdrawals = e.Withdrawals
enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed) enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed)
enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas) enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas)
enc.Deposits = e.Deposits
enc.ExecutionWitness = e.ExecutionWitness enc.ExecutionWitness = e.ExecutionWitness
return json.Marshal(&enc) return json.Marshal(&enc)
} }
@ -88,7 +86,6 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error {
Withdrawals []*types.Withdrawal `json:"withdrawals"` Withdrawals []*types.Withdrawal `json:"withdrawals"`
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
Deposits *types.Deposits `json:"depositRequests"`
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"` ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
} }
@ -193,9 +190,6 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error {
if dec.ExcessBlobGas != nil { if dec.ExcessBlobGas != nil {
e.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas) e.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas)
} }
if dec.Deposits != nil {
e.Deposits = *dec.Deposits
}
if dec.ExecutionWitness != nil { if dec.ExecutionWitness != nil {
e.ExecutionWitness = dec.ExecutionWitness e.ExecutionWitness = dec.ExecutionWitness
} }

View file

@ -18,14 +18,21 @@ func (e ExecutionPayloadEnvelope) MarshalJSON() ([]byte, error) {
ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"` ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"`
BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"` BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"`
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"` BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
Requests []hexutil.Bytes `json:"executionRequests"`
Override bool `json:"shouldOverrideBuilder"` Override bool `json:"shouldOverrideBuilder"`
Witness *hexutil.Bytes `json:"witness"` Witness *hexutil.Bytes `json:"witness,omitempty"`
} }
var enc ExecutionPayloadEnvelope var enc ExecutionPayloadEnvelope
enc.ExecutionPayload = e.ExecutionPayload enc.ExecutionPayload = e.ExecutionPayload
enc.BlockValue = (*hexutil.Big)(e.BlockValue) enc.BlockValue = (*hexutil.Big)(e.BlockValue)
enc.BlobsBundle = e.BlobsBundle enc.BlobsBundle = e.BlobsBundle
if e.Requests != nil {
enc.Requests = make([]hexutil.Bytes, len(e.Requests))
for k, v := range e.Requests {
enc.Requests[k] = v
}
}
enc.Override = e.Override enc.Override = e.Override
enc.Witness = e.Witness enc.Witness = e.Witness
return json.Marshal(&enc) return json.Marshal(&enc)
@ -37,8 +44,9 @@ func (e *ExecutionPayloadEnvelope) UnmarshalJSON(input []byte) error {
ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"` ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"`
BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"` BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"`
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"` BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
Requests []hexutil.Bytes `json:"executionRequests"`
Override *bool `json:"shouldOverrideBuilder"` Override *bool `json:"shouldOverrideBuilder"`
Witness *hexutil.Bytes `json:"witness"` Witness *hexutil.Bytes `json:"witness,omitempty"`
} }
var dec ExecutionPayloadEnvelope var dec ExecutionPayloadEnvelope
@ -60,6 +68,12 @@ func (e *ExecutionPayloadEnvelope) UnmarshalJSON(input []byte) error {
if dec.BlobsBundle != nil { if dec.BlobsBundle != nil {
e.BlobsBundle = dec.BlobsBundle e.BlobsBundle = dec.BlobsBundle
} }
if dec.Requests != nil {
e.Requests = make([][]byte, len(dec.Requests))
for k, v := range dec.Requests {
e.Requests[k] = v
}
}
if dec.Override != nil { if dec.Override != nil {
e.Override = *dec.Override e.Override = *dec.Override
} }

View file

@ -76,7 +76,6 @@ type ExecutableData struct {
Withdrawals []*types.Withdrawal `json:"withdrawals"` Withdrawals []*types.Withdrawal `json:"withdrawals"`
BlobGasUsed *uint64 `json:"blobGasUsed"` BlobGasUsed *uint64 `json:"blobGasUsed"`
ExcessBlobGas *uint64 `json:"excessBlobGas"` ExcessBlobGas *uint64 `json:"excessBlobGas"`
Deposits types.Deposits `json:"depositRequests"`
ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"` ExecutionWitness *types.ExecutionWitness `json:"executionWitness,omitempty"`
} }
@ -108,8 +107,9 @@ type ExecutionPayloadEnvelope struct {
ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"` ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"`
BlockValue *big.Int `json:"blockValue" gencodec:"required"` BlockValue *big.Int `json:"blockValue" gencodec:"required"`
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"` BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
Requests [][]byte `json:"executionRequests"`
Override bool `json:"shouldOverrideBuilder"` Override bool `json:"shouldOverrideBuilder"`
Witness *hexutil.Bytes `json:"witness"` Witness *hexutil.Bytes `json:"witness,omitempty"`
} }
type BlobsBundleV1 struct { type BlobsBundleV1 struct {
@ -118,9 +118,15 @@ type BlobsBundleV1 struct {
Blobs []hexutil.Bytes `json:"blobs"` Blobs []hexutil.Bytes `json:"blobs"`
} }
type BlobAndProofV1 struct {
Blob hexutil.Bytes `json:"blob"`
Proof hexutil.Bytes `json:"proof"`
}
// JSON type overrides for ExecutionPayloadEnvelope. // JSON type overrides for ExecutionPayloadEnvelope.
type executionPayloadEnvelopeMarshaling struct { type executionPayloadEnvelopeMarshaling struct {
BlockValue *hexutil.Big BlockValue *hexutil.Big
Requests []hexutil.Bytes
} }
type PayloadStatusV1 struct { type PayloadStatusV1 struct {
@ -212,8 +218,8 @@ func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
// and that the blockhash of the constructed block matches the parameters. Nil // and that the blockhash of the constructed block matches the parameters. Nil
// Withdrawals value will propagate through the returned block. Empty // Withdrawals value will propagate through the returned block. Empty
// Withdrawals value must be passed via non-nil, length 0 value in data. // Withdrawals value must be passed via non-nil, length 0 value in data.
func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (*types.Block, error) { func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte) (*types.Block, error) {
block, err := ExecutableDataToBlockNoHash(data, versionedHashes, beaconRoot) block, err := ExecutableDataToBlockNoHash(data, versionedHashes, beaconRoot, requests)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -226,7 +232,7 @@ func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, b
// ExecutableDataToBlockNoHash is analogous to ExecutableDataToBlock, but is used // ExecutableDataToBlockNoHash is analogous to ExecutableDataToBlock, but is used
// for stateless execution, so it skips checking if the executable data hashes to // for stateless execution, so it skips checking if the executable data hashes to
// the requested hash (stateless has to *compute* the root hash, it's not given). // the requested hash (stateless has to *compute* the root hash, it's not given).
func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (*types.Block, error) { func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte) (*types.Block, error) {
txs, err := decodeTransactions(data.Transactions) txs, err := decodeTransactions(data.Transactions)
if err != nil { if err != nil {
return nil, err return nil, err
@ -261,19 +267,21 @@ func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.H
h := types.DeriveSha(types.Withdrawals(data.Withdrawals), trie.NewStackTrie(nil)) h := types.DeriveSha(types.Withdrawals(data.Withdrawals), trie.NewStackTrie(nil))
withdrawalsRoot = &h withdrawalsRoot = &h
} }
// Compute requestsHash if any requests are non-nil.
var ( var requestsHash *common.Hash
requestsHash *common.Hash if requests != nil {
requests types.Requests // Put back request type byte.
) typedRequests := make([][]byte, len(requests))
if data.Deposits != nil { for i, reqdata := range requests {
requests = make(types.Requests, 0) typedReqdata := make([]byte, len(reqdata)+1)
for _, d := range data.Deposits { typedReqdata[0] = byte(i)
requests = append(requests, types.NewRequest(d)) copy(typedReqdata[1:], reqdata)
typedRequests[i] = typedReqdata
} }
h := types.DeriveSha(requests, trie.NewStackTrie(nil)) h := types.CalcRequestsHash(typedRequests)
requestsHash = &h requestsHash = &h
} }
header := &types.Header{ header := &types.Header{
ParentHash: data.ParentHash, ParentHash: data.ParentHash,
UncleHash: types.EmptyUncleHash, UncleHash: types.EmptyUncleHash,
@ -297,14 +305,14 @@ func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.H
RequestsHash: requestsHash, RequestsHash: requestsHash,
} }
return types.NewBlockWithHeader(header). return types.NewBlockWithHeader(header).
WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals, Requests: requests}). WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals}).
WithWitness(data.ExecutionWitness), WithWitness(data.ExecutionWitness),
nil nil
} }
// BlockToExecutableData constructs the ExecutableData structure by filling the // BlockToExecutableData constructs the ExecutableData structure by filling the
// fields from the given block. It assumes the given block is post-merge block. // fields from the given block. It assumes the given block is post-merge block.
func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.BlobTxSidecar) *ExecutionPayloadEnvelope { func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.BlobTxSidecar, requests [][]byte) *ExecutionPayloadEnvelope {
data := &ExecutableData{ data := &ExecutableData{
BlockHash: block.Hash(), BlockHash: block.Hash(),
ParentHash: block.ParentHash(), ParentHash: block.ParentHash(),
@ -325,6 +333,8 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.
ExcessBlobGas: block.ExcessBlobGas(), ExcessBlobGas: block.ExcessBlobGas(),
ExecutionWitness: block.ExecutionWitness(), ExecutionWitness: block.ExecutionWitness(),
} }
// Add blobs.
bundle := BlobsBundleV1{ bundle := BlobsBundleV1{
Commitments: make([]hexutil.Bytes, 0), Commitments: make([]hexutil.Bytes, 0),
Blobs: make([]hexutil.Bytes, 0), Blobs: make([]hexutil.Bytes, 0),
@ -337,30 +347,29 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.
bundle.Proofs = append(bundle.Proofs, hexutil.Bytes(sidecar.Proofs[j][:])) bundle.Proofs = append(bundle.Proofs, hexutil.Bytes(sidecar.Proofs[j][:]))
} }
} }
setRequests(block.Requests(), data)
return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees, BlobsBundle: &bundle, Override: false}
}
// setRequests differentiates the different request types and // Remove type byte in requests.
// assigns them to the associated fields in ExecutableData. var plainRequests [][]byte
func setRequests(requests types.Requests, data *ExecutableData) {
if requests != nil { if requests != nil {
// If requests is non-nil, it means deposits are available in block and we plainRequests = make([][]byte, len(requests))
// should return an empty slice instead of nil if there are no deposits. for i, reqdata := range requests {
data.Deposits = make(types.Deposits, 0) plainRequests[i] = reqdata[1:]
}
for _, r := range requests {
if d, ok := r.Inner().(*types.Deposit); ok {
data.Deposits = append(data.Deposits, d)
} }
} }
return &ExecutionPayloadEnvelope{
ExecutionPayload: data,
BlockValue: fees,
BlobsBundle: &bundle,
Requests: plainRequests,
Override: false,
}
} }
// ExecutionPayloadBody is used in the response to GetPayloadBodiesByHash and GetPayloadBodiesByRange // ExecutionPayloadBody is used in the response to GetPayloadBodiesByHash and GetPayloadBodiesByRange
type ExecutionPayloadBody struct { type ExecutionPayloadBody struct {
TransactionData []hexutil.Bytes `json:"transactions"` TransactionData []hexutil.Bytes `json:"transactions"`
Withdrawals []*types.Withdrawal `json:"withdrawals"` Withdrawals []*types.Withdrawal `json:"withdrawals"`
Deposits types.Deposits `json:"depositRequests"`
} }
// Client identifiers to support ClientVersionV1. // Client identifiers to support ClientVersionV1.

View file

@ -76,34 +76,32 @@ type CommitteeChain struct {
unixNano func() int64 // system clock (simulated clock in tests) unixNano func() int64 // system clock (simulated clock in tests)
sigVerifier committeeSigVerifier // BLS sig verifier (dummy verifier in tests) sigVerifier committeeSigVerifier // BLS sig verifier (dummy verifier in tests)
config *types.ChainConfig config *params.ChainConfig
signerThreshold int
minimumUpdateScore types.UpdateScore minimumUpdateScore types.UpdateScore
enforceTime bool // enforceTime specifies whether the age of a signed header should be checked enforceTime bool // enforceTime specifies whether the age of a signed header should be checked
} }
// NewCommitteeChain creates a new CommitteeChain. // NewCommitteeChain creates a new CommitteeChain.
func NewCommitteeChain(db ethdb.KeyValueStore, config *types.ChainConfig, signerThreshold int, enforceTime bool) *CommitteeChain { func NewCommitteeChain(db ethdb.KeyValueStore, config *params.ChainConfig, signerThreshold int, enforceTime bool) *CommitteeChain {
return newCommitteeChain(db, config, signerThreshold, enforceTime, blsVerifier{}, &mclock.System{}, func() int64 { return time.Now().UnixNano() }) return newCommitteeChain(db, config, signerThreshold, enforceTime, blsVerifier{}, &mclock.System{}, func() int64 { return time.Now().UnixNano() })
} }
// NewTestCommitteeChain creates a new CommitteeChain for testing. // NewTestCommitteeChain creates a new CommitteeChain for testing.
func NewTestCommitteeChain(db ethdb.KeyValueStore, config *types.ChainConfig, signerThreshold int, enforceTime bool, clock *mclock.Simulated) *CommitteeChain { func NewTestCommitteeChain(db ethdb.KeyValueStore, config *params.ChainConfig, signerThreshold int, enforceTime bool, clock *mclock.Simulated) *CommitteeChain {
return newCommitteeChain(db, config, signerThreshold, enforceTime, dummyVerifier{}, clock, func() int64 { return int64(clock.Now()) }) return newCommitteeChain(db, config, signerThreshold, enforceTime, dummyVerifier{}, clock, func() int64 { return int64(clock.Now()) })
} }
// newCommitteeChain creates a new CommitteeChain with the option of replacing the // newCommitteeChain creates a new CommitteeChain with the option of replacing the
// clock source and signature verification for testing purposes. // clock source and signature verification for testing purposes.
func newCommitteeChain(db ethdb.KeyValueStore, config *types.ChainConfig, signerThreshold int, enforceTime bool, sigVerifier committeeSigVerifier, clock mclock.Clock, unixNano func() int64) *CommitteeChain { func newCommitteeChain(db ethdb.KeyValueStore, config *params.ChainConfig, signerThreshold int, enforceTime bool, sigVerifier committeeSigVerifier, clock mclock.Clock, unixNano func() int64) *CommitteeChain {
s := &CommitteeChain{ s := &CommitteeChain{
committeeCache: lru.NewCache[uint64, syncCommittee](10), committeeCache: lru.NewCache[uint64, syncCommittee](10),
db: db, db: db,
sigVerifier: sigVerifier, sigVerifier: sigVerifier,
clock: clock, clock: clock,
unixNano: unixNano, unixNano: unixNano,
config: config, config: config,
signerThreshold: signerThreshold, enforceTime: enforceTime,
enforceTime: enforceTime,
minimumUpdateScore: types.UpdateScore{ minimumUpdateScore: types.UpdateScore{
SignerCount: uint32(signerThreshold), SignerCount: uint32(signerThreshold),
SubPeriodIndex: params.SyncPeriodLength / 16, SubPeriodIndex: params.SyncPeriodLength / 16,
@ -507,7 +505,7 @@ func (s *CommitteeChain) verifySignedHeader(head types.SignedHeader) (bool, time
if committee == nil { if committee == nil {
return false, age, nil return false, age, nil
} }
if signingRoot, err := s.config.Forks.SigningRoot(head.Header); err == nil { if signingRoot, err := s.config.Forks.SigningRoot(head.Header.Epoch(), head.Header.Hash()); err == nil {
return s.sigVerifier.verifySignature(committee, signingRoot, &head.Signature), age, nil return s.sigVerifier.verifySignature(committee, signingRoot, &head.Signature), age, nil
} }
return false, age, nil return false, age, nil

View file

@ -31,15 +31,15 @@ var (
testGenesis = newTestGenesis() testGenesis = newTestGenesis()
testGenesis2 = newTestGenesis() testGenesis2 = newTestGenesis()
tfBase = newTestForks(testGenesis, types.Forks{ tfBase = newTestForks(testGenesis, params.Forks{
&types.Fork{Epoch: 0, Version: []byte{0}}, &params.Fork{Epoch: 0, Version: []byte{0}},
}) })
tfAlternative = newTestForks(testGenesis, types.Forks{ tfAlternative = newTestForks(testGenesis, params.Forks{
&types.Fork{Epoch: 0, Version: []byte{0}}, &params.Fork{Epoch: 0, Version: []byte{0}},
&types.Fork{Epoch: 0x700, Version: []byte{1}}, &params.Fork{Epoch: 0x700, Version: []byte{1}},
}) })
tfAnotherGenesis = newTestForks(testGenesis2, types.Forks{ tfAnotherGenesis = newTestForks(testGenesis2, params.Forks{
&types.Fork{Epoch: 0, Version: []byte{0}}, &params.Fork{Epoch: 0, Version: []byte{0}},
}) })
tcBase = newTestCommitteeChain(nil, tfBase, true, 0, 10, 400, false) tcBase = newTestCommitteeChain(nil, tfBase, true, 0, 10, 400, false)
@ -226,13 +226,13 @@ type committeeChainTest struct {
t *testing.T t *testing.T
db *memorydb.Database db *memorydb.Database
clock *mclock.Simulated clock *mclock.Simulated
config types.ChainConfig config params.ChainConfig
signerThreshold int signerThreshold int
enforceTime bool enforceTime bool
chain *CommitteeChain chain *CommitteeChain
} }
func newCommitteeChainTest(t *testing.T, config types.ChainConfig, signerThreshold int, enforceTime bool) *committeeChainTest { func newCommitteeChainTest(t *testing.T, config params.ChainConfig, signerThreshold int, enforceTime bool) *committeeChainTest {
c := &committeeChainTest{ c := &committeeChainTest{
t: t, t: t,
db: memorydb.New(), db: memorydb.New(),
@ -298,20 +298,20 @@ func (c *committeeChainTest) verifyRange(tc *testCommitteeChain, begin, end uint
c.verifySignedHeader(tc, float64(end)+1.5, false) c.verifySignedHeader(tc, float64(end)+1.5, false)
} }
func newTestGenesis() types.ChainConfig { func newTestGenesis() params.ChainConfig {
var config types.ChainConfig var config params.ChainConfig
rand.Read(config.GenesisValidatorsRoot[:]) rand.Read(config.GenesisValidatorsRoot[:])
return config return config
} }
func newTestForks(config types.ChainConfig, forks types.Forks) types.ChainConfig { func newTestForks(config params.ChainConfig, forks params.Forks) params.ChainConfig {
for _, fork := range forks { for _, fork := range forks {
config.AddFork(fork.Name, fork.Epoch, fork.Version) config.AddFork(fork.Name, fork.Epoch, fork.Version)
} }
return config return config
} }
func newTestCommitteeChain(parent *testCommitteeChain, config types.ChainConfig, newCommittees bool, begin, end int, signerCount int, finalizedHeader bool) *testCommitteeChain { func newTestCommitteeChain(parent *testCommitteeChain, config params.ChainConfig, newCommittees bool, begin, end int, signerCount int, finalizedHeader bool) *testCommitteeChain {
tc := &testCommitteeChain{ tc := &testCommitteeChain{
config: config, config: config,
} }
@ -337,7 +337,7 @@ type testPeriod struct {
type testCommitteeChain struct { type testCommitteeChain struct {
periods []testPeriod periods []testPeriod
config types.ChainConfig config params.ChainConfig
} }
func (tc *testCommitteeChain) fillCommittees(begin, end int) { func (tc *testCommitteeChain) fillCommittees(begin, end int) {

View file

@ -69,12 +69,13 @@ func (h *HeadTracker) ValidatedFinality() (types.FinalityUpdate, bool) {
// slot or same slot and more signers) then ValidatedOptimistic is updated. // slot or same slot and more signers) then ValidatedOptimistic is updated.
// The boolean return flag signals if ValidatedOptimistic has been changed. // The boolean return flag signals if ValidatedOptimistic has been changed.
func (h *HeadTracker) ValidateOptimistic(update types.OptimisticUpdate) (bool, error) { func (h *HeadTracker) ValidateOptimistic(update types.OptimisticUpdate) (bool, error) {
h.lock.Lock()
defer h.lock.Unlock()
if err := update.Validate(); err != nil { if err := update.Validate(); err != nil {
return false, err return false, err
} }
h.lock.Lock()
defer h.lock.Unlock()
replace, err := h.validate(update.SignedHeader(), h.optimisticUpdate.SignedHeader()) replace, err := h.validate(update.SignedHeader(), h.optimisticUpdate.SignedHeader())
if replace { if replace {
h.optimisticUpdate, h.hasOptimisticUpdate = update, true h.optimisticUpdate, h.hasOptimisticUpdate = update, true
@ -88,12 +89,13 @@ func (h *HeadTracker) ValidateOptimistic(update types.OptimisticUpdate) (bool, e
// slot or same slot and more signers) then ValidatedFinality is updated. // slot or same slot and more signers) then ValidatedFinality is updated.
// The boolean return flag signals if ValidatedFinality has been changed. // The boolean return flag signals if ValidatedFinality has been changed.
func (h *HeadTracker) ValidateFinality(update types.FinalityUpdate) (bool, error) { func (h *HeadTracker) ValidateFinality(update types.FinalityUpdate) (bool, error) {
h.lock.Lock()
defer h.lock.Unlock()
if err := update.Validate(); err != nil { if err := update.Validate(); err != nil {
return false, err return false, err
} }
h.lock.Lock()
defer h.lock.Unlock()
replace, err := h.validate(update.SignedHeader(), h.finalityUpdate.SignedHeader()) replace, err := h.validate(update.SignedHeader(), h.finalityUpdate.SignedHeader())
if replace { if replace {
h.finalityUpdate, h.hasFinalityUpdate = update, true h.finalityUpdate, h.hasFinalityUpdate = update, true

View file

@ -33,7 +33,7 @@ func GenerateTestCommittee() *types.SerializedSyncCommittee {
return s return s
} }
func GenerateTestUpdate(config *types.ChainConfig, period uint64, committee, nextCommittee *types.SerializedSyncCommittee, signerCount int, finalizedHeader bool) *types.LightClientUpdate { func GenerateTestUpdate(config *params.ChainConfig, period uint64, committee, nextCommittee *types.SerializedSyncCommittee, signerCount int, finalizedHeader bool) *types.LightClientUpdate {
update := new(types.LightClientUpdate) update := new(types.LightClientUpdate)
update.NextSyncCommitteeRoot = nextCommittee.Root() update.NextSyncCommitteeRoot = nextCommittee.Root()
var attestedHeader types.Header var attestedHeader types.Header
@ -48,9 +48,9 @@ func GenerateTestUpdate(config *types.ChainConfig, period uint64, committee, nex
return update return update
} }
func GenerateTestSignedHeader(header types.Header, config *types.ChainConfig, committee *types.SerializedSyncCommittee, signatureSlot uint64, signerCount int) types.SignedHeader { func GenerateTestSignedHeader(header types.Header, config *params.ChainConfig, committee *types.SerializedSyncCommittee, signatureSlot uint64, signerCount int) types.SignedHeader {
bitmask := makeBitmask(signerCount) bitmask := makeBitmask(signerCount)
signingRoot, _ := config.Forks.SigningRoot(header) signingRoot, _ := config.Forks.SigningRoot(header.Epoch(), header.Hash())
c, _ := dummyVerifier{}.deserializeSyncCommittee(committee) c, _ := dummyVerifier{}.deserializeSyncCommittee(committee)
return types.SignedHeader{ return types.SignedHeader{
Header: header, Header: header,

View file

@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package types package params
import ( import (
"crypto/sha256" "crypto/sha256"
@ -39,81 +39,13 @@ const syncCommitteeDomain = 7
var knownForks = []string{"GENESIS", "ALTAIR", "BELLATRIX", "CAPELLA", "DENEB"} var knownForks = []string{"GENESIS", "ALTAIR", "BELLATRIX", "CAPELLA", "DENEB"}
// Fork describes a single beacon chain fork and also stores the calculated // ClientConfig contains beacon light client configuration.
// signature domain used after this fork. type ClientConfig struct {
type Fork struct { ChainConfig
// Name of the fork in the chain config (config.yaml) file Apis []string
Name string CustomHeader map[string]string
Threshold int
// Epoch when given fork version is activated NoFilter bool
Epoch uint64
// Fork version, see https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types
Version []byte
// index in list of known forks or MaxInt if unknown
knownIndex int
// calculated by computeDomain, based on fork version and genesis validators root
domain merkle.Value
}
// computeDomain returns the signature domain based on the given fork version
// and genesis validator set root.
func (f *Fork) computeDomain(genesisValidatorsRoot common.Hash) {
var (
hasher = sha256.New()
forkVersion32 merkle.Value
forkDataRoot merkle.Value
)
copy(forkVersion32[:], f.Version)
hasher.Write(forkVersion32[:])
hasher.Write(genesisValidatorsRoot[:])
hasher.Sum(forkDataRoot[:0])
f.domain[0] = syncCommitteeDomain
copy(f.domain[4:], forkDataRoot[:28])
}
// Forks is the list of all beacon chain forks in the chain configuration.
type Forks []*Fork
// domain returns the signature domain for the given epoch (assumes that domains
// have already been calculated).
func (f Forks) domain(epoch uint64) (merkle.Value, error) {
for i := len(f) - 1; i >= 0; i-- {
if epoch >= f[i].Epoch {
return f[i].domain, nil
}
}
return merkle.Value{}, fmt.Errorf("unknown fork for epoch %d", epoch)
}
// SigningRoot calculates the signing root of the given header.
func (f Forks) SigningRoot(header Header) (common.Hash, error) {
domain, err := f.domain(header.Epoch())
if err != nil {
return common.Hash{}, err
}
var (
signingRoot common.Hash
headerHash = header.Hash()
hasher = sha256.New()
)
hasher.Write(headerHash[:])
hasher.Write(domain[:])
hasher.Sum(signingRoot[:0])
return signingRoot, nil
}
func (f Forks) Len() int { return len(f) }
func (f Forks) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
func (f Forks) Less(i, j int) bool {
if f[i].Epoch != f[j].Epoch {
return f[i].Epoch < f[j].Epoch
}
return f[i].knownIndex < f[j].knownIndex
} }
// ChainConfig contains the beacon chain configuration. // ChainConfig contains the beacon chain configuration.
@ -121,6 +53,7 @@ type ChainConfig struct {
GenesisTime uint64 // Unix timestamp of slot 0 GenesisTime uint64 // Unix timestamp of slot 0
GenesisValidatorsRoot common.Hash // Root hash of the genesis validator set, used for signature domain calculation GenesisValidatorsRoot common.Hash // Root hash of the genesis validator set, used for signature domain calculation
Forks Forks Forks Forks
Checkpoint common.Hash
} }
// ForkAtEpoch returns the latest active fork at the given epoch. // ForkAtEpoch returns the latest active fork at the given epoch.
@ -202,3 +135,79 @@ func (c *ChainConfig) LoadForks(path string) error {
} }
return nil return nil
} }
// Fork describes a single beacon chain fork and also stores the calculated
// signature domain used after this fork.
type Fork struct {
// Name of the fork in the chain config (config.yaml) file
Name string
// Epoch when given fork version is activated
Epoch uint64
// Fork version, see https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types
Version []byte
// index in list of known forks or MaxInt if unknown
knownIndex int
// calculated by computeDomain, based on fork version and genesis validators root
domain merkle.Value
}
// computeDomain returns the signature domain based on the given fork version
// and genesis validator set root.
func (f *Fork) computeDomain(genesisValidatorsRoot common.Hash) {
var (
hasher = sha256.New()
forkVersion32 merkle.Value
forkDataRoot merkle.Value
)
copy(forkVersion32[:], f.Version)
hasher.Write(forkVersion32[:])
hasher.Write(genesisValidatorsRoot[:])
hasher.Sum(forkDataRoot[:0])
f.domain[0] = syncCommitteeDomain
copy(f.domain[4:], forkDataRoot[:28])
}
// Forks is the list of all beacon chain forks in the chain configuration.
type Forks []*Fork
// domain returns the signature domain for the given epoch (assumes that domains
// have already been calculated).
func (f Forks) domain(epoch uint64) (merkle.Value, error) {
for i := len(f) - 1; i >= 0; i-- {
if epoch >= f[i].Epoch {
return f[i].domain, nil
}
}
return merkle.Value{}, fmt.Errorf("unknown fork for epoch %d", epoch)
}
// SigningRoot calculates the signing root of the given header.
func (f Forks) SigningRoot(epoch uint64, root common.Hash) (common.Hash, error) {
domain, err := f.domain(epoch)
if err != nil {
return common.Hash{}, err
}
var (
signingRoot common.Hash
hasher = sha256.New()
)
hasher.Write(root[:])
hasher.Write(domain[:])
hasher.Sum(signingRoot[:0])
return signingRoot, nil
}
func (f Forks) Len() int { return len(f) }
func (f Forks) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
func (f Forks) Less(i, j int) bool {
if f[i].Epoch != f[j].Epoch {
return f[i].Epoch < f[j].Epoch
}
return f[i].knownIndex < f[j].knownIndex
}

56
beacon/params/networks.go Normal file
View file

@ -0,0 +1,56 @@
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package params
import (
"github.com/ethereum/go-ethereum/common"
)
var (
MainnetLightConfig = (&ChainConfig{
GenesisValidatorsRoot: common.HexToHash("0x4b363db94e286120d76eb905340fdd4e54bfe9f06bf33ff6cf5ad27f511bfe95"),
GenesisTime: 1606824023,
Checkpoint: common.HexToHash("0x6509b691f4de4f7b083f2784938fd52f0e131675432b3fd85ea549af9aebd3d0"),
}).
AddFork("GENESIS", 0, []byte{0, 0, 0, 0}).
AddFork("ALTAIR", 74240, []byte{1, 0, 0, 0}).
AddFork("BELLATRIX", 144896, []byte{2, 0, 0, 0}).
AddFork("CAPELLA", 194048, []byte{3, 0, 0, 0}).
AddFork("DENEB", 269568, []byte{4, 0, 0, 0})
SepoliaLightConfig = (&ChainConfig{
GenesisValidatorsRoot: common.HexToHash("0xd8ea171f3c94aea21ebc42a1ed61052acf3f9209c00e4efbaaddac09ed9b8078"),
GenesisTime: 1655733600,
Checkpoint: common.HexToHash("0x456e85f5608afab3465a0580bff8572255f6d97af0c5f939e3f7536b5edb2d3f"),
}).
AddFork("GENESIS", 0, []byte{144, 0, 0, 105}).
AddFork("ALTAIR", 50, []byte{144, 0, 0, 112}).
AddFork("BELLATRIX", 100, []byte{144, 0, 0, 113}).
AddFork("CAPELLA", 56832, []byte{144, 0, 0, 114}).
AddFork("DENEB", 132608, []byte{144, 0, 0, 115})
HoleskyLightConfig = (&ChainConfig{
GenesisValidatorsRoot: common.HexToHash("0x9143aa7c615a7f7115e2b6aac319c03529df8242ae705fba9df39b79c59fa8b1"),
GenesisTime: 1695902400,
Checkpoint: common.HexToHash("0x6456a1317f54d4b4f2cb5bc9d153b5af0988fe767ef0609f0236cf29030bcff7"),
}).
AddFork("GENESIS", 0, []byte{1, 1, 112, 0}).
AddFork("ALTAIR", 0, []byte{2, 1, 112, 0}).
AddFork("BELLATRIX", 0, []byte{3, 1, 112, 0}).
AddFork("CAPELLA", 256, []byte{4, 1, 112, 0}).
AddFork("DENEB", 29696, []byte{5, 1, 112, 0})
)

View file

@ -5,88 +5,88 @@
# https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/ # https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/
ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz
# version:golang 1.23.1 # version:golang 1.23.3
# https://go.dev/dl/ # https://go.dev/dl/
6ee44e298379d146a5e5aa6b1c5b5d5f5d0a3365eabdd70741e6e21340ec3b0d go1.23.1.src.tar.gz 8d6a77332487557c6afa2421131b50f83db4ae3c579c3bc72e670ee1f6968599 go1.23.3.src.tar.gz
f17f2791717c15728ec63213a014e244c35f9c8846fb29f5a1b63d0c0556f756 go1.23.1.aix-ppc64.tar.gz bdbf2a243ed4a121c9988684e5b15989cb244c1ff9e41ca823d0187b5c859114 go1.23.3.aix-ppc64.tar.gz
dd9e772686ed908bcff94b6144322d4e2473a7dcd7c696b7e8b6d12f23c887fd go1.23.1.darwin-amd64.pkg b79c77bbdf61e6e486aa6bea9286f3f7969c28e2ff7686ce10c334f746bfb724 go1.23.3.darwin-amd64.pkg
488d9e4ca3e3ed513ee4edd91bef3a2360c65fa6d6be59cf79640bf840130a58 go1.23.1.darwin-amd64.tar.gz c7e024d5c0bc81845070f23598caf02f05b8ae88fd4ad2cd3e236ddbea833ad2 go1.23.3.darwin-amd64.tar.gz
be34b488157ec69d94e26e1554558219a2c90789bcb7e3686965a7f9c8cfcbe7 go1.23.1.darwin-arm64.pkg 3e764df0db8f3c7470b9ff641954a380510a4822613c06bd5a195fd083f4731d go1.23.3.darwin-arm64.pkg
e223795ca340e285a760a6446ce57a74500b30e57469a4109961d36184d3c05a go1.23.1.darwin-arm64.tar.gz 31e119fe9bde6e105407a32558d5b5fa6ca11e2bd17f8b7b2f8a06aba16a0632 go1.23.3.darwin-arm64.tar.gz
6af626176923a6ae6c5de6dc1c864f38365793c0e4ecd0d6eab847bdc23953e5 go1.23.1.dragonfly-amd64.tar.gz 3872c9a98331050a242afe63fa6abc8fc313aca83dcaefda318e903309ac0c8d go1.23.3.dragonfly-amd64.tar.gz
cc957c1a019702e6cdc2e257202d42799011ebc1968b6c3bcd6b1965952607d5 go1.23.1.freebsd-386.tar.gz 69479fa016ec5b4605885643ce0c2dd5c583e02353978feb6de38c961863b9cc go1.23.3.freebsd-386.tar.gz
a7d57781c50bb80886a8f04066791956d45aa3eea0f83070c5268b6223afb2ff go1.23.1.freebsd-amd64.tar.gz bf1de22a900646ef4f79480ed88337856d47089cc610f87e6fef46f6b8db0e1f go1.23.3.freebsd-amd64.tar.gz
c7b09f3fef456048e596db9bea746eb66796aeb82885622b0388feee18f36a3e go1.23.1.freebsd-arm.tar.gz e461f866479bc36bdd4cfec32bfecb1bb243152268a1b3223de109410dec3407 go1.23.3.freebsd-arm.tar.gz
b05cd6a77995a0c8439d88df124811c725fb78b942d0b6dd1643529d7ba62f1f go1.23.1.freebsd-arm64.tar.gz 24154b4018a45540aefeb6b5b9ffdcc8d9a8cdb78cd7fec262787b89fed19997 go1.23.3.freebsd-arm64.tar.gz
56236ae70be1613f2915943b94f53c96be5bffc0719314078facd778a89bc57e go1.23.1.freebsd-riscv64.tar.gz 218f3f1532e61dd65c330c2a5fc85bec18cc3690489763e62ffa9bb9fc85a68e go1.23.3.freebsd-riscv64.tar.gz
8644c52df4e831202114fd67c9fcaf1f7233ad27bf945ac53fa7217cf1a0349f go1.23.1.illumos-amd64.tar.gz 24e3f34858b8687c31f5e5ab9e46d27fb613b0d50a94261c500cebb2d79c0672 go1.23.3.illumos-amd64.tar.gz
cdee2f4e2efa001f7ee75c90f2efc310b63346cfbba7b549987e9139527c6b17 go1.23.1.linux-386.tar.gz 3d7b00191a43c50d28e0903a0c576104bc7e171a8670de419d41111c08dfa299 go1.23.3.linux-386.tar.gz
49bbb517cfa9eee677e1e7897f7cf9cfdbcf49e05f61984a2789136de359f9bd go1.23.1.linux-amd64.tar.gz a0afb9744c00648bafb1b90b4aba5bdb86f424f02f9275399ce0c20b93a2c3a8 go1.23.3.linux-amd64.tar.gz
faec7f7f8ae53fda0f3d408f52182d942cc89ef5b7d3d9f23ff117437d4b2d2f go1.23.1.linux-arm64.tar.gz 1f7cbd7f668ea32a107ecd41b6488aaee1f5d77a66efd885b175494439d4e1ce go1.23.3.linux-arm64.tar.gz
6c7832c7dcd8fb6d4eb308f672a725393403c74ee7be1aeccd8a443015df99de go1.23.1.linux-armv6l.tar.gz 5f0332754beffc65af65a7b2da76e9dd997567d0d81b6f4f71d3588dc7b4cb00 go1.23.3.linux-armv6l.tar.gz
649ce3856ddc808c00b14a46232eab0bf95e7911cdf497010b17d76656f5ca4e go1.23.1.linux-loong64.tar.gz 1d0161a8946c7d99f717bad23631738408511f9f87e78d852224a023d8882ad8 go1.23.3.linux-loong64.tar.gz
201911048f234e5a0c51ec94b1a11d4e47062fee4398b1d2faa6c820dc026724 go1.23.1.linux-mips.tar.gz e924a7c9027f521f8a3563541ed0f89a4db3ef005b6b71263415b38e0b46e63a go1.23.3.linux-mips.tar.gz
2bce3743df463915e45d2612f9476ffb03d0b3750b1cb3879347de08715b5fc6 go1.23.1.linux-mips64.tar.gz 4cdf8c38165627f032c2b17cdd95e4aafff40d75fc873824d4c94914284098ca go1.23.3.linux-mips64.tar.gz
54e301f266e33431b0703136e0bbd4cf02461b1ecedd37b7cbd90cb862a98e5f go1.23.1.linux-mips64le.tar.gz 5e49347e7325d2e268fb14040529b704e66eed77154cc73a919e9167d8527a2f go1.23.3.linux-mips64le.tar.gz
8efd495e93d17408c0803595cdc3bf13cb28e0f957aeabd9cc18245fb8e64019 go1.23.1.linux-mipsle.tar.gz 142eabc17cee99403e895383ed7a6b7b40e740e8c2f73b79352bb9d1242fbd98 go1.23.3.linux-mipsle.tar.gz
52bd68689095831ad9af7160844c23b28bb8d0acd268de7e300ff5f0662b7a07 go1.23.1.linux-ppc64.tar.gz 96ad61ba6b6cc0f5adfd75e65231c61e7db26d8236f01117023899528164d1b0 go1.23.3.linux-ppc64.tar.gz
042888cae54b5fbfd9dd1e3b6bc4a5134879777fe6497fc4c62ec394b5ecf2da go1.23.1.linux-ppc64le.tar.gz e3b926c81e8099d3cee6e6e270b85b39c3bd44263f8d3df29aacb4d7e00507c8 go1.23.3.linux-ppc64le.tar.gz
1a4a609f0391bea202d9095453cbfaf7368fa88a04c206bf9dd715a738664dc3 go1.23.1.linux-riscv64.tar.gz 324e03b6f59be841dfbaeabc466224b0f0905f5ad3a225b7c0703090e6c4b1a5 go1.23.3.linux-riscv64.tar.gz
47dc49ad45c45e192efa0df7dc7bc5403f5f2d15b5d0dc74ef3018154b616f4d go1.23.1.linux-s390x.tar.gz 6bd72fcef72b046b6282c2d1f2c38f31600e4fe9361fcd8341500c754fb09c38 go1.23.3.linux-s390x.tar.gz
fbfbd5efa6a5d581ea7f5e65015f927db0e52135cab057e43d39d5482da54b61 go1.23.1.netbsd-386.tar.gz 5df382337fe2e4ea6adaafa823da5e083513a97534a38f89d691dd6f599084ca go1.23.3.netbsd-386.tar.gz
e96e1cc5cf36113ee6099d1a7306b22cd9c3f975a36bdff954c59f104f22b853 go1.23.1.netbsd-amd64.tar.gz 9ae7cb6095a3e91182ac03547167e230fddd4941ed02dbdb6af663b2a53d9db7 go1.23.3.netbsd-amd64.tar.gz
c394dfc06bfc276a591209a37e09cd39089ec9a9cc3db30b94814ce2e39eb1d4 go1.23.1.netbsd-arm.tar.gz 4a452c4134a9bea6213d8925d322f26b01c0eccda1330585bb2b241c76a0c3ea go1.23.3.netbsd-arm.tar.gz
b3b35d64f32821a68b3e2994032dbefb81978f2ec3f218c7a770623b82d36b8e go1.23.1.netbsd-arm64.tar.gz 8ff3b5184d840148dbca061c04dca35a7070dc894255d3b755066bd76a7094dc go1.23.3.netbsd-arm64.tar.gz
3c775c4c16c182e33c2c4ac090d9a247a93b3fb18a3df01d87d490f29599faff go1.23.1.openbsd-386.tar.gz 5b6940922e68ac1162a704a8b583fb4f039f955bfe97c35a56c40269cbcff9b1 go1.23.3.openbsd-386.tar.gz
5edbe53b47c57b32707fd7154536fbe9eaa79053fea01650c93b54cdba13fc0f go1.23.1.openbsd-amd64.tar.gz 6ae4aeb6a88f3754b10ecec90422a30fb8bf86c3187be2be9408d67a5a235ace go1.23.3.openbsd-amd64.tar.gz
c30903dd8fa98b8aca8e9db0962ce9f55502aed93e0ef41e5ae148aaa0088de1 go1.23.1.openbsd-arm.tar.gz e5eae226391b60c4d1ea1022663f55b225c6d7bab67f31fbafd5dd7a04684006 go1.23.3.openbsd-arm.tar.gz
12da183489e58f9c6b357bc1b626f85ed7d4220cab31a49d6a49e6ac6a718b67 go1.23.1.openbsd-arm64.tar.gz e12b2c04535e0bf5561d54831122b410d708519c1ec2c56b0c2350b15243c331 go1.23.3.openbsd-arm64.tar.gz
9cc9aad37696a4a10c31dcec9e35a308de0b369dad354d54cf07406ac6fa7c6f go1.23.1.openbsd-ppc64.tar.gz 599818e4062166d7a112f6f3fcca2dd4e2cdd3111fe48f9757bd8debf38c7f52 go1.23.3.openbsd-ppc64.tar.gz
e1d740dda062ce5a276a0c3ed7d8b6353238bc8ff405f63e2e3480bfd26a5ec5 go1.23.1.openbsd-riscv64.tar.gz 9ca4db8cab2a07d561f5b2a9397793684ab3b22326add1fe8cda8a545a1693db go1.23.3.openbsd-riscv64.tar.gz
da2a37f9987f01f096859230aa13ecc4ad2e7884465bce91004bc78c64435d65 go1.23.1.plan9-386.tar.gz 8fca1ec2aced936e0170605378ee7f0acb38f002490321f67fc83728ee281967 go1.23.3.plan9-386.tar.gz
fd8fff8b0697d55c4a4d02a8dc998192b80a9dc2a057647373d6ff607cad29de go1.23.1.plan9-amd64.tar.gz 22d663692224fc1933a97f61d9fe49815e3b9ef1c2be97046505683fdf2e23c7 go1.23.3.plan9-amd64.tar.gz
52efbc5804c1c86ba7868aa8ebbc31cc8c2a27b62a60fd57944970d48fc67525 go1.23.1.plan9-arm.tar.gz d0417a702d0e776d57e450fa2ce1ce7efa199a636644776862dbf946c409a462 go1.23.3.plan9-arm.tar.gz
f54205f21e2143f2ada1bf1c00ddf64590f5139d5c3fb77cc06175f0d8cc7567 go1.23.1.solaris-amd64.tar.gz b5d9db1c02e0ca266a142eb687bd7749890c30872b09a4a0ffcd491425039754 go1.23.3.solaris-amd64.tar.gz
369a17f0cfd29e5c848e58ffe0d772da20abe334d1c7ca01dbcd55bb3db0b440 go1.23.1.windows-386.msi 14b7baf4af2046013b74dfac6e9a0a7403f15ee9940a16890bc028dfd32c49ac go1.23.3.windows-386.msi
ab866f47d7be56e6b1c67f1d529bf4c23331a339fb0785f435a0552d352cb257 go1.23.1.windows-386.zip 23da9089ea6c5612d718f13c26e9bfc9aaaabe222838075346a8191d48f9dfe5 go1.23.3.windows-386.zip
e99dac215ee437b9bb8f8b14bbfe0e8756882c1ed291f30818e8363bc9c047a5 go1.23.1.windows-amd64.msi 614f0e3eed82245dfb4356d4e8d5b96abecca6a4c4f0168c0e389e4dd6284db8 go1.23.3.windows-amd64.msi
32dedf277c86610e380e1765593edb66876f00223df71690bd6be68ee17675c0 go1.23.1.windows-amd64.zip 81968b563642096b8a7521171e2be6e77ff6f44032f7493b7bdec9d33f44f31d go1.23.3.windows-amd64.zip
23169c79dc6b54e0dffb25be6b67425ad9759392a58309bc057430a9bf4c8f6a go1.23.1.windows-arm.msi c9951eecad732c59dfde6dc4803fa9253eb074663c61035c8d856f4d2eb146cb go1.23.3.windows-arm.msi
1a57615a09f13534f88e9f2d7efd5743535d1a5719b19e520eef965a634f8efb go1.23.1.windows-arm.zip 1a7db02be47deada42082d21d63eba0013f93375cfa0e7768962f1295a469022 go1.23.3.windows-arm.zip
313e1a543931ad8735b4df8969e00f5f4c2ef07be21f54015ede961a70263d35 go1.23.1.windows-arm64.msi a74e3e195219af4330b93c71cd4b736b709a5654a07cc37eebe181c4984afb82 go1.23.3.windows-arm64.msi
64ad0954d2c33f556fb1018d62de091254aa6e3a94f1c8a8b16af0d3701d194e go1.23.1.windows-arm64.zip dbdfa868b1a3f8c62950373e4975d83f90dd8b869a3907319af8384919bcaffe go1.23.3.windows-arm64.zip
# version:golangci 1.59.0 # version:golangci 1.61.0
# https://github.com/golangci/golangci-lint/releases/ # https://github.com/golangci/golangci-lint/releases/
# https://github.com/golangci/golangci-lint/releases/download/v1.59.0/ # https://github.com/golangci/golangci-lint/releases/download/v1.61.0/
418acf7e255ddc0783e97129c9b03d9311b77826a5311d425a01c708a86417e7 golangci-lint-1.59.0-darwin-amd64.tar.gz 5c280ef3284f80c54fd90d73dc39ca276953949da1db03eb9dd0fbf868cc6e55 golangci-lint-1.61.0-darwin-amd64.tar.gz
5f6a1d95a6dd69f6e328eb56dd311a38e04cfab79a1305fbf4957f4e203f47b6 golangci-lint-1.59.0-darwin-arm64.tar.gz 544334890701e4e04a6e574bc010bea8945205c08c44cced73745a6378012d36 golangci-lint-1.61.0-darwin-arm64.tar.gz
8899bf589185d49f747f3e5db9f0bde8a47245a100c64a3dd4d65e8e92cfc4f2 golangci-lint-1.59.0-freebsd-386.tar.gz e885a6f561092055930ebd298914d80e8fd2e10d2b1e9942836c2c6a115301fa golangci-lint-1.61.0-freebsd-386.tar.gz
658212f138d9df2ac89427e22115af34bf387c0871d70f2a25101718946a014f golangci-lint-1.59.0-freebsd-amd64.tar.gz b13f6a3f11f65e7ff66b734d7554df3bbae0f485768848424e7554ed289e19c2 golangci-lint-1.61.0-freebsd-amd64.tar.gz
4c6395ea40f314d3b6fa17d8997baab93464d5d1deeaab513155e625473bd03a golangci-lint-1.59.0-freebsd-armv6.tar.gz cd8e7bbe5b8f33ed1597aa1cc588da96a3b9f22e1b9ae60d93511eae1a0ee8c5 golangci-lint-1.61.0-freebsd-armv6.tar.gz
ff37da4fbaacdb6bbae70fdbdbb1ba932a859956f788c82822fa06bef5b7c6b3 golangci-lint-1.59.0-freebsd-armv7.tar.gz 7ade524dbd88bd250968f45e190af90e151fa5ee63dd6aa7f7bb90e8155db61d golangci-lint-1.61.0-freebsd-armv7.tar.gz
439739469ed2bda182b1ec276d40c40e02f195537f78e3672996741ad223d6b6 golangci-lint-1.59.0-illumos-amd64.tar.gz 0fe3cd8a1ed8d9f54f48670a5af3df056d6040d94017057f0f4d65c930660ad9 golangci-lint-1.61.0-illumos-amd64.tar.gz
940801d46790e40d0a097d8fee34e2606f0ef148cd039654029b0b8750a15ed6 golangci-lint-1.59.0-linux-386.tar.gz b463fc5053a612abd26393ebaff1d85d7d56058946f4f0f7bf25ed44ea899415 golangci-lint-1.61.0-linux-386.tar.gz
3b14a439f33c4fff83dbe0349950d984042b9a1feb6c62f82787b598fc3ab5f4 golangci-lint-1.59.0-linux-amd64.tar.gz 77cb0af99379d9a21d5dc8c38364d060e864a01bd2f3e30b5e8cc550c3a54111 golangci-lint-1.61.0-linux-amd64.tar.gz
c57e6c0b0fa03089a2611dceddd5bc5d206716cccdff8b149da8baac598719a1 golangci-lint-1.59.0-linux-arm64.tar.gz af60ac05566d9351615cb31b4cc070185c25bf8cbd9b09c1873aa5ec6f3cc17e golangci-lint-1.61.0-linux-arm64.tar.gz
93149e2d3b25ac754df9a23172403d8aa6d021a7e0d9c090a12f51897f68c9a0 golangci-lint-1.59.0-linux-armv6.tar.gz 1f307f2fcc5d7d674062a967a0d83a7091e300529aa237ec6ad2b3dd14c897f5 golangci-lint-1.61.0-linux-armv6.tar.gz
d10ac38239d9efee3ee87b55c96cdf3fa09e1a525babe3ffdaaf65ccc48cf3dc golangci-lint-1.59.0-linux-armv7.tar.gz 3ad8cbaae75a547450844811300f99c4cd290277398e43d22b9eb1792d15af4c golangci-lint-1.61.0-linux-armv7.tar.gz
047338114b4f0d5f08f0fb9a397b03cc171916ed0960be7dfb355c2320cd5e9c golangci-lint-1.59.0-linux-loong64.tar.gz 9be2ca67d961d7699079739cf6f7c8291c5183d57e34d1677de21ca19d0bd3ed golangci-lint-1.61.0-linux-loong64.tar.gz
5632df0f7f8fc03a80a266130faef0b5902d280cf60621f1b2bdc1aef6d97ee9 golangci-lint-1.59.0-linux-mips64.tar.gz 90d005e1648115ebf0861b408eab9c936079a24763e883058b0a227cd3135d31 golangci-lint-1.61.0-linux-mips64.tar.gz
71dd638c82fa4439171e7126d2c7a32b5d103bfdef282cea40c83632cb3d1f4b golangci-lint-1.59.0-linux-mips64le.tar.gz 6d2ed4f49407115460b8c10ccfc40fd177e0887a48864a2879dd16e84ba2a48c golangci-lint-1.61.0-linux-mips64le.tar.gz
6cf9ea0d34e91669948483f9ae7f07da319a879344373a1981099fbd890cde00 golangci-lint-1.59.0-linux-ppc64le.tar.gz 633089589af5a58b7430afb6eee107d4e9c99e8d91711ddc219eb13a07e8d3b8 golangci-lint-1.61.0-linux-ppc64le.tar.gz
af0205fa6fbab197cee613c359947711231739095d21b5c837086233b36ad971 golangci-lint-1.59.0-linux-riscv64.tar.gz 4c1a097d9e0d1b4a8144dae6a1f5583a38d662f3bdc1498c4e954b6ed856be98 golangci-lint-1.61.0-linux-riscv64.tar.gz
a9d2fb93f3c688ebccef94f5dc96c0b07c4d20bf6556cddebd8442159b0c80f6 golangci-lint-1.59.0-linux-s390x.tar.gz 30581d3c987d287b7064617f1a2694143e10dffc40bc25be6636006ee82d7e1c golangci-lint-1.61.0-linux-s390x.tar.gz
68ab4c57a847b8ace9679887f2f8b2b6760e57ee29dcde8c3f40dd8bb2654fa2 golangci-lint-1.59.0-netbsd-386.tar.gz 42530bf8100bd43c07f5efe6d92148ba6c5a7a712d510c6f24be85af6571d5eb golangci-lint-1.61.0-netbsd-386.tar.gz
d277b8b435c19406d00de4d509eadf5a024a5782878332e9a1b7c02bb76e87a7 golangci-lint-1.59.0-netbsd-amd64.tar.gz b8bb07c920f6601edf718d5e82ec0784fd590b0992b42b6ec18da99f26013ed4 golangci-lint-1.61.0-netbsd-amd64.tar.gz
83211656be8dcfa1545af4f92894409f412d1f37566798cb9460a526593ad62c golangci-lint-1.59.0-netbsd-arm64.tar.gz 353a51527c60bd0776b0891b03f247c791986f625fca689d121972c624e54198 golangci-lint-1.61.0-netbsd-arm64.tar.gz
6c6866d28bf79fa9817a0f7d2b050890ed109cae80bdb4dfa39536a7226da237 golangci-lint-1.59.0-netbsd-armv6.tar.gz 957a6272c3137910514225704c5dac0723b9c65eb7d9587366a997736e2d7580 golangci-lint-1.61.0-netbsd-armv6.tar.gz
11587566363bd03ca586b7df9776ccaed569fcd1f3489930ac02f9375b307503 golangci-lint-1.59.0-netbsd-armv7.tar.gz a89eb28ff7f18f5cd52b914739360fa95cf2f643de4adeca46e26bec3a07e8d8 golangci-lint-1.61.0-netbsd-armv7.tar.gz
466181a8967bafa495e41494f93a0bec829c2cf715de874583b0460b3b8ae2b8 golangci-lint-1.59.0-windows-386.zip d8d74c43600b271393000717a4ed157d7a15bb85bab7db2efad9b63a694d4634 golangci-lint-1.61.0-windows-386.zip
3317d8a87a99a49a0a1321d295c010790e6dbf43ee96b318f4b8bb23eae7a565 golangci-lint-1.59.0-windows-amd64.zip e7bc2a81929a50f830244d6d2e657cce4f19a59aff49fa9000176ff34fda64ce golangci-lint-1.61.0-windows-amd64.zip
b3af955c7fceac8220a36fc799e1b3f19d3b247d32f422caac5f9845df8f7316 golangci-lint-1.59.0-windows-arm64.zip ed97c221596dd771e3dd9344872c140340bee2e819cd7a90afa1de752f1f2e0f golangci-lint-1.61.0-windows-arm64.zip
6f083c7d0c764e5a0e5bde46ee3e91ae357d80c194190fe1d9754392e9064c7e golangci-lint-1.59.0-windows-armv6.zip 4b365233948b13d02d45928a5c390045e00945e919747b9887b5f260247541ae golangci-lint-1.61.0-windows-armv6.zip
3709b4dd425deadab27748778d08e03c0f804d7748f7dd5b6bb488d98aa031c7 golangci-lint-1.59.0-windows-armv7.zip 595538fb64d152173959d28f6235227f9cd969a828e5af0c4e960d02af4ffd0e golangci-lint-1.61.0-windows-armv7.zip
# This is the builder on PPA that will build Go itself (inception-y), don't modify! # This is the builder on PPA that will build Go itself (inception-y), don't modify!
# #

View file

@ -24,9 +24,14 @@ Usage: go run build/ci.go <command> <command flags/arguments>
Available commands are: Available commands are:
install [ -arch architecture ] [ -cc compiler ] [ packages... ] -- builds packages and executables lint -- runs certain pre-selected linters
test [ -coverage ] [ packages... ] -- runs the tests check_tidy -- verifies that everything is 'go mod tidy'-ed
lint -- runs certain pre-selected linters check_generate -- verifies that everything is 'go generate'-ed
check_baddeps -- verifies that certain dependencies are avoided
install [ -arch architecture ] [ -cc compiler ] [ packages... ] -- builds packages and executables
test [ -coverage ] [ packages... ] -- runs the tests
archive [ -arch architecture ] [ -type zip|tar ] [ -signer key-envvar ] [ -signify key-envvar ] [ -upload dest ] -- archives build artifacts archive [ -arch architecture ] [ -type zip|tar ] [ -signer key-envvar ] [ -signify key-envvar ] [ -upload dest ] -- archives build artifacts
importkeys -- imports signing keys from env importkeys -- imports signing keys from env
debsrc [ -signer key-id ] [ -upload dest ] -- creates a debian source package debsrc [ -signer key-id ] [ -upload dest ] -- creates a debian source package
@ -39,25 +44,23 @@ package main
import ( import (
"bytes" "bytes"
"crypto/sha256"
"encoding/base64" "encoding/base64"
"flag" "flag"
"fmt" "fmt"
"io"
"log" "log"
"os" "os"
"os/exec" "os/exec"
"path" "path"
"path/filepath" "path/filepath"
"runtime" "runtime"
"slices"
"strings" "strings"
"time" "time"
"github.com/cespare/cp" "github.com/cespare/cp"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto/signify" "github.com/ethereum/go-ethereum/crypto/signify"
"github.com/ethereum/go-ethereum/internal/build" "github.com/ethereum/go-ethereum/internal/build"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/internal/version"
) )
var ( var (
@ -109,7 +112,7 @@ var (
// A debian package is created for all executables listed here. // A debian package is created for all executables listed here.
debEthereum = debPackage{ debEthereum = debPackage{
Name: "ethereum", Name: "ethereum",
Version: params.Version, Version: version.Semantic,
Executables: debExecutables, Executables: debExecutables,
} }
@ -120,11 +123,12 @@ var (
// Distros for which packages are created // Distros for which packages are created
debDistros = []string{ debDistros = []string{
"xenial", // 16.04, EOL: 04/2026 "xenial", // 16.04, EOL: 04/2026
"bionic", // 18.04, EOL: 04/2028 "bionic", // 18.04, EOL: 04/2028
"focal", // 20.04, EOL: 04/2030 "focal", // 20.04, EOL: 04/2030
"jammy", // 22.04, EOL: 04/2032 "jammy", // 22.04, EOL: 04/2032
"noble", // 24.04, EOL: 04/2034 "noble", // 24.04, EOL: 04/2034
"oracular", // 24.10, EOL: 07/2025
} }
// This is where the tests should be unpacked. // This is where the tests should be unpacked.
@ -143,7 +147,7 @@ func executablePath(name string) string {
func main() { func main() {
log.SetFlags(log.Lshortfile) log.SetFlags(log.Lshortfile)
if !common.FileExist(filepath.Join("build", "ci.go")) { if !build.FileExist(filepath.Join("build", "ci.go")) {
log.Fatal("this script must be run from the root of the repository") log.Fatal("this script must be run from the root of the repository")
} }
if len(os.Args) < 2 { if len(os.Args) < 2 {
@ -156,6 +160,12 @@ func main() {
doTest(os.Args[2:]) doTest(os.Args[2:])
case "lint": case "lint":
doLint(os.Args[2:]) doLint(os.Args[2:])
case "check_tidy":
doCheckTidy()
case "check_generate":
doCheckGenerate()
case "check_baddeps":
doCheckBadDeps()
case "archive": case "archive":
doArchive(os.Args[2:]) doArchive(os.Args[2:])
case "dockerx": case "dockerx":
@ -168,8 +178,6 @@ func main() {
doPurge(os.Args[2:]) doPurge(os.Args[2:])
case "sanitycheck": case "sanitycheck":
doSanityCheck() doSanityCheck()
case "generate":
doGenerate()
default: default:
log.Fatal("unknown command ", os.Args[1]) log.Fatal("unknown command ", os.Args[1])
} }
@ -204,12 +212,6 @@ func doInstall(cmdline []string) {
// Configure the build. // Configure the build.
gobuild := tc.Go("build", buildFlags(env, *staticlink, buildTags)...) gobuild := tc.Go("build", buildFlags(env, *staticlink, buildTags)...)
// arm64 CI builders are memory-constrained and can't handle concurrent builds,
// better disable it. This check isn't the best, it should probably
// check for something in env instead.
if env.CI && runtime.GOARCH == "arm64" {
gobuild.Args = append(gobuild.Args, "-p", "1")
}
// We use -trimpath to avoid leaking local paths into the built executables. // We use -trimpath to avoid leaking local paths into the built executables.
gobuild.Args = append(gobuild.Args, "-trimpath") gobuild.Args = append(gobuild.Args, "-trimpath")
@ -225,8 +227,7 @@ func doInstall(cmdline []string) {
// Do the build! // Do the build!
for _, pkg := range packages { for _, pkg := range packages {
args := make([]string, len(gobuild.Args)) args := slices.Clone(gobuild.Args)
copy(args, gobuild.Args)
args = append(args, "-o", executablePath(path.Base(pkg))) args = append(args, "-o", executablePath(path.Base(pkg)))
args = append(args, pkg) args = append(args, pkg)
build.MustRun(&exec.Cmd{Path: gobuild.Path, Args: args, Env: gobuild.Env}) build.MustRun(&exec.Cmd{Path: gobuild.Path, Args: args, Env: gobuild.Env})
@ -354,128 +355,93 @@ func downloadSpecTestFixtures(csdb *build.ChecksumDB, cachedir string) string {
return filepath.Join(cachedir, base) return filepath.Join(cachedir, base)
} }
// hashAllSourceFiles iterates all files under the top-level project directory // doCheckTidy assets that the Go modules files are tidied already.
// computing the hash of each file (excluding files within the tests func doCheckTidy() {
// subrepo) targets := []string{"go.mod", "go.sum"}
func hashAllSourceFiles() (map[string]common.Hash, error) {
res := make(map[string]common.Hash) hashes, err := build.HashFiles(targets)
err := filepath.WalkDir(".", func(path string, d os.DirEntry, err error) error {
if strings.HasPrefix(path, filepath.FromSlash("tests/testdata")) {
return filepath.SkipDir
}
if !d.Type().IsRegular() {
return nil
}
// open the file and hash it
f, err := os.OpenFile(path, os.O_RDONLY, 0666)
if err != nil {
return err
}
hasher := sha256.New()
if _, err := io.Copy(hasher, f); err != nil {
return err
}
res[path] = common.Hash(hasher.Sum(nil))
return nil
})
if err != nil { if err != nil {
return nil, err log.Fatalf("failed to hash go.mod/go.sum: %v", err)
} }
return res, nil build.MustRun(new(build.GoToolchain).Go("mod", "tidy"))
}
// hashSourceFiles iterates the provided set of filepaths (relative to the top-level geth project directory) tidied, err := build.HashFiles(targets)
// computing the hash of each file.
func hashSourceFiles(files []string) (map[string]common.Hash, error) {
res := make(map[string]common.Hash)
for _, filePath := range files {
f, err := os.OpenFile(filePath, os.O_RDONLY, 0666)
if err != nil {
return nil, err
}
hasher := sha256.New()
if _, err := io.Copy(hasher, f); err != nil {
return nil, err
}
res[filePath] = common.Hash(hasher.Sum(nil))
}
return res, nil
}
// compareHashedFilesets compares two maps (key is relative file path to top-level geth directory, value is its hash)
// and returns the list of file paths whose hashes differed.
func compareHashedFilesets(preHashes map[string]common.Hash, postHashes map[string]common.Hash) []string {
updates := []string{}
for path, postHash := range postHashes {
preHash, ok := preHashes[path]
if !ok || preHash != postHash {
updates = append(updates, path)
}
}
return updates
}
func doGoModTidy() {
targetFiles := []string{"go.mod", "go.sum"}
preHashes, err := hashSourceFiles(targetFiles)
if err != nil { if err != nil {
log.Fatal("failed to hash go.mod/go.sum", "err", err) log.Fatalf("failed to rehash go.mod/go.sum: %v", err)
} }
tc := new(build.GoToolchain) if updates := build.DiffHashes(hashes, tidied); len(updates) > 0 {
c := tc.Go("mod", "tidy") log.Fatalf("files changed on running 'go mod tidy': %v", updates)
build.MustRun(c)
postHashes, err := hashSourceFiles(targetFiles)
updates := compareHashedFilesets(preHashes, postHashes)
for _, updatedFile := range updates {
fmt.Fprintf(os.Stderr, "changed file %s\n", updatedFile)
}
if len(updates) != 0 {
log.Fatal("go.sum and/or go.mod were updated by running 'go mod tidy'")
} }
fmt.Println("No untidy module files detected.")
} }
// doGenerate ensures that re-generating generated files does not cause // doCheckGenerate ensures that re-generating generated files does not cause
// any mutations in the source file tree: i.e. all generated files were // any mutations in the source file tree.
// updated and committed. Any stale generated files are updated. func doCheckGenerate() {
func doGenerate() {
var ( var (
tc = new(build.GoToolchain)
cachedir = flag.String("cachedir", "./build/cache", "directory for caching binaries.") cachedir = flag.String("cachedir", "./build/cache", "directory for caching binaries.")
verify = flag.Bool("verify", false, "check whether any files are changed by go generate")
) )
// Compute the origin hashes of all the files
var hashes map[string][32]byte
protocPath := downloadProtoc(*cachedir) var err error
protocGenGoPath := downloadProtocGenGo(*cachedir) hashes, err = build.HashFolder(".", []string{"tests/testdata", "build/cache"})
if err != nil {
var preHashes map[string]common.Hash log.Fatal("Error computing hashes", "err", err)
if *verify {
var err error
preHashes, err = hashAllSourceFiles()
if err != nil {
log.Fatal("failed to compute map of source hashes", "err", err)
}
} }
// Run any go generate steps we might be missing
c := tc.Go("generate", "./...") var (
protocPath = downloadProtoc(*cachedir)
protocGenGoPath = downloadProtocGenGo(*cachedir)
)
c := new(build.GoToolchain).Go("generate", "./...")
pathList := []string{filepath.Join(protocPath, "bin"), protocGenGoPath, os.Getenv("PATH")} pathList := []string{filepath.Join(protocPath, "bin"), protocGenGoPath, os.Getenv("PATH")}
c.Env = append(c.Env, "PATH="+strings.Join(pathList, string(os.PathListSeparator))) c.Env = append(c.Env, "PATH="+strings.Join(pathList, string(os.PathListSeparator)))
build.MustRun(c) build.MustRun(c)
if !*verify { // Check if generate file hashes have changed
return generated, err := build.HashFolder(".", []string{"tests/testdata", "build/cache"})
}
// Check if files were changed.
postHashes, err := hashAllSourceFiles()
if err != nil { if err != nil {
log.Fatal("error computing source tree file hashes", "err", err) log.Fatalf("Error re-computing hashes: %v", err)
} }
updates := compareHashedFilesets(preHashes, postHashes) updates := build.DiffHashes(hashes, generated)
for _, updatedFile := range updates { for _, file := range updates {
fmt.Fprintf(os.Stderr, "changed file %s\n", updatedFile) log.Printf("File changed: %s", file)
} }
if len(updates) != 0 { if len(updates) != 0 {
log.Fatal("One or more generated files were updated by running 'go generate ./...'") log.Fatal("One or more generated files were updated by running 'go generate ./...'")
} }
fmt.Println("No stale files detected.")
}
// doCheckBadDeps verifies whether certain unintended dependencies between some
// packages leak into the codebase due to a refactor. This is not an exhaustive
// list, rather something we build up over time at sensitive places.
func doCheckBadDeps() {
baddeps := [][2]string{
// Rawdb tends to be a dumping ground for db utils, sometimes leaking the db itself
{"github.com/ethereum/go-ethereum/core/rawdb", "github.com/ethereum/go-ethereum/ethdb/leveldb"},
{"github.com/ethereum/go-ethereum/core/rawdb", "github.com/ethereum/go-ethereum/ethdb/pebbledb"},
}
tc := new(build.GoToolchain)
var failed bool
for _, rule := range baddeps {
out, err := tc.Go("list", "-deps", rule[0]).CombinedOutput()
if err != nil {
log.Fatalf("Failed to list '%s' dependencies: %v", rule[0], err)
}
for _, line := range strings.Split(string(out), "\n") {
if strings.TrimSpace(line) == rule[1] {
log.Printf("Found bad dependency '%s' -> '%s'", rule[0], rule[1])
failed = true
}
}
}
if failed {
log.Fatalf("Bad dependencies detected.")
}
fmt.Println("No bad dependencies detected.")
} }
// doLint runs golangci-lint on requested packages. // doLint runs golangci-lint on requested packages.
@ -492,8 +458,6 @@ func doLint(cmdline []string) {
linter := downloadLinter(*cachedir) linter := downloadLinter(*cachedir)
lflags := []string{"run", "--config", ".golangci.yml"} lflags := []string{"run", "--config", ".golangci.yml"}
build.MustRunCommandWithOutput(linter, append(lflags, packages...)...) build.MustRunCommandWithOutput(linter, append(lflags, packages...)...)
doGoModTidy()
fmt.Println("You have achieved perfection.") fmt.Println("You have achieved perfection.")
} }
@ -637,7 +601,7 @@ func doArchive(cmdline []string) {
var ( var (
env = build.Env() env = build.Env()
basegeth = archiveBasename(*arch, params.ArchiveVersion(env.Commit)) basegeth = archiveBasename(*arch, version.Archive(env.Commit))
geth = "geth-" + basegeth + ext geth = "geth-" + basegeth + ext
alltools = "geth-alltools-" + basegeth + ext alltools = "geth-alltools-" + basegeth + ext
) )
@ -757,7 +721,7 @@ func doDockerBuildx(cmdline []string) {
case env.Branch == "master": case env.Branch == "master":
tags = []string{"latest"} tags = []string{"latest"}
case strings.HasPrefix(env.Tag, "v1."): case strings.HasPrefix(env.Tag, "v1."):
tags = []string{"stable", fmt.Sprintf("release-1.%d", params.VersionMinor), "v" + params.Version} tags = []string{"stable", fmt.Sprintf("release-%v", version.Family), "v" + version.Semantic}
} }
// Need to create a mult-arch builder // Need to create a mult-arch builder
build.MustRunCommand("docker", "buildx", "create", "--use", "--name", "multi-arch-builder", "--platform", *platform) build.MustRunCommand("docker", "buildx", "create", "--use", "--name", "multi-arch-builder", "--platform", *platform)
@ -773,7 +737,7 @@ func doDockerBuildx(cmdline []string) {
gethImage := fmt.Sprintf("%s%s", spec.base, tag) gethImage := fmt.Sprintf("%s%s", spec.base, tag)
build.MustRunCommand("docker", "buildx", "build", build.MustRunCommand("docker", "buildx", "build",
"--build-arg", "COMMIT="+env.Commit, "--build-arg", "COMMIT="+env.Commit,
"--build-arg", "VERSION="+params.VersionWithMeta, "--build-arg", "VERSION="+version.WithMeta,
"--build-arg", "BUILDNUM="+env.Buildnum, "--build-arg", "BUILDNUM="+env.Buildnum,
"--tag", gethImage, "--tag", gethImage,
"--platform", *platform, "--platform", *platform,
@ -927,15 +891,21 @@ func ppaUpload(workdir, ppa, sshUser string, files []string) {
var idfile string var idfile string
if sshkey := getenvBase64("PPA_SSH_KEY"); len(sshkey) > 0 { if sshkey := getenvBase64("PPA_SSH_KEY"); len(sshkey) > 0 {
idfile = filepath.Join(workdir, "sshkey") idfile = filepath.Join(workdir, "sshkey")
if !common.FileExist(idfile) { if !build.FileExist(idfile) {
os.WriteFile(idfile, sshkey, 0600) os.WriteFile(idfile, sshkey, 0600)
} }
} }
// Upload // Upload. This doesn't always work, so try up to three times.
dest := sshUser + "@ppa.launchpad.net" dest := sshUser + "@ppa.launchpad.net"
if err := build.UploadSFTP(idfile, dest, incomingDir, files); err != nil { for i := 0; i < 3; i++ {
log.Fatal(err) err := build.UploadSFTP(idfile, dest, incomingDir, files)
if err == nil {
return
}
log.Println("PPA upload failed:", err)
time.Sleep(5 * time.Second)
} }
log.Fatal("PPA upload failed all attempts.")
} }
func getenvBase64(variable string) []byte { func getenvBase64(variable string) []byte {
@ -1152,19 +1122,19 @@ func doWindowsInstaller(cmdline []string) {
// Build the installer. This assumes that all the needed files have been previously // Build the installer. This assumes that all the needed files have been previously
// built (don't mix building and packaging to keep cross compilation complexity to a // built (don't mix building and packaging to keep cross compilation complexity to a
// minimum). // minimum).
version := strings.Split(params.Version, ".") ver := strings.Split(version.Semantic, ".")
if env.Commit != "" { if env.Commit != "" {
version[2] += "-" + env.Commit[:8] ver[2] += "-" + env.Commit[:8]
} }
installer, err := filepath.Abs("geth-" + archiveBasename(*arch, params.ArchiveVersion(env.Commit)) + ".exe") installer, err := filepath.Abs("geth-" + archiveBasename(*arch, version.Archive(env.Commit)) + ".exe")
if err != nil { if err != nil {
log.Fatalf("Failed to convert installer file path: %v", err) log.Fatalf("Failed to convert installer file path: %v", err)
} }
build.MustRunCommand("makensis.exe", build.MustRunCommand("makensis.exe",
"/DOUTPUTFILE="+installer, "/DOUTPUTFILE="+installer,
"/DMAJORVERSION="+version[0], "/DMAJORVERSION="+ver[0],
"/DMINORVERSION="+version[1], "/DMINORVERSION="+ver[1],
"/DBUILDVERSION="+version[2], "/DBUILDVERSION="+ver[2],
"/DARCH="+*arch, "/DARCH="+*arch,
filepath.Join(*workdir, "geth.nsi"), filepath.Join(*workdir, "geth.nsi"),
) )

View file

@ -20,6 +20,7 @@ import (
"context" "context"
"fmt" "fmt"
"os" "os"
"slices"
"github.com/ethereum/go-ethereum/beacon/blsync" "github.com/ethereum/go-ethereum/beacon/blsync"
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
@ -33,7 +34,7 @@ import (
func main() { func main() {
app := flags.NewApp("beacon light syncer tool") app := flags.NewApp("beacon light syncer tool")
app.Flags = flags.Merge([]cli.Flag{ app.Flags = slices.Concat([]cli.Flag{
utils.BeaconApiFlag, utils.BeaconApiFlag,
utils.BeaconApiHeaderFlag, utils.BeaconApiHeaderFlag,
utils.BeaconThresholdFlag, utils.BeaconThresholdFlag,
@ -45,6 +46,7 @@ func main() {
//TODO datadir for optional permanent database //TODO datadir for optional permanent database
utils.MainnetFlag, utils.MainnetFlag,
utils.SepoliaFlag, utils.SepoliaFlag,
utils.HoleskyFlag,
utils.BlsyncApiFlag, utils.BlsyncApiFlag,
utils.BlsyncJWTSecretFlag, utils.BlsyncJWTSecretFlag,
}, },
@ -68,7 +70,7 @@ func main() {
func sync(ctx *cli.Context) error { func sync(ctx *cli.Context) error {
// set up blsync // set up blsync
client := blsync.NewClient(ctx) client := blsync.NewClient(utils.MakeBeaconLightConfig(ctx))
client.SetEngineRPC(makeRPCClient(ctx)) client.SetEngineRPC(makeRPCClient(ctx))
client.Start() client.Start()

View file

@ -21,6 +21,7 @@ import (
"fmt" "fmt"
"net" "net"
"net/http" "net/http"
"slices"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -30,7 +31,6 @@ import (
"github.com/ethereum/go-ethereum/cmd/devp2p/internal/v4test" "github.com/ethereum/go-ethereum/cmd/devp2p/internal/v4test"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
@ -84,7 +84,7 @@ var (
Name: "listen", Name: "listen",
Usage: "Runs a discovery node", Usage: "Runs a discovery node",
Action: discv4Listen, Action: discv4Listen,
Flags: flags.Merge(discoveryNodeFlags, []cli.Flag{ Flags: slices.Concat(discoveryNodeFlags, []cli.Flag{
httpAddrFlag, httpAddrFlag,
}), }),
} }
@ -92,7 +92,7 @@ var (
Name: "crawl", Name: "crawl",
Usage: "Updates a nodes.json file with random nodes found in the DHT", Usage: "Updates a nodes.json file with random nodes found in the DHT",
Action: discv4Crawl, Action: discv4Crawl,
Flags: flags.Merge(discoveryNodeFlags, []cli.Flag{crawlTimeoutFlag, crawlParallelismFlag}), Flags: slices.Concat(discoveryNodeFlags, []cli.Flag{crawlTimeoutFlag, crawlParallelismFlag}),
} }
discv4TestCommand = &cli.Command{ discv4TestCommand = &cli.Command{
Name: "test", Name: "test",

View file

@ -19,13 +19,13 @@ package main
import ( import (
"errors" "errors"
"fmt" "fmt"
"slices"
"time" "time"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum/cmd/devp2p/internal/v5test" "github.com/ethereum/go-ethereum/cmd/devp2p/internal/v5test"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/discover"
) )
@ -57,7 +57,7 @@ var (
Name: "crawl", Name: "crawl",
Usage: "Updates a nodes.json file with random nodes found in the DHT", Usage: "Updates a nodes.json file with random nodes found in the DHT",
Action: discv5Crawl, Action: discv5Crawl,
Flags: flags.Merge(discoveryNodeFlags, []cli.Flag{ Flags: slices.Concat(discoveryNodeFlags, []cli.Flag{
crawlTimeoutFlag, crawlTimeoutFlag,
}), }),
} }

View file

@ -100,7 +100,6 @@ func (c *Chain) AccountsInHashOrder() []state.DumpAccount {
list := make([]state.DumpAccount, len(c.state)) list := make([]state.DumpAccount, len(c.state))
i := 0 i := 0
for addr, acc := range c.state { for addr, acc := range c.state {
addr := addr
list[i] = acc list[i] = acc
list[i].Address = &addr list[i].Address = &addr
if len(acc.AddressHash) != 32 { if len(acc.AddressHash) != 32 {

View file

@ -288,7 +288,6 @@ a key before startingHash (wrong order). The server should return the first avai
} }
for i, tc := range tests { for i, tc := range tests {
tc := tc
if i > 0 { if i > 0 {
t.Log("\n") t.Log("\n")
} }
@ -431,7 +430,6 @@ of the test account. The server should return slots [2,3] (i.e. the 'next availa
} }
for i, tc := range tests { for i, tc := range tests {
tc := tc
if i > 0 { if i > 0 {
t.Log("\n") t.Log("\n")
} }
@ -528,7 +526,6 @@ func (s *Suite) TestSnapGetByteCodes(t *utesting.T) {
} }
for i, tc := range tests { for i, tc := range tests {
tc := tc
if i > 0 { if i > 0 {
t.Log("\n") t.Log("\n")
} }
@ -734,7 +731,6 @@ The server should reject the request.`,
} }
for i, tc := range tests { for i, tc := range tests {
tc := tc
if i > 0 { if i > 0 {
t.Log("\n") t.Log("\n")
} }

View file

@ -18,7 +18,6 @@
"shanghaiTime": 780, "shanghaiTime": 780,
"cancunTime": 840, "cancunTime": 840,
"terminalTotalDifficulty": 9454784, "terminalTotalDifficulty": 9454784,
"terminalTotalDifficultyPassed": true,
"ethash": {} "ethash": {}
}, },
"nonce": "0x0", "nonce": "0x0",

200
cmd/evm/eofparse.go Normal file
View file

@ -0,0 +1,200 @@
// Copyright 2023 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"bufio"
"encoding/hex"
"encoding/json"
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/log"
"github.com/urfave/cli/v2"
)
func init() {
jt = vm.NewPragueEOFInstructionSetForTesting()
}
var (
jt vm.JumpTable
initcode = "INITCODE"
)
func eofParseAction(ctx *cli.Context) error {
// If `--test` is set, parse and validate the reference test at the provided path.
if ctx.IsSet(refTestFlag.Name) {
var (
file = ctx.String(refTestFlag.Name)
executedTests int
passedTests int
)
err := filepath.Walk(file, func(path string, info fs.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
log.Debug("Executing test", "name", info.Name())
passed, tot, err := executeTest(path)
passedTests += passed
executedTests += tot
return err
})
if err != nil {
return err
}
log.Info("Executed tests", "passed", passedTests, "total executed", executedTests)
return nil
}
// If `--hex` is set, parse and validate the hex string argument.
if ctx.IsSet(hexFlag.Name) {
if _, err := parseAndValidate(ctx.String(hexFlag.Name), false); err != nil {
return fmt.Errorf("err: %w", err)
}
fmt.Println("OK")
return nil
}
// If neither are passed in, read input from stdin.
scanner := bufio.NewScanner(os.Stdin)
scanner.Buffer(make([]byte, 1024*1024), 10*1024*1024)
for scanner.Scan() {
l := strings.TrimSpace(scanner.Text())
if strings.HasPrefix(l, "#") || l == "" {
continue
}
if _, err := parseAndValidate(l, false); err != nil {
fmt.Printf("err: %v\n", err)
} else {
fmt.Println("OK")
}
}
if err := scanner.Err(); err != nil {
fmt.Println(err.Error())
}
return nil
}
type refTests struct {
Vectors map[string]eOFTest `json:"vectors"`
}
type eOFTest struct {
Code string `json:"code"`
Results map[string]etResult `json:"results"`
ContainerKind string `json:"containerKind"`
}
type etResult struct {
Result bool `json:"result"`
Exception string `json:"exception,omitempty"`
}
func executeTest(path string) (int, int, error) {
src, err := os.ReadFile(path)
if err != nil {
return 0, 0, err
}
var testsByName map[string]refTests
if err := json.Unmarshal(src, &testsByName); err != nil {
return 0, 0, err
}
passed, total := 0, 0
for testsName, tests := range testsByName {
for name, tt := range tests.Vectors {
for fork, r := range tt.Results {
total++
_, err := parseAndValidate(tt.Code, tt.ContainerKind == initcode)
if r.Result && err != nil {
log.Error("Test failure, expected validation success", "name", testsName, "idx", name, "fork", fork, "err", err)
continue
}
if !r.Result && err == nil {
log.Error("Test failure, expected validation error", "name", testsName, "idx", name, "fork", fork, "have err", r.Exception, "err", err)
continue
}
passed++
}
}
}
return passed, total, nil
}
func parseAndValidate(s string, isInitCode bool) (*vm.Container, error) {
if len(s) >= 2 && strings.HasPrefix(s, "0x") {
s = s[2:]
}
b, err := hex.DecodeString(s)
if err != nil {
return nil, fmt.Errorf("unable to decode data: %w", err)
}
return parse(b, isInitCode)
}
func parse(b []byte, isInitCode bool) (*vm.Container, error) {
var c vm.Container
if err := c.UnmarshalBinary(b, isInitCode); err != nil {
return nil, err
}
if err := c.ValidateCode(&jt, isInitCode); err != nil {
return nil, err
}
return &c, nil
}
func eofDumpAction(ctx *cli.Context) error {
// If `--hex` is set, parse and validate the hex string argument.
if ctx.IsSet(hexFlag.Name) {
return eofDump(ctx.String(hexFlag.Name))
}
// Otherwise read from stdin
scanner := bufio.NewScanner(os.Stdin)
scanner.Buffer(make([]byte, 1024*1024), 10*1024*1024)
for scanner.Scan() {
l := strings.TrimSpace(scanner.Text())
if strings.HasPrefix(l, "#") || l == "" {
continue
}
if err := eofDump(l); err != nil {
return err
}
fmt.Println("")
}
return scanner.Err()
}
func eofDump(hexdata string) error {
if len(hexdata) >= 2 && strings.HasPrefix(hexdata, "0x") {
hexdata = hexdata[2:]
}
b, err := hex.DecodeString(hexdata)
if err != nil {
return fmt.Errorf("unable to decode data: %w", err)
}
var c vm.Container
if err := c.UnmarshalBinary(b, false); err != nil {
return err
}
fmt.Println(c.String())
return nil
}

166
cmd/evm/eofparse_test.go Normal file
View file

@ -0,0 +1,166 @@
package main
import (
"bufio"
"bytes"
"encoding/hex"
"fmt"
"os"
"strings"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
)
func FuzzEofParsing(f *testing.F) {
// Seed with corpus from execution-spec-tests
for i := 0; ; i++ {
fname := fmt.Sprintf("testdata/eof/eof_corpus_%d.txt", i)
corpus, err := os.Open(fname)
if err != nil {
break
}
f.Logf("Reading seed data from %v", fname)
scanner := bufio.NewScanner(corpus)
scanner.Buffer(make([]byte, 1024), 10*1024*1024)
for scanner.Scan() {
s := scanner.Text()
if len(s) >= 2 && strings.HasPrefix(s, "0x") {
s = s[2:]
}
b, err := hex.DecodeString(s)
if err != nil {
panic(err) // rotten corpus
}
f.Add(b)
}
corpus.Close()
if err := scanner.Err(); err != nil {
panic(err) // rotten corpus
}
}
// And do the fuzzing
f.Fuzz(func(t *testing.T, data []byte) {
var (
jt = vm.NewPragueEOFInstructionSetForTesting()
c vm.Container
)
cpy := common.CopyBytes(data)
if err := c.UnmarshalBinary(data, true); err == nil {
c.ValidateCode(&jt, true)
if have := c.MarshalBinary(); !bytes.Equal(have, data) {
t.Fatal("Unmarshal-> Marshal failure!")
}
}
if err := c.UnmarshalBinary(data, false); err == nil {
c.ValidateCode(&jt, false)
if have := c.MarshalBinary(); !bytes.Equal(have, data) {
t.Fatal("Unmarshal-> Marshal failure!")
}
}
if !bytes.Equal(cpy, data) {
panic("data modified during unmarshalling")
}
})
}
func TestEofParseInitcode(t *testing.T) {
testEofParse(t, true, "testdata/eof/results.initcode.txt")
}
func TestEofParseRegular(t *testing.T) {
testEofParse(t, false, "testdata/eof/results.regular.txt")
}
func testEofParse(t *testing.T, isInitCode bool, wantFile string) {
var wantFn func() string
var wantLoc = 0
{ // Configure the want-reader
wants, err := os.Open(wantFile)
if err != nil {
t.Fatal(err)
}
scanner := bufio.NewScanner(wants)
scanner.Buffer(make([]byte, 1024), 10*1024*1024)
wantFn = func() string {
if scanner.Scan() {
wantLoc++
return scanner.Text()
}
return "end of file reached"
}
}
for i := 0; ; i++ {
fname := fmt.Sprintf("testdata/eof/eof_corpus_%d.txt", i)
corpus, err := os.Open(fname)
if err != nil {
break
}
t.Logf("# Reading seed data from %v", fname)
scanner := bufio.NewScanner(corpus)
scanner.Buffer(make([]byte, 1024), 10*1024*1024)
line := 1
for scanner.Scan() {
s := scanner.Text()
if len(s) >= 2 && strings.HasPrefix(s, "0x") {
s = s[2:]
}
b, err := hex.DecodeString(s)
if err != nil {
panic(err) // rotten corpus
}
have := "OK"
if _, err := parse(b, isInitCode); err != nil {
have = fmt.Sprintf("ERR: %v", err)
}
if false { // Change this to generate the want-output
fmt.Printf("%v\n", have)
} else {
want := wantFn()
if have != want {
if len(want) > 100 {
want = want[:100]
}
if len(b) > 100 {
b = b[:100]
}
t.Errorf("%v:%d\n%v\ninput %x\nisInit: %v\nhave: %q\nwant: %q\n",
fname, line, fmt.Sprintf("%v:%d", wantFile, wantLoc), b, isInitCode, have, want)
}
}
line++
}
corpus.Close()
}
}
func BenchmarkEofParse(b *testing.B) {
corpus, err := os.Open("testdata/eof/eof_benches.txt")
if err != nil {
b.Fatal(err)
}
defer corpus.Close()
scanner := bufio.NewScanner(corpus)
scanner.Buffer(make([]byte, 1024), 10*1024*1024)
line := 1
for scanner.Scan() {
s := scanner.Text()
if len(s) >= 2 && strings.HasPrefix(s, "0x") {
s = s[2:]
}
data, err := hex.DecodeString(s)
if err != nil {
b.Fatal(err) // rotten corpus
}
b.Run(fmt.Sprintf("test-%d", line), func(b *testing.B) {
b.ReportAllocs()
b.SetBytes(int64(len(data)))
for i := 0; i < b.N; i++ {
_, _ = parse(data, false)
}
})
line++
}
}

View file

@ -23,6 +23,7 @@ import (
"math/big" "math/big"
"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/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/consensus/misc"
@ -50,6 +51,8 @@ type Prestate struct {
Pre types.GenesisAlloc `json:"pre"` Pre types.GenesisAlloc `json:"pre"`
} }
//go:generate go run github.com/fjl/gencodec -type ExecutionResult -field-override executionResultMarshaling -out gen_execresult.go
// ExecutionResult contains the execution status after running a state test, any // ExecutionResult contains the execution status after running a state test, any
// error that might have occurred and a dump of the final state if requested. // error that might have occurred and a dump of the final state if requested.
type ExecutionResult struct { type ExecutionResult struct {
@ -66,8 +69,12 @@ type ExecutionResult struct {
WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"` WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"`
CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"` CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"`
CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"` CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"`
RequestsHash *common.Hash `json:"requestsRoot,omitempty"` RequestsHash *common.Hash `json:"requestsHash,omitempty"`
DepositRequests *types.Deposits `json:"depositRequests,omitempty"` Requests [][]byte `json:"requests,omitempty"`
}
type executionResultMarshaling struct {
Requests []hexutil.Bytes `json:"requests,omitempty"`
} }
type ommer struct { type ommer struct {
@ -125,7 +132,7 @@ type rejectedTx struct {
// Apply applies a set of transactions to a pre-state // Apply applies a set of transactions to a pre-state
func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
txIt txIterator, miningReward int64, txIt txIterator, miningReward int64,
getTracerFn func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error)) (*state.StateDB, *ExecutionResult, []byte, error) { getTracerFn func(txIndex int, txHash common.Hash, chainConfig *params.ChainConfig) (*tracers.Tracer, io.WriteCloser, error)) (*state.StateDB, *ExecutionResult, []byte, error) {
// Capture errors for BLOCKHASH operation, if we haven't been supplied the // Capture errors for BLOCKHASH operation, if we haven't been supplied the
// required blockhashes // required blockhashes
var hashError error var hashError error
@ -241,7 +248,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
continue continue
} }
} }
tracer, traceOutput, err := getTracerFn(txIndex, tx.Hash()) tracer, traceOutput, err := getTracerFn(txIndex, tx.Hash(), chainConfig)
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }
@ -367,6 +374,28 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei)) amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei))
statedb.AddBalance(w.Address, uint256.MustFromBig(amount), tracing.BalanceIncreaseWithdrawal) statedb.AddBalance(w.Address, uint256.MustFromBig(amount), tracing.BalanceIncreaseWithdrawal)
} }
// Gather the execution-layer triggered requests.
var requests [][]byte
if chainConfig.IsPrague(vmContext.BlockNumber, vmContext.Time) {
// EIP-6110 deposits
var allLogs []*types.Log
for _, receipt := range receipts {
allLogs = append(allLogs, receipt.Logs...)
}
depositRequests, err := core.ParseDepositLogs(allLogs, chainConfig)
if err != nil {
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not parse requests logs: %v", err))
}
requests = append(requests, depositRequests)
// create EVM for system calls
vmenv := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{})
// EIP-7002 withdrawals
requests = append(requests, core.ProcessWithdrawalQueue(vmenv, statedb))
// EIP-7251 consolidations
requests = append(requests, core.ProcessConsolidationQueue(vmenv, statedb))
}
// Commit block // Commit block
root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber)) root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber))
if err != nil { if err != nil {
@ -394,28 +423,17 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
execRs.CurrentExcessBlobGas = (*math.HexOrDecimal64)(&excessBlobGas) execRs.CurrentExcessBlobGas = (*math.HexOrDecimal64)(&excessBlobGas)
execRs.CurrentBlobGasUsed = (*math.HexOrDecimal64)(&blobGasUsed) execRs.CurrentBlobGasUsed = (*math.HexOrDecimal64)(&blobGasUsed)
} }
if chainConfig.IsPrague(vmContext.BlockNumber) && chainConfig.Bor == nil { if requests != nil {
// Parse the requests from the logs // Set requestsHash on block.
var allLogs []*types.Log h := types.CalcRequestsHash(requests)
for _, receipt := range receipts {
allLogs = append(allLogs, receipt.Logs...)
}
requests, err := core.ParseDepositLogs(allLogs, chainConfig)
if err != nil {
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not parse requests logs: %v", err))
}
// Calculate the requests root
h := types.DeriveSha(requests, trie.NewStackTrie(nil))
execRs.RequestsHash = &h execRs.RequestsHash = &h
// Get the deposits from the requests for i := range requests {
deposits := make(types.Deposits, 0) // remove prefix
for _, req := range requests { requests[i] = requests[i][1:]
if dep, ok := req.Inner().(*types.Deposit); ok {
deposits = append(deposits, dep)
}
} }
execRs.DepositRequests = &deposits execRs.Requests = requests
} }
// Re-create statedb instance with new root upon the updated database // Re-create statedb instance with new root upon the updated database
// for accessing latest states. // for accessing latest states.
statedb, err = state.New(root, statedb.Database()) statedb, err = state.New(root, statedb.Database())

View file

@ -0,0 +1,134 @@
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
package t8ntool
import (
"encoding/json"
"errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/types"
)
var _ = (*executionResultMarshaling)(nil)
// MarshalJSON marshals as JSON.
func (e ExecutionResult) MarshalJSON() ([]byte, error) {
type ExecutionResult struct {
StateRoot common.Hash `json:"stateRoot"`
TxRoot common.Hash `json:"txRoot"`
ReceiptRoot common.Hash `json:"receiptsRoot"`
LogsHash common.Hash `json:"logsHash"`
Bloom types.Bloom `json:"logsBloom" gencodec:"required"`
Receipts types.Receipts `json:"receipts"`
Rejected []*rejectedTx `json:"rejected,omitempty"`
Difficulty *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"`
GasUsed math.HexOrDecimal64 `json:"gasUsed"`
BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"`
WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"`
CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"`
CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"`
RequestsHash *common.Hash `json:"requestsHash,omitempty"`
Requests []hexutil.Bytes `json:"requests,omitempty"`
}
var enc ExecutionResult
enc.StateRoot = e.StateRoot
enc.TxRoot = e.TxRoot
enc.ReceiptRoot = e.ReceiptRoot
enc.LogsHash = e.LogsHash
enc.Bloom = e.Bloom
enc.Receipts = e.Receipts
enc.Rejected = e.Rejected
enc.Difficulty = e.Difficulty
enc.GasUsed = e.GasUsed
enc.BaseFee = e.BaseFee
enc.WithdrawalsRoot = e.WithdrawalsRoot
enc.CurrentExcessBlobGas = e.CurrentExcessBlobGas
enc.CurrentBlobGasUsed = e.CurrentBlobGasUsed
enc.RequestsHash = e.RequestsHash
if e.Requests != nil {
enc.Requests = make([]hexutil.Bytes, len(e.Requests))
for k, v := range e.Requests {
enc.Requests[k] = v
}
}
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
func (e *ExecutionResult) UnmarshalJSON(input []byte) error {
type ExecutionResult struct {
StateRoot *common.Hash `json:"stateRoot"`
TxRoot *common.Hash `json:"txRoot"`
ReceiptRoot *common.Hash `json:"receiptsRoot"`
LogsHash *common.Hash `json:"logsHash"`
Bloom *types.Bloom `json:"logsBloom" gencodec:"required"`
Receipts *types.Receipts `json:"receipts"`
Rejected []*rejectedTx `json:"rejected,omitempty"`
Difficulty *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"`
GasUsed *math.HexOrDecimal64 `json:"gasUsed"`
BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"`
WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"`
CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"`
CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"`
RequestsHash *common.Hash `json:"requestsHash,omitempty"`
Requests []hexutil.Bytes `json:"requests,omitempty"`
}
var dec ExecutionResult
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.StateRoot != nil {
e.StateRoot = *dec.StateRoot
}
if dec.TxRoot != nil {
e.TxRoot = *dec.TxRoot
}
if dec.ReceiptRoot != nil {
e.ReceiptRoot = *dec.ReceiptRoot
}
if dec.LogsHash != nil {
e.LogsHash = *dec.LogsHash
}
if dec.Bloom == nil {
return errors.New("missing required field 'logsBloom' for ExecutionResult")
}
e.Bloom = *dec.Bloom
if dec.Receipts != nil {
e.Receipts = *dec.Receipts
}
if dec.Rejected != nil {
e.Rejected = dec.Rejected
}
if dec.Difficulty == nil {
return errors.New("missing required field 'currentDifficulty' for ExecutionResult")
}
e.Difficulty = dec.Difficulty
if dec.GasUsed != nil {
e.GasUsed = *dec.GasUsed
}
if dec.BaseFee != nil {
e.BaseFee = dec.BaseFee
}
if dec.WithdrawalsRoot != nil {
e.WithdrawalsRoot = dec.WithdrawalsRoot
}
if dec.CurrentExcessBlobGas != nil {
e.CurrentExcessBlobGas = dec.CurrentExcessBlobGas
}
if dec.CurrentBlobGasUsed != nil {
e.CurrentBlobGasUsed = dec.CurrentBlobGasUsed
}
if dec.RequestsHash != nil {
e.RequestsHash = dec.RequestsHash
}
if dec.Requests != nil {
e.Requests = make([][]byte, len(dec.Requests))
for k, v := range dec.Requests {
e.Requests[k] = v
}
}
return nil
}

View file

@ -84,7 +84,9 @@ type input struct {
} }
func Transition(ctx *cli.Context) error { func Transition(ctx *cli.Context) error {
var getTracer = func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error) { return nil, nil, nil } var getTracer = func(txIndex int, txHash common.Hash, chainConfig *params.ChainConfig) (*tracers.Tracer, io.WriteCloser, error) {
return nil, nil, nil
}
baseDir, err := createBasedir(ctx) baseDir, err := createBasedir(ctx)
if err != nil { if err != nil {
@ -99,7 +101,7 @@ func Transition(ctx *cli.Context) error {
EnableReturnData: ctx.Bool(TraceEnableReturnDataFlag.Name), EnableReturnData: ctx.Bool(TraceEnableReturnDataFlag.Name),
Debug: true, Debug: true,
} }
getTracer = func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error) { getTracer = func(txIndex int, txHash common.Hash, _ *params.ChainConfig) (*tracers.Tracer, io.WriteCloser, error) {
traceFile, err := os.Create(filepath.Join(baseDir, fmt.Sprintf("trace-%d-%v.jsonl", txIndex, txHash.String()))) traceFile, err := os.Create(filepath.Join(baseDir, fmt.Sprintf("trace-%d-%v.jsonl", txIndex, txHash.String())))
if err != nil { if err != nil {
return nil, nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) return nil, nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err))
@ -123,12 +125,12 @@ func Transition(ctx *cli.Context) error {
if ctx.IsSet(TraceTracerConfigFlag.Name) { if ctx.IsSet(TraceTracerConfigFlag.Name) {
config = []byte(ctx.String(TraceTracerConfigFlag.Name)) config = []byte(ctx.String(TraceTracerConfigFlag.Name))
} }
getTracer = func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error) { getTracer = func(txIndex int, txHash common.Hash, chainConfig *params.ChainConfig) (*tracers.Tracer, io.WriteCloser, error) {
traceFile, err := os.Create(filepath.Join(baseDir, fmt.Sprintf("trace-%d-%v.json", txIndex, txHash.String()))) traceFile, err := os.Create(filepath.Join(baseDir, fmt.Sprintf("trace-%d-%v.json", txIndex, txHash.String())))
if err != nil { if err != nil {
return nil, nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) return nil, nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err))
} }
tracer, err := tracers.DefaultDirectory.New(ctx.String(TraceTracerFlag.Name), nil, config) tracer, err := tracers.DefaultDirectory.New(ctx.String(TraceTracerFlag.Name), nil, config, chainConfig)
if err != nil { if err != nil {
return nil, nil, NewError(ErrorConfig, fmt.Errorf("failed instantiating tracer: %w", err)) return nil, nil, NewError(ErrorConfig, fmt.Errorf("failed instantiating tracer: %w", err))
} }

View file

@ -21,6 +21,7 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"os" "os"
"slices"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
@ -139,61 +140,90 @@ var (
Usage: "enable return data output", Usage: "enable return data output",
Category: flags.VMCategory, Category: flags.VMCategory,
} }
refTestFlag = &cli.StringFlag{
Name: "test",
Usage: "Path to EOF validation reference test.",
}
hexFlag = &cli.StringFlag{
Name: "hex",
Usage: "single container data parse and validation",
}
) )
var stateTransitionCommand = &cli.Command{ var (
Name: "transition", stateTransitionCommand = &cli.Command{
Aliases: []string{"t8n"}, Name: "transition",
Usage: "Executes a full state transition", Aliases: []string{"t8n"},
Action: t8ntool.Transition, Usage: "Executes a full state transition",
Flags: []cli.Flag{ Action: t8ntool.Transition,
t8ntool.TraceFlag, Flags: []cli.Flag{
t8ntool.TraceTracerFlag, t8ntool.TraceFlag,
t8ntool.TraceTracerConfigFlag, t8ntool.TraceTracerFlag,
t8ntool.TraceEnableMemoryFlag, t8ntool.TraceTracerConfigFlag,
t8ntool.TraceDisableStackFlag, t8ntool.TraceEnableMemoryFlag,
t8ntool.TraceEnableReturnDataFlag, t8ntool.TraceDisableStackFlag,
t8ntool.TraceEnableCallFramesFlag, t8ntool.TraceEnableReturnDataFlag,
t8ntool.OutputBasedir, t8ntool.TraceEnableCallFramesFlag,
t8ntool.OutputAllocFlag, t8ntool.OutputBasedir,
t8ntool.OutputResultFlag, t8ntool.OutputAllocFlag,
t8ntool.OutputBodyFlag, t8ntool.OutputResultFlag,
t8ntool.InputAllocFlag, t8ntool.OutputBodyFlag,
t8ntool.InputEnvFlag, t8ntool.InputAllocFlag,
t8ntool.InputTxsFlag, t8ntool.InputEnvFlag,
t8ntool.ForknameFlag, t8ntool.InputTxsFlag,
t8ntool.ChainIDFlag, t8ntool.ForknameFlag,
t8ntool.RewardFlag, t8ntool.ChainIDFlag,
}, t8ntool.RewardFlag,
} },
}
var transactionCommand = &cli.Command{ transactionCommand = &cli.Command{
Name: "transaction", Name: "transaction",
Aliases: []string{"t9n"}, Aliases: []string{"t9n"},
Usage: "Performs transaction validation", Usage: "Performs transaction validation",
Action: t8ntool.Transaction, Action: t8ntool.Transaction,
Flags: []cli.Flag{ Flags: []cli.Flag{
t8ntool.InputTxsFlag, t8ntool.InputTxsFlag,
t8ntool.ChainIDFlag, t8ntool.ChainIDFlag,
t8ntool.ForknameFlag, t8ntool.ForknameFlag,
}, },
} }
var blockBuilderCommand = &cli.Command{ blockBuilderCommand = &cli.Command{
Name: "block-builder", Name: "block-builder",
Aliases: []string{"b11r"}, Aliases: []string{"b11r"},
Usage: "Builds a block", Usage: "Builds a block",
Action: t8ntool.BuildBlock, Action: t8ntool.BuildBlock,
Flags: []cli.Flag{ Flags: []cli.Flag{
t8ntool.OutputBasedir, t8ntool.OutputBasedir,
t8ntool.OutputBlockFlag, t8ntool.OutputBlockFlag,
t8ntool.InputHeaderFlag, t8ntool.InputHeaderFlag,
t8ntool.InputOmmersFlag, t8ntool.InputOmmersFlag,
t8ntool.InputWithdrawalsFlag, t8ntool.InputWithdrawalsFlag,
t8ntool.InputTxsRlpFlag, t8ntool.InputTxsRlpFlag,
t8ntool.SealCliqueFlag, t8ntool.SealCliqueFlag,
}, },
} }
eofParseCommand = &cli.Command{
Name: "eofparse",
Aliases: []string{"eof"},
Usage: "Parses hex eof container and returns validation errors (if any)",
Action: eofParseAction,
Flags: []cli.Flag{
hexFlag,
refTestFlag,
},
}
eofDumpCommand = &cli.Command{
Name: "eofdump",
Usage: "Parses hex eof container and prints out human-readable representation of the container.",
Action: eofDumpAction,
Flags: []cli.Flag{
hexFlag,
},
}
)
// vmFlags contains flags related to running the EVM. // vmFlags contains flags related to running the EVM.
var vmFlags = []cli.Flag{ var vmFlags = []cli.Flag{
@ -226,7 +256,7 @@ var traceFlags = []cli.Flag{
var app = flags.NewApp("the evm command line interface") var app = flags.NewApp("the evm command line interface")
func init() { func init() {
app.Flags = flags.Merge(vmFlags, traceFlags, debug.Flags) app.Flags = slices.Concat(vmFlags, traceFlags, debug.Flags)
app.Commands = []*cli.Command{ app.Commands = []*cli.Command{
compileCommand, compileCommand,
disasmCommand, disasmCommand,
@ -236,6 +266,8 @@ func init() {
stateTransitionCommand, stateTransitionCommand,
transactionCommand, transactionCommand,
blockBuilderCommand, blockBuilderCommand,
eofParseCommand,
eofDumpCommand,
} }
app.Before = func(ctx *cli.Context) error { app.Before = func(ctx *cli.Context) error {
flags.MigrateGlobalFlags(ctx) flags.MigrateGlobalFlags(ctx)

View file

@ -24,6 +24,7 @@ import (
"math/big" "math/big"
"os" "os"
goruntime "runtime" goruntime "runtime"
"slices"
"testing" "testing"
"time" "time"
@ -51,7 +52,7 @@ var runCommand = &cli.Command{
Usage: "Run arbitrary evm binary", Usage: "Run arbitrary evm binary",
ArgsUsage: "<code>", ArgsUsage: "<code>",
Description: `The run command runs arbitrary EVM code.`, Description: `The run command runs arbitrary EVM code.`,
Flags: flags.Merge(vmFlags, traceFlags), Flags: slices.Concat(vmFlags, traceFlags),
} }
// readGenesis will read the given JSON format genesis file and return // readGenesis will read the given JSON format genesis file and return
@ -79,19 +80,30 @@ func readGenesis(genesisPath string) *core.Genesis {
} }
type execStats struct { type execStats struct {
time time.Duration // The execution time. Time time.Duration `json:"time"` // The execution Time.
allocs int64 // The number of heap allocations during execution. Allocs int64 `json:"allocs"` // The number of heap allocations during execution.
bytesAllocated int64 // The cumulative number of bytes allocated during execution. BytesAllocated int64 `json:"bytesAllocated"` // The cumulative number of bytes allocated during execution.
GasUsed uint64 `json:"gasUsed"` // the amount of gas used during execution
} }
func timedExec(bench bool, execFunc func() ([]byte, uint64, error)) (output []byte, gasLeft uint64, stats execStats, err error) { func timedExec(bench bool, execFunc func() ([]byte, uint64, error)) ([]byte, execStats, error) {
if bench { if bench {
// Do one warm-up run
output, gasUsed, err := execFunc()
result := testing.Benchmark(func(b *testing.B) { result := testing.Benchmark(func(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
output, gasLeft, err = execFunc() haveOutput, haveGasUsed, haveErr := execFunc()
if !bytes.Equal(haveOutput, output) {
b.Fatalf("output differs, have\n%x\nwant%x\n", haveOutput, output)
}
if haveGasUsed != gasUsed {
b.Fatalf("gas differs, have %v want%v", haveGasUsed, gasUsed)
}
if haveErr != err {
b.Fatalf("err differs, have %v want%v", haveErr, err)
}
} }
}) })
// Get the average execution time from the benchmarking result. // Get the average execution time from the benchmarking result.
// There are other useful stats here that could be reported. // There are other useful stats here that could be reported.
stats.time = time.Duration(result.NsPerOp()) stats.time = time.Duration(result.NsPerOp())
@ -110,8 +122,19 @@ func timedExec(bench bool, execFunc func() ([]byte, uint64, error)) (output []by
stats.allocs = int64(memStatsAfter.Mallocs - memStatsBefore.Mallocs) stats.allocs = int64(memStatsAfter.Mallocs - memStatsBefore.Mallocs)
stats.bytesAllocated = int64(memStatsAfter.TotalAlloc - memStatsBefore.TotalAlloc) stats.bytesAllocated = int64(memStatsAfter.TotalAlloc - memStatsBefore.TotalAlloc)
} }
var memStatsBefore, memStatsAfter goruntime.MemStats
return output, gasLeft, stats, err goruntime.ReadMemStats(&memStatsBefore)
t0 := time.Now()
output, gasUsed, err := execFunc()
duration := time.Since(t0)
goruntime.ReadMemStats(&memStatsAfter)
stats := execStats{
Time: duration,
Allocs: int64(memStatsAfter.Mallocs - memStatsBefore.Mallocs),
BytesAllocated: int64(memStatsAfter.TotalAlloc - memStatsBefore.TotalAlloc),
GasUsed: gasUsed,
}
return output, stats, err
} }
func runCmd(ctx *cli.Context) error { func runCmd(ctx *cli.Context) error {
@ -284,12 +307,13 @@ func runCmd(ctx *cli.Context) error {
} }
execFunc = func() ([]byte, uint64, error) { execFunc = func() ([]byte, uint64, error) {
return runtime.Call(receiver, input, &runtimeConfig) output, gasLeft, err := runtime.Call(receiver, input, &runtimeConfig)
return output, initialGas - gasLeft, err
} }
} }
bench := ctx.Bool(BenchFlag.Name) bench := ctx.Bool(BenchFlag.Name)
output, leftOverGas, stats, err := timedExec(bench, execFunc) output, stats, err := timedExec(bench, execFunc)
if ctx.Bool(DumpFlag.Name) { if ctx.Bool(DumpFlag.Name) {
root, err := statedb.Commit(genesisConfig.Number, true) root, err := statedb.Commit(genesisConfig.Number, true)
@ -320,7 +344,7 @@ func runCmd(ctx *cli.Context) error {
execution time: %v execution time: %v
allocations: %d allocations: %d
allocated bytes: %d allocated bytes: %d
`, initialGas-leftOverGas, stats.time, stats.allocs, stats.bytesAllocated) `, stats.GasUsed, stats.Time, stats.Allocs, stats.BytesAllocated)
} }
if tracer == nil { if tracer == nil {

View file

@ -29,25 +29,50 @@ import (
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/eth/tracers/logger"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/tests" "github.com/ethereum/go-ethereum/tests"
) )
var (
forkFlag = &cli.StringFlag{
Name: "statetest.fork",
Usage: "The hard-fork to run the test against",
Category: flags.VMCategory,
}
idxFlag = &cli.IntFlag{
Name: "statetest.index",
Usage: "The index of the subtest to run",
Category: flags.VMCategory,
Value: -1, // default to select all subtest indices
}
testNameFlag = &cli.StringFlag{
Name: "statetest.name",
Usage: "The name of the state test to run",
Category: flags.VMCategory,
}
)
var stateTestCommand = &cli.Command{ var stateTestCommand = &cli.Command{
Action: stateTestCmd, Action: stateTestCmd,
Name: "statetest", Name: "statetest",
Usage: "Executes the given state tests. Filenames can be fed via standard input (batch mode) or as an argument (one-off execution).", Usage: "Executes the given state tests. Filenames can be fed via standard input (batch mode) or as an argument (one-off execution).",
ArgsUsage: "<file>", ArgsUsage: "<file>",
Flags: []cli.Flag{
forkFlag,
idxFlag,
testNameFlag,
},
} }
// StatetestResult contains the execution status after running a state test, any // StatetestResult contains the execution status after running a state test, any
// error that might have occurred and a dump of the final state if requested. // error that might have occurred and a dump of the final state if requested.
type StatetestResult struct { type StatetestResult struct {
Name string `json:"name"` Name string `json:"name"`
Pass bool `json:"pass"` Pass bool `json:"pass"`
Root *common.Hash `json:"stateRoot,omitempty"` Root *common.Hash `json:"stateRoot,omitempty"`
Fork string `json:"fork"` Fork string `json:"fork"`
Error string `json:"error,omitempty"` Error string `json:"error,omitempty"`
State *state.Dump `json:"state,omitempty"` State *state.Dump `json:"state,omitempty"`
BenchStats *execStats `json:"benchStats,omitempty"`
} }
func stateTestCmd(ctx *cli.Context) error { func stateTestCmd(ctx *cli.Context) error {
@ -68,7 +93,7 @@ func stateTestCmd(ctx *cli.Context) error {
} }
// Load the test content from the input file // Load the test content from the input file
if len(ctx.Args().First()) != 0 { if len(ctx.Args().First()) != 0 {
return runStateTest(ctx.Args().First(), cfg, ctx.Bool(DumpFlag.Name)) return runStateTest(ctx, ctx.Args().First(), cfg, ctx.Bool(DumpFlag.Name), ctx.Bool(BenchFlag.Name))
} }
// Read filenames from stdin and execute back-to-back // Read filenames from stdin and execute back-to-back
scanner := bufio.NewScanner(os.Stdin) scanner := bufio.NewScanner(os.Stdin)
@ -77,15 +102,48 @@ func stateTestCmd(ctx *cli.Context) error {
if len(fname) == 0 { if len(fname) == 0 {
return nil return nil
} }
if err := runStateTest(fname, cfg, ctx.Bool(DumpFlag.Name)); err != nil { if err := runStateTest(ctx, fname, cfg, ctx.Bool(DumpFlag.Name), ctx.Bool(BenchFlag.Name)); err != nil {
return err return err
} }
} }
return nil return nil
} }
type stateTestCase struct {
name string
test tests.StateTest
st tests.StateSubtest
}
// collectMatchedSubtests returns test cases which match against provided filtering CLI parameters
func collectMatchedSubtests(ctx *cli.Context, testsByName map[string]tests.StateTest) []stateTestCase {
var res []stateTestCase
subtestName := ctx.String(testNameFlag.Name)
if subtestName != "" {
if subtest, ok := testsByName[subtestName]; ok {
testsByName := make(map[string]tests.StateTest)
testsByName[subtestName] = subtest
}
}
idx := ctx.Int(idxFlag.Name)
fork := ctx.String(forkFlag.Name)
for key, test := range testsByName {
for _, st := range test.Subtests() {
if idx != -1 && st.Index != idx {
continue
}
if fork != "" && st.Fork != fork {
continue
}
res = append(res, stateTestCase{name: key, st: st, test: test})
}
}
return res
}
// runStateTest loads the state-test given by fname, and executes the test. // runStateTest loads the state-test given by fname, and executes the test.
func runStateTest(fname string, cfg vm.Config, dump bool) error { func runStateTest(ctx *cli.Context, fname string, cfg vm.Config, dump bool, bench bool) error {
src, err := os.ReadFile(fname) src, err := os.ReadFile(fname)
if err != nil { if err != nil {
return err return err
@ -96,32 +154,38 @@ func runStateTest(fname string, cfg vm.Config, dump bool) error {
return err return err
} }
// Iterate over all the tests, run them and aggregate the results matchingTests := collectMatchedSubtests(ctx, testsByName)
results := make([]StatetestResult, 0, len(testsByName))
for key, test := range testsByName { // Iterate over all the tests, run them and aggregate the results
for _, st := range test.Subtests() { var results []StatetestResult
// Run the test and aggregate the result for _, test := range matchingTests {
result := &StatetestResult{Name: key, Fork: st.Fork, Pass: true} // Run the test and aggregate the result
test.Run(st, cfg, false, rawdb.HashScheme, func(err error, tstate *tests.StateTestState) { result := &StatetestResult{Name: test.name, Fork: test.st.Fork, Pass: true}
var root common.Hash test.test.Run(test.st, cfg, false, rawdb.HashScheme, func(err error, tstate *tests.StateTestState) {
if tstate.StateDB != nil { var root common.Hash
root = tstate.StateDB.IntermediateRoot(false) if tstate.StateDB != nil {
result.Root = &root root = tstate.StateDB.IntermediateRoot(false)
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root) result.Root = &root
if dump { // Dump any state to aid debugging fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
cpy, _ := state.New(root, tstate.StateDB.Database()) if dump { // Dump any state to aid debugging
dump := cpy.RawDump(nil) cpy, _ := state.New(root, tstate.StateDB.Database())
result.State = &dump dump := cpy.RawDump(nil)
} result.State = &dump
}
if err != nil {
// Test failed, mark as so
result.Pass, result.Error = false, err.Error()
} }
}
if err != nil {
// Test failed, mark as so
result.Pass, result.Error = false, err.Error()
}
})
if bench {
_, stats, _ := timedExec(true, func() ([]byte, uint64, error) {
_, _, gasUsed, _ := test.test.RunNoVerify(test.st, cfg, false, rawdb.HashScheme)
return nil, gasUsed, nil
}) })
results = append(results, *result) result.BenchStats = &stats
} }
results = append(results, *result)
} }
out, _ := json.MarshalIndent(results, "", " ") out, _ := json.MarshalIndent(results, "", " ")

19
cmd/evm/testdata/eof/eof_benches.txt vendored Normal file

File diff suppressed because one or more lines are too long

1986
cmd/evm/testdata/eof/eof_corpus_0.txt vendored Normal file

File diff suppressed because one or more lines are too long

350
cmd/evm/testdata/eof/eof_corpus_1.txt vendored Normal file

File diff suppressed because one or more lines are too long

2336
cmd/evm/testdata/eof/results.initcode.txt vendored Normal file

File diff suppressed because it is too large Load diff

2336
cmd/evm/testdata/eof/results.regular.txt vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -17,16 +17,19 @@
package main package main
import ( import (
"errors"
"fmt" "fmt"
"os" "os"
"strings"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/keystore"
"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/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log" "github.com/urfave/cli/v2"
) )
var ( var (
@ -192,7 +195,7 @@ nodes.
// makeAccountManager creates an account manager with backends // makeAccountManager creates an account manager with backends
func makeAccountManager(ctx *cli.Context) *accounts.Manager { func makeAccountManager(ctx *cli.Context) *accounts.Manager {
cfg := loadBaseConfig(ctx) cfg := loadBaseConfig(ctx)
am := accounts.NewManager(&accounts.Config{InsecureUnlockAllowed: cfg.Node.InsecureUnlockAllowed}) am := accounts.NewManager(nil)
keydir, isEphemeral, err := cfg.Node.GetKeyStoreDir() keydir, isEphemeral, err := cfg.Node.GetKeyStoreDir()
if err != nil { if err != nil {
utils.Fatalf("Failed to get the keystore directory: %v", err) utils.Fatalf("Failed to get the keystore directory: %v", err)
@ -221,72 +224,22 @@ func accountList(ctx *cli.Context) error {
return nil return nil
} }
// tries unlocking the specified account a few times. // readPasswordFromFile reads the first line of the given file, trims line endings,
func unlockAccount(ks *keystore.KeyStore, address string, i int, passwords []string) (accounts.Account, string) { // and returns the password and whether the reading was successful.
account, err := utils.MakeAddress(ks, address) func readPasswordFromFile(path string) (string, bool) {
if path == "" {
return "", false
}
text, err := os.ReadFile(path)
if err != nil { if err != nil {
utils.Fatalf("Could not list accounts: %v", err) utils.Fatalf("Failed to read password file: %v", err)
} }
lines := strings.Split(string(text), "\n")
for trials := 0; trials < 3; trials++ { if len(lines) == 0 {
prompt := fmt.Sprintf("Unlocking account %s | Attempt %d/%d", address, trials+1, 3) return "", false
password := utils.GetPassPhraseWithList(prompt, false, i, passwords)
err = ks.Unlock(account, password)
if err == nil {
log.Info("Unlocked account", "address", account.Address.Hex())
return account, password
}
if err, ok := err.(*keystore.AmbiguousAddrError); ok {
log.Info("Unlocked account", "address", account.Address.Hex())
return ambiguousAddrRecovery(ks, err, password), password
}
if err != keystore.ErrDecrypt {
// No need to prompt again if the error is not decryption-related.
break
}
} }
// All trials expended to unlock account, bail out // Sanitise DOS line endings.
utils.Fatalf("Failed to unlock account %s (%v)", address, err) return strings.TrimRight(lines[0], "\r"), true
return accounts.Account{}, ""
}
func ambiguousAddrRecovery(ks *keystore.KeyStore, err *keystore.AmbiguousAddrError, auth string) accounts.Account {
fmt.Printf("Multiple key files exist for address %x:\n", err.Addr)
for _, a := range err.Matches {
fmt.Println(" ", a.URL)
}
fmt.Println("Testing your password against all of them...")
var match *accounts.Account
for i, a := range err.Matches {
if e := ks.Unlock(a, auth); e == nil {
match = &err.Matches[i]
break
}
}
if match == nil {
utils.Fatalf("None of the listed files could be unlocked.")
return accounts.Account{}
}
fmt.Printf("Your password unlocked %s\n", match.URL)
fmt.Println("In order to avoid this warning, you need to remove the following duplicate key files:")
for _, a := range err.Matches {
if a != *match {
fmt.Println(" ", a.URL)
}
}
return *match
} }
// accountCreate creates a new account into the keystore defined by the CLI flags. // accountCreate creates a new account into the keystore defined by the CLI flags.
@ -308,8 +261,10 @@ func accountCreate(ctx *cli.Context) error {
scryptP = keystore.LightScryptP scryptP = keystore.LightScryptP
} }
password := utils.GetPassPhraseWithList("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx)) password, ok := readPasswordFromFile(ctx.Path(utils.PasswordFileFlag.Name))
if !ok {
password = utils.GetPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true)
}
account, err := keystore.StoreKey(keydir, password, scryptN, scryptP) account, err := keystore.StoreKey(keydir, password, scryptN, scryptP)
if err != nil { if err != nil {
@ -342,11 +297,23 @@ func accountUpdate(ctx *cli.Context) error {
ks := backends[0].(*keystore.KeyStore) ks := backends[0].(*keystore.KeyStore)
for _, addr := range ctx.Args().Slice() { for _, addr := range ctx.Args().Slice() {
account, oldPassword := unlockAccount(ks, addr, 0, nil) if !common.IsHexAddress(addr) {
newPassword := utils.GetPassPhraseWithList("Please give a new password. Do not forget this password.", true, 0, nil) return errors.New("address must be specified in hexadecimal form")
}
if err := ks.Update(account, oldPassword, newPassword); err != nil { account := accounts.Account{Address: common.HexToAddress(addr)}
utils.Fatalf("Could not update the account: %v", err) newPassword := utils.GetPassPhrase("Please give a NEW password. Do not forget this password.", true)
updateFn := func(attempt int) error {
prompt := fmt.Sprintf("Please provide the OLD password for account %s | Attempt %d/%d", addr, attempt+1, 3)
password := utils.GetPassPhrase(prompt, false)
return ks.Update(account, password, newPassword)
}
// let user attempt unlock thrice.
err := updateFn(0)
for attempts := 1; attempts < 3 && errors.Is(err, keystore.ErrDecrypt); attempts++ {
err = updateFn(attempts)
}
if err != nil {
return fmt.Errorf("could not update account: %w", err)
} }
} }
@ -370,11 +337,12 @@ func importWallet(ctx *cli.Context) error {
if len(backends) == 0 { if len(backends) == 0 {
utils.Fatalf("Keystore is not available") utils.Fatalf("Keystore is not available")
} }
password, ok := readPasswordFromFile(ctx.Path(utils.PasswordFileFlag.Name))
if !ok {
password = utils.GetPassPhrase("", false)
}
ks := backends[0].(*keystore.KeyStore) ks := backends[0].(*keystore.KeyStore)
passphrase := utils.GetPassPhraseWithList("", false, 0, utils.MakePasswordList(ctx)) acct, err := ks.ImportPreSaleKey(keyJSON, password)
acct, err := ks.ImportPreSaleKey(keyJSON, passphrase)
if err != nil { if err != nil {
utils.Fatalf("%v", err) utils.Fatalf("%v", err)
} }
@ -402,9 +370,11 @@ func accountImport(ctx *cli.Context) error {
} }
ks := backends[0].(*keystore.KeyStore) ks := backends[0].(*keystore.KeyStore)
passphrase := utils.GetPassPhraseWithList("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx)) password, ok := readPasswordFromFile(ctx.Path(utils.PasswordFileFlag.Name))
if !ok {
acct, err := ks.ImportECDSA(key, passphrase) password = utils.GetPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true)
}
acct, err := ks.ImportECDSA(key, password)
if err != nil { if err != nil {
utils.Fatalf("Could not create the account: %v", err) utils.Fatalf("Could not create the account: %v", err)
} }

View file

@ -20,7 +20,6 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strings"
"testing" "testing"
"github.com/cespare/cp" "github.com/cespare/cp"
@ -117,7 +116,6 @@ func TestAccountImport(t *testing.T) {
}, },
} }
for _, test := range tests { for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
t.Parallel() t.Parallel()
importAccountWithExpect(t, test.key, test.output) importAccountWithExpect(t, test.key, test.output)
@ -183,12 +181,12 @@ func TestAccountUpdate(t *testing.T) {
"f466859ead1932d743d622cb74fc058882e8648a") "f466859ead1932d743d622cb74fc058882e8648a")
defer geth.ExpectExit() defer geth.ExpectExit()
geth.Expect(` geth.Expect(`
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3 Please give a NEW password. Do not forget this password.
!! Unsupported terminal, password will be echoed. !! Unsupported terminal, password will be echoed.
Password: {{.InputLine "foobar"}}
Please give a new password. Do not forget this password.
Password: {{.InputLine "foobar2"}} Password: {{.InputLine "foobar2"}}
Repeat password: {{.InputLine "foobar2"}} Repeat password: {{.InputLine "foobar2"}}
Please provide the OLD password for account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3
Password: {{.InputLine "foobar"}}
`) `)
} }
@ -218,173 +216,3 @@ Password: {{.InputLine "wrong"}}
Fatal: could not decrypt key with given password Fatal: could not decrypt key with given password
`) `)
} }
func TestUnlockFlag(t *testing.T) {
t.Parallel()
geth := runMinimalGeth(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t),
"--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "console", "--exec", "loadScript('testdata/empty.js')")
geth.Expect(`
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3
!! Unsupported terminal, password will be echoed.
Password: {{.InputLine "foobar"}}
undefined
`)
geth.ExpectExit()
wantMessages := []string{
"Unlocked account",
"=0xf466859eAD1932D743d622CB74FC058882E8648A",
}
for _, m := range wantMessages {
if !strings.Contains(geth.StderrText(), m) {
t.Errorf("stderr text does not contain %q", m)
}
}
}
func TestUnlockFlagWrongPassword(t *testing.T) {
t.Parallel()
geth := runMinimalGeth(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t),
"--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "console", "--exec", "loadScript('testdata/empty.js')")
defer geth.ExpectExit()
geth.Expect(`
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3
!! Unsupported terminal, password will be echoed.
Password: {{.InputLine "wrong1"}}
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 2/3
Password: {{.InputLine "wrong2"}}
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 3/3
Password: {{.InputLine "wrong3"}}
Fatal: Failed to unlock account f466859ead1932d743d622cb74fc058882e8648a (could not decrypt key with given password)
`)
}
// https://github.com/ethereum/go-ethereum/issues/1785
func TestUnlockFlagMultiIndex(t *testing.T) {
t.Parallel()
geth := runMinimalGeth(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t),
"--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "--unlock", "0,2", "console", "--exec", "loadScript('testdata/empty.js')")
geth.Expect(`
Unlocking account 0 | Attempt 1/3
!! Unsupported terminal, password will be echoed.
Password: {{.InputLine "foobar"}}
Unlocking account 2 | Attempt 1/3
Password: {{.InputLine "foobar"}}
undefined
`)
geth.ExpectExit()
wantMessages := []string{
"Unlocked account",
"=0x7EF5A6135f1FD6a02593eEdC869c6D41D934aef8",
"=0x289d485D9771714CCe91D3393D764E1311907ACc",
}
for _, m := range wantMessages {
if !strings.Contains(geth.StderrText(), m) {
t.Errorf("stderr text does not contain %q", m)
}
}
}
func TestUnlockFlagPasswordFile(t *testing.T) {
t.Parallel()
geth := runMinimalGeth(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t),
"--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "--password", "testdata/passwords.txt", "--unlock", "0,2", "console", "--exec", "loadScript('testdata/empty.js')")
geth.Expect(`
undefined
`)
geth.ExpectExit()
wantMessages := []string{
"Unlocked account",
"=0x7EF5A6135f1FD6a02593eEdC869c6D41D934aef8",
"=0x289d485D9771714CCe91D3393D764E1311907ACc",
}
for _, m := range wantMessages {
if !strings.Contains(geth.StderrText(), m) {
t.Errorf("stderr text does not contain %q", m)
}
}
}
func TestUnlockFlagPasswordFileWrongPassword(t *testing.T) {
t.Parallel()
geth := runMinimalGeth(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t),
"--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "--password",
"testdata/wrong-passwords.txt", "--unlock", "0,2")
defer geth.ExpectExit()
geth.Expect(`
Fatal: Failed to unlock account 0 (could not decrypt key with given password)
`)
}
func TestUnlockFlagAmbiguous(t *testing.T) {
t.Parallel()
store := filepath.Join("..", "..", "accounts", "keystore", "testdata", "dupes")
geth := runMinimalGeth(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t),
"--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "--keystore",
store, "--unlock", "f466859ead1932d743d622cb74fc058882e8648a",
"console", "--exec", "loadScript('testdata/empty.js')")
defer geth.ExpectExit()
// Helper for the expect template, returns absolute keystore path.
geth.SetTemplateFunc("keypath", func(file string) string {
abs, _ := filepath.Abs(filepath.Join(store, file))
return abs
})
geth.Expect(`
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3
!! Unsupported terminal, password will be echoed.
Password: {{.InputLine "foobar"}}
Multiple key files exist for address f466859ead1932d743d622cb74fc058882e8648a:
keystore://{{keypath "1"}}
keystore://{{keypath "2"}}
Testing your password against all of them...
Your password unlocked keystore://{{keypath "1"}}
In order to avoid this warning, you need to remove the following duplicate key files:
keystore://{{keypath "2"}}
undefined
`)
geth.ExpectExit()
wantMessages := []string{
"Unlocked account",
"=0xf466859eAD1932D743d622CB74FC058882E8648A",
}
for _, m := range wantMessages {
if !strings.Contains(geth.StderrText(), m) {
t.Errorf("stderr text does not contain %q", m)
}
}
}
func TestUnlockFlagAmbiguousWrongPassword(t *testing.T) {
t.Parallel()
store := filepath.Join("..", "..", "accounts", "keystore", "testdata", "dupes")
geth := runMinimalGeth(t, "--port", "0", "--ipcdisable", "--datadir", tmpDatadirWithKeystore(t),
"--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "--keystore",
store, "--unlock", "f466859ead1932d743d622cb74fc058882e8648a")
defer geth.ExpectExit()
// Helper for the expect template, returns absolute keystore path.
geth.SetTemplateFunc("keypath", func(file string) string {
abs, _ := filepath.Abs(filepath.Join(store, file))
return abs
})
geth.Expect(`
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3
!! Unsupported terminal, password will be echoed.
Password: {{.InputLine "wrong"}}
Multiple key files exist for address f466859ead1932d743d622cb74fc058882e8648a:
keystore://{{keypath "1"}}
keystore://{{keypath "2"}}
Testing your password against all of them...
Fatal: None of the listed files could be unlocked.
`)
geth.ExpectExit()
}

View file

@ -23,6 +23,7 @@ import (
"math/big" "math/big"
"os" "os"
"runtime" "runtime"
"slices"
"strconv" "strconv"
"sync/atomic" "sync/atomic"
"time" "time"
@ -39,7 +40,6 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/internal/era" "github.com/ethereum/go-ethereum/internal/era"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
@ -51,7 +51,7 @@ var (
Name: "init", Name: "init",
Usage: "Bootstrap and initialize a new genesis block", Usage: "Bootstrap and initialize a new genesis block",
ArgsUsage: "<genesisPath>", ArgsUsage: "<genesisPath>",
Flags: flags.Merge([]cli.Flag{ Flags: slices.Concat([]cli.Flag{
utils.CachePreimagesFlag, utils.CachePreimagesFlag,
utils.OverrideCancun, utils.OverrideCancun,
utils.OverrideVerkle, utils.OverrideVerkle,
@ -78,7 +78,7 @@ if one is set. Otherwise it prints the genesis from the datadir.`,
Name: "import", Name: "import",
Usage: "Import a blockchain file", Usage: "Import a blockchain file",
ArgsUsage: "<filename> (<filename 2> ... <filename N>) ", ArgsUsage: "<filename> (<filename 2> ... <filename N>) ",
Flags: flags.Merge([]cli.Flag{ Flags: slices.Concat([]cli.Flag{
utils.CacheFlag, utils.CacheFlag,
utils.SyncModeFlag, utils.SyncModeFlag,
utils.GCModeFlag, utils.GCModeFlag,
@ -117,7 +117,7 @@ processing will proceed even if an individual RLP-file import failure occurs.`,
Name: "export", Name: "export",
Usage: "Export blockchain into file", Usage: "Export blockchain into file",
ArgsUsage: "<filename> [<blockNumFirst> <blockNumLast>]", ArgsUsage: "<filename> [<blockNumFirst> <blockNumLast>]",
Flags: flags.Merge([]cli.Flag{ Flags: slices.Concat([]cli.Flag{
utils.CacheFlag, utils.CacheFlag,
utils.SyncModeFlag, utils.SyncModeFlag,
}, utils.DatabaseFlags), }, utils.DatabaseFlags),
@ -133,7 +133,7 @@ be gzipped.`,
Name: "import-history", Name: "import-history",
Usage: "Import an Era archive", Usage: "Import an Era archive",
ArgsUsage: "<dir>", ArgsUsage: "<dir>",
Flags: flags.Merge([]cli.Flag{ Flags: slices.Concat([]cli.Flag{
utils.TxLookupLimitFlag, utils.TxLookupLimitFlag,
}, },
utils.DatabaseFlags, utils.DatabaseFlags,
@ -149,7 +149,7 @@ from Era archives.
Name: "export-history", Name: "export-history",
Usage: "Export blockchain history to Era archives", Usage: "Export blockchain history to Era archives",
ArgsUsage: "<dir> <first> <last>", ArgsUsage: "<dir> <first> <last>",
Flags: flags.Merge(utils.DatabaseFlags), Flags: slices.Concat(utils.DatabaseFlags),
Description: ` Description: `
The export-history command will export blocks and their corresponding receipts The export-history command will export blocks and their corresponding receipts
into Era archives. Eras are typically packaged in steps of 8192 blocks. into Era archives. Eras are typically packaged in steps of 8192 blocks.
@ -160,7 +160,7 @@ into Era archives. Eras are typically packaged in steps of 8192 blocks.
Name: "import-preimages", Name: "import-preimages",
Usage: "Import the preimage database from an RLP stream", Usage: "Import the preimage database from an RLP stream",
ArgsUsage: "<datafile>", ArgsUsage: "<datafile>",
Flags: flags.Merge([]cli.Flag{ Flags: slices.Concat([]cli.Flag{
utils.CacheFlag, utils.CacheFlag,
utils.SyncModeFlag, utils.SyncModeFlag,
}, utils.DatabaseFlags), }, utils.DatabaseFlags),
@ -175,7 +175,7 @@ It's deprecated, please use "geth db import" instead.
Name: "dump", Name: "dump",
Usage: "Dump a specific block from storage", Usage: "Dump a specific block from storage",
ArgsUsage: "[? <blockHash> | <blockNum>]", ArgsUsage: "[? <blockHash> | <blockNum>]",
Flags: flags.Merge([]cli.Flag{ Flags: slices.Concat([]cli.Flag{
utils.CacheFlag, utils.CacheFlag,
utils.IterativeOutputFlag, utils.IterativeOutputFlag,
utils.ExcludeCodeFlag, utils.ExcludeCodeFlag,

View file

@ -24,6 +24,7 @@ import (
"os" "os"
"reflect" "reflect"
"runtime" "runtime"
"slices"
"strings" "strings"
"time" "time"
"unicode" "unicode"
@ -46,7 +47,6 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/naoina/toml" "github.com/naoina/toml"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
@ -58,7 +58,7 @@ var (
Name: "dumpconfig", Name: "dumpconfig",
Usage: "Export configuration values in a TOML format", Usage: "Export configuration values in a TOML format",
ArgsUsage: "<dumpfile (optional)>", ArgsUsage: "<dumpfile (optional)>",
Flags: flags.Merge(nodeFlags, rpcFlags), Flags: slices.Concat(nodeFlags, rpcFlags),
Description: `Export configuration values in TOML format (to stdout by default).`, Description: `Export configuration values in TOML format (to stdout by default).`,
} }
@ -134,11 +134,10 @@ func defaultNodeConfig() node.Config {
git, _ := version.VCS() git, _ := version.VCS()
cfg := node.DefaultConfig cfg := node.DefaultConfig
cfg.Name = clientIdentifier cfg.Name = clientIdentifier
cfg.Version = params.VersionWithCommit(git.Commit, git.Date) cfg.Version = version.WithCommit(git.Commit, git.Date)
cfg.HTTPModules = append(cfg.HTTPModules, "eth") cfg.HTTPModules = append(cfg.HTTPModules, "eth")
cfg.WSModules = append(cfg.WSModules, "eth") cfg.WSModules = append(cfg.WSModules, "eth")
cfg.IPCPath = clientIdentifier + ".ipc" cfg.IPCPath = clientIdentifier + ".ipc"
return cfg return cfg
} }
@ -262,7 +261,7 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
// Start blsync mode. // Start blsync mode.
srv := rpc.NewServer("", 0, 0) srv := rpc.NewServer("", 0, 0)
srv.RegisterName("engine", catalyst.NewConsensusAPI(eth)) srv.RegisterName("engine", catalyst.NewConsensusAPI(eth))
blsyncer := blsync.NewClient(ctx) blsyncer := blsync.NewClient(utils.MakeBeaconLightConfig(ctx))
blsyncer.SetEngineRPC(rpc.DialInProc(srv)) blsyncer.SetEngineRPC(rpc.DialInProc(srv))
stack.RegisterLifecycle(blsyncer) stack.RegisterLifecycle(blsyncer)
} else { } else {

View file

@ -18,16 +18,14 @@ package main
import ( import (
"fmt" "fmt"
"os" "slices"
"path/filepath"
"strings" "strings"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/console" "github.com/ethereum/go-ethereum/console"
"github.com/ethereum/go-ethereum/internal/flags" "github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum/node"
) )
var ( var (
@ -37,7 +35,7 @@ var (
Action: localConsole, Action: localConsole,
Name: "console", Name: "console",
Usage: "Start an interactive JavaScript environment", Usage: "Start an interactive JavaScript environment",
Flags: flags.Merge(nodeFlags, rpcFlags, consoleFlags), Flags: slices.Concat(nodeFlags, rpcFlags, consoleFlags),
Description: ` Description: `
The Geth console is an interactive shell for the JavaScript runtime environment The Geth console is an interactive shell for the JavaScript runtime environment
which exposes a node admin interface as well as the Ðapp JavaScript API. which exposes a node admin interface as well as the Ðapp JavaScript API.
@ -49,7 +47,7 @@ See https://geth.ethereum.org/docs/interacting-with-geth/javascript-console.`,
Name: "attach", Name: "attach",
Usage: "Start an interactive JavaScript environment (connect to node)", Usage: "Start an interactive JavaScript environment (connect to node)",
ArgsUsage: "[endpoint]", ArgsUsage: "[endpoint]",
Flags: flags.Merge([]cli.Flag{utils.DataDirFlag, utils.HttpHeaderFlag}, consoleFlags), Flags: slices.Concat([]cli.Flag{utils.DataDirFlag, utils.HttpHeaderFlag}, consoleFlags),
Description: ` Description: `
The Geth console is an interactive shell for the JavaScript runtime environment The Geth console is an interactive shell for the JavaScript runtime environment
which exposes a node admin interface as well as the Ðapp JavaScript API. which exposes a node admin interface as well as the Ðapp JavaScript API.
@ -62,7 +60,7 @@ This command allows to open a console on a running geth node.`,
Name: "js", Name: "js",
Usage: "(DEPRECATED) Execute the specified JavaScript files", Usage: "(DEPRECATED) Execute the specified JavaScript files",
ArgsUsage: "<jsfile> [jsfile...]", ArgsUsage: "<jsfile> [jsfile...]",
Flags: flags.Merge(nodeFlags, consoleFlags), Flags: slices.Concat(nodeFlags, consoleFlags),
Description: ` Description: `
The JavaScript VM exposes a node admin interface as well as the Ðapp The JavaScript VM exposes a node admin interface as well as the Ðapp
JavaScript API. See https://geth.ethereum.org/docs/interacting-with-geth/javascript-console`, JavaScript API. See https://geth.ethereum.org/docs/interacting-with-geth/javascript-console`,
@ -177,7 +175,7 @@ func remoteConsole(ctx *cli.Context) error {
func ephemeralConsole(ctx *cli.Context) error { func ephemeralConsole(ctx *cli.Context) error {
var b strings.Builder var b strings.Builder
for _, file := range ctx.Args().Slice() { for _, file := range ctx.Args().Slice() {
b.Write([]byte(fmt.Sprintf("loadScript('%s');", file))) b.WriteString(fmt.Sprintf("loadScript('%s');", file))
} }
utils.Fatalf(`The "js" command is deprecated. Please use the following instead: utils.Fatalf(`The "js" command is deprecated. Please use the following instead:

View file

@ -26,7 +26,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/internal/version"
) )
const ( const (
@ -61,7 +61,7 @@ func TestConsoleWelcome(t *testing.T) {
geth.SetTemplateFunc("goos", func() string { return runtime.GOOS }) geth.SetTemplateFunc("goos", func() string { return runtime.GOOS })
geth.SetTemplateFunc("goarch", func() string { return runtime.GOARCH }) geth.SetTemplateFunc("goarch", func() string { return runtime.GOARCH })
geth.SetTemplateFunc("gover", runtime.Version) geth.SetTemplateFunc("gover", runtime.Version)
geth.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") }) geth.SetTemplateFunc("gethver", func() string { return version.WithCommit("", "") })
geth.SetTemplateFunc("niltime", func() string { geth.SetTemplateFunc("niltime", func() string {
return time.Unix(1695902100, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)") return time.Unix(1695902100, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
}) })
@ -131,7 +131,7 @@ func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) {
attach.SetTemplateFunc("goos", func() string { return runtime.GOOS }) attach.SetTemplateFunc("goos", func() string { return runtime.GOOS })
attach.SetTemplateFunc("goarch", func() string { return runtime.GOARCH }) attach.SetTemplateFunc("goarch", func() string { return runtime.GOARCH })
attach.SetTemplateFunc("gover", runtime.Version) attach.SetTemplateFunc("gover", runtime.Version)
attach.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") }) attach.SetTemplateFunc("gethver", func() string { return version.WithCommit("", "") })
attach.SetTemplateFunc("niltime", func() string { attach.SetTemplateFunc("niltime", func() string {
return time.Unix(1695902100, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)") return time.Unix(1695902100, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
}) })

View file

@ -22,6 +22,7 @@ import (
"os" "os"
"os/signal" "os/signal"
"path/filepath" "path/filepath"
"slices"
"strconv" "strconv"
"strings" "strings"
"syscall" "syscall"
@ -36,7 +37,6 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
@ -60,7 +60,7 @@ var (
Name: "removedb", Name: "removedb",
Usage: "Remove blockchain and state databases", Usage: "Remove blockchain and state databases",
ArgsUsage: "", ArgsUsage: "",
Flags: flags.Merge(utils.DatabaseFlags, Flags: slices.Concat(utils.DatabaseFlags,
[]cli.Flag{removeStateDataFlag, removeChainDataFlag}), []cli.Flag{removeStateDataFlag, removeChainDataFlag}),
Description: ` Description: `
Remove blockchain and state databases`, Remove blockchain and state databases`,
@ -89,7 +89,7 @@ Remove blockchain and state databases`,
Action: inspect, Action: inspect,
Name: "inspect", Name: "inspect",
ArgsUsage: "<prefix> <start>", ArgsUsage: "<prefix> <start>",
Flags: flags.Merge([]cli.Flag{ Flags: slices.Concat([]cli.Flag{
utils.SyncModeFlag, utils.SyncModeFlag,
}, utils.NetworkFlags, utils.DatabaseFlags), }, utils.NetworkFlags, utils.DatabaseFlags),
Usage: "Inspect the storage size for each type of data in the database", Usage: "Inspect the storage size for each type of data in the database",
@ -99,7 +99,7 @@ Remove blockchain and state databases`,
Action: checkStateContent, Action: checkStateContent,
Name: "check-state-content", Name: "check-state-content",
ArgsUsage: "<start (optional)>", ArgsUsage: "<start (optional)>",
Flags: flags.Merge(utils.NetworkFlags, utils.DatabaseFlags), Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Usage: "Verify that state data is cryptographically correct", Usage: "Verify that state data is cryptographically correct",
Description: `This command iterates the entire database for 32-byte keys, looking for rlp-encoded trie nodes. Description: `This command iterates the entire database for 32-byte keys, looking for rlp-encoded trie nodes.
For each trie node encountered, it checks that the key corresponds to the keccak256(value). If this is not true, this indicates For each trie node encountered, it checks that the key corresponds to the keccak256(value). If this is not true, this indicates
@ -109,7 +109,7 @@ a data corruption.`,
Action: dbStats, Action: dbStats,
Name: "stats", Name: "stats",
Usage: "Print leveldb statistics", Usage: "Print leveldb statistics",
Flags: flags.Merge([]cli.Flag{ Flags: slices.Concat([]cli.Flag{
utils.SyncModeFlag, utils.SyncModeFlag,
}, utils.NetworkFlags, utils.DatabaseFlags), }, utils.NetworkFlags, utils.DatabaseFlags),
} }
@ -117,7 +117,7 @@ a data corruption.`,
Action: dbCompact, Action: dbCompact,
Name: "compact", Name: "compact",
Usage: "Compact leveldb database. WARNING: May take a very long time", Usage: "Compact leveldb database. WARNING: May take a very long time",
Flags: flags.Merge([]cli.Flag{ Flags: slices.Concat([]cli.Flag{
utils.SyncModeFlag, utils.SyncModeFlag,
utils.CacheFlag, utils.CacheFlag,
utils.CacheDatabaseFlag, utils.CacheDatabaseFlag,
@ -131,7 +131,7 @@ corruption if it is aborted during execution'!`,
Name: "get", Name: "get",
Usage: "Show the value of a database key", Usage: "Show the value of a database key",
ArgsUsage: "<hex-encoded key>", ArgsUsage: "<hex-encoded key>",
Flags: flags.Merge([]cli.Flag{ Flags: slices.Concat([]cli.Flag{
utils.SyncModeFlag, utils.SyncModeFlag,
}, utils.NetworkFlags, utils.DatabaseFlags), }, utils.NetworkFlags, utils.DatabaseFlags),
Description: "This command looks up the specified database key from the database.", Description: "This command looks up the specified database key from the database.",
@ -141,7 +141,7 @@ corruption if it is aborted during execution'!`,
Name: "delete", Name: "delete",
Usage: "Delete a database key (WARNING: may corrupt your database)", Usage: "Delete a database key (WARNING: may corrupt your database)",
ArgsUsage: "<hex-encoded key>", ArgsUsage: "<hex-encoded key>",
Flags: flags.Merge([]cli.Flag{ Flags: slices.Concat([]cli.Flag{
utils.SyncModeFlag, utils.SyncModeFlag,
}, utils.NetworkFlags, utils.DatabaseFlags), }, utils.NetworkFlags, utils.DatabaseFlags),
Description: `This command deletes the specified database key from the database. Description: `This command deletes the specified database key from the database.
@ -152,7 +152,7 @@ WARNING: This is a low-level operation which may cause database corruption!`,
Name: "put", Name: "put",
Usage: "Set the value of a database key (WARNING: may corrupt your database)", Usage: "Set the value of a database key (WARNING: may corrupt your database)",
ArgsUsage: "<hex-encoded key> <hex-encoded value>", ArgsUsage: "<hex-encoded key> <hex-encoded value>",
Flags: flags.Merge([]cli.Flag{ Flags: slices.Concat([]cli.Flag{
utils.SyncModeFlag, utils.SyncModeFlag,
}, utils.NetworkFlags, utils.DatabaseFlags), }, utils.NetworkFlags, utils.DatabaseFlags),
Description: `This command sets a given database key to the given value. Description: `This command sets a given database key to the given value.
@ -163,7 +163,7 @@ WARNING: This is a low-level operation which may cause database corruption!`,
Name: "dumptrie", Name: "dumptrie",
Usage: "Show the storage key/values of a given storage trie", Usage: "Show the storage key/values of a given storage trie",
ArgsUsage: "<hex-encoded state root> <hex-encoded account hash> <hex-encoded storage trie root> <hex-encoded start (optional)> <int max elements (optional)>", ArgsUsage: "<hex-encoded state root> <hex-encoded account hash> <hex-encoded storage trie root> <hex-encoded start (optional)> <int max elements (optional)>",
Flags: flags.Merge([]cli.Flag{ Flags: slices.Concat([]cli.Flag{
utils.SyncModeFlag, utils.SyncModeFlag,
}, utils.NetworkFlags, utils.DatabaseFlags), }, utils.NetworkFlags, utils.DatabaseFlags),
Description: "This command looks up the specified database key from the database.", Description: "This command looks up the specified database key from the database.",
@ -173,7 +173,7 @@ WARNING: This is a low-level operation which may cause database corruption!`,
Name: "freezer-index", Name: "freezer-index",
Usage: "Dump out the index of a specific freezer table", Usage: "Dump out the index of a specific freezer table",
ArgsUsage: "<freezer-type> <table-type> <start (int)> <end (int)>", ArgsUsage: "<freezer-type> <table-type> <start (int)> <end (int)>",
Flags: flags.Merge([]cli.Flag{ Flags: slices.Concat([]cli.Flag{
utils.SyncModeFlag, utils.SyncModeFlag,
}, utils.NetworkFlags, utils.DatabaseFlags), }, utils.NetworkFlags, utils.DatabaseFlags),
Description: "This command displays information about the freezer index.", Description: "This command displays information about the freezer index.",
@ -183,7 +183,7 @@ WARNING: This is a low-level operation which may cause database corruption!`,
Name: "import", Name: "import",
Usage: "Imports leveldb-data from an exported RLP dump.", Usage: "Imports leveldb-data from an exported RLP dump.",
ArgsUsage: "<dumpfile> <start (optional)", ArgsUsage: "<dumpfile> <start (optional)",
Flags: flags.Merge([]cli.Flag{ Flags: slices.Concat([]cli.Flag{
utils.SyncModeFlag, utils.SyncModeFlag,
}, utils.NetworkFlags, utils.DatabaseFlags), }, utils.NetworkFlags, utils.DatabaseFlags),
Description: "The import command imports the specific chain data from an RLP encoded stream.", Description: "The import command imports the specific chain data from an RLP encoded stream.",
@ -193,7 +193,7 @@ WARNING: This is a low-level operation which may cause database corruption!`,
Name: "export", Name: "export",
Usage: "Exports the chain data into an RLP dump. If the <dumpfile> has .gz suffix, gzip compression will be used.", Usage: "Exports the chain data into an RLP dump. If the <dumpfile> has .gz suffix, gzip compression will be used.",
ArgsUsage: "<type> <dumpfile>", ArgsUsage: "<type> <dumpfile>",
Flags: flags.Merge([]cli.Flag{ Flags: slices.Concat([]cli.Flag{
utils.SyncModeFlag, utils.SyncModeFlag,
}, utils.NetworkFlags, utils.DatabaseFlags), }, utils.NetworkFlags, utils.DatabaseFlags),
Description: "Exports the specified chain data to an RLP encoded stream, optionally gzip-compressed.", Description: "Exports the specified chain data to an RLP encoded stream, optionally gzip-compressed.",
@ -202,7 +202,7 @@ WARNING: This is a low-level operation which may cause database corruption!`,
Action: showMetaData, Action: showMetaData,
Name: "metadata", Name: "metadata",
Usage: "Shows metadata about the chain status.", Usage: "Shows metadata about the chain status.",
Flags: flags.Merge([]cli.Flag{ Flags: slices.Concat([]cli.Flag{
utils.SyncModeFlag, utils.SyncModeFlag,
}, utils.NetworkFlags, utils.DatabaseFlags), }, utils.NetworkFlags, utils.DatabaseFlags),
Description: "Shows metadata about the chain status.", Description: "Shows metadata about the chain status.",
@ -212,7 +212,7 @@ WARNING: This is a low-level operation which may cause database corruption!`,
Name: "inspect-history", Name: "inspect-history",
Usage: "Inspect the state history within block range", Usage: "Inspect the state history within block range",
ArgsUsage: "<address> [OPTIONAL <storage-slot>]", ArgsUsage: "<address> [OPTIONAL <storage-slot>]",
Flags: flags.Merge([]cli.Flag{ Flags: slices.Concat([]cli.Flag{
utils.SyncModeFlag, utils.SyncModeFlag,
&cli.Uint64Flag{ &cli.Uint64Flag{
Name: "start", Name: "start",

View file

@ -29,7 +29,7 @@ var customGenesisTests = []struct {
query string query string
result string result string
}{ }{
// Genesis file with an empty chain configuration (ensure missing fields work) // Genesis file with a mostly-empty chain configuration (ensure missing fields work)
{ {
genesis: `{ genesis: `{
"alloc" : {}, "alloc" : {},
@ -41,8 +41,8 @@ var customGenesisTests = []struct {
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000", "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00", "timestamp" : "0x00",
"config" : { "config": {
"terminalTotalDifficultyPassed": true "terminalTotalDifficulty": 0
} }
}`, }`,
query: "eth.getBlock(0).nonce", query: "eth.getBlock(0).nonce",
@ -64,7 +64,7 @@ var customGenesisTests = []struct {
"homesteadBlock" : 42, "homesteadBlock" : 42,
"daoForkBlock" : 141, "daoForkBlock" : 141,
"daoForkSupport" : true, "daoForkSupport" : true,
"terminalTotalDifficultyPassed" : true "terminalTotalDifficulty": 0
} }
}`, }`,
query: "eth.getBlock(0).nonce", query: "eth.getBlock(0).nonce",
@ -117,8 +117,8 @@ func TestCustomBackend(t *testing.T) {
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000", "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00", "timestamp" : "0x00",
"config" : { "config": {
"terminalTotalDifficultyPassed": true "terminalTotalDifficulty": 0
} }
}` }`
type backendTest struct { type backendTest struct {

View file

@ -22,6 +22,7 @@ import (
"fmt" "fmt"
"os" "os"
"os/signal" "os/signal"
"slices"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
@ -72,7 +73,7 @@ var (
utils.SmartCardDaemonPathFlag, utils.SmartCardDaemonPathFlag,
utils.OverrideCancun, utils.OverrideCancun,
utils.OverrideVerkle, utils.OverrideVerkle,
utils.EnablePersonal, utils.EnablePersonal, // deprecated
utils.TxPoolLocalsFlag, utils.TxPoolLocalsFlag,
utils.TxPoolNoLocalsFlag, utils.TxPoolNoLocalsFlag,
utils.TxPoolJournalFlag, utils.TxPoolJournalFlag,
@ -259,7 +260,7 @@ func init() {
} }
sort.Sort(cli.CommandsByName(app.Commands)) sort.Sort(cli.CommandsByName(app.Commands))
app.Flags = flags.Merge( app.Flags = slices.Concat(
nodeFlags, nodeFlags,
rpcFlags, rpcFlags,
consoleFlags, consoleFlags,
@ -390,8 +391,9 @@ func startNode(ctx *cli.Context, stack *node.Node, isConsole bool) {
// Start up the node itself // Start up the node itself
utils.StartNode(ctx, stack, isConsole) utils.StartNode(ctx, stack, isConsole)
// Unlock any account specifically requested if ctx.IsSet(utils.UnlockedAccountFlag.Name) {
unlockAccounts(ctx, stack) log.Warn(`The "unlock" flag has been deprecated and has no effect`)
}
// Register wallet event handlers to open and auto-derive wallets // Register wallet event handlers to open and auto-derive wallets
events := make(chan accounts.WalletEvent, 16) events := make(chan accounts.WalletEvent, 16)

View file

@ -25,7 +25,7 @@ import (
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum/internal/version" "github.com/ethereum/go-ethereum/internal/version"
"github.com/ethereum/go-ethereum/params" "github.com/urfave/cli/v2"
) )
var ( var (
@ -74,8 +74,7 @@ func printVersion(ctx *cli.Context) error {
git, _ := version.VCS() git, _ := version.VCS()
fmt.Println(strings.Title(clientIdentifier)) fmt.Println(strings.Title(clientIdentifier))
fmt.Println("Version:", params.VersionWithMeta) fmt.Println("Version:", version.WithMeta)
if git.Commit != "" { if git.Commit != "" {
fmt.Println("Git Commit:", git.Commit) fmt.Println("Git Commit:", git.Commit)
} }

View file

@ -22,6 +22,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"os" "os"
"slices"
"time" "time"
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
@ -32,7 +33,6 @@ import (
"github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/core/state/snapshot"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
@ -50,7 +50,7 @@ var (
Usage: "Prune stale ethereum state data based on the snapshot", Usage: "Prune stale ethereum state data based on the snapshot",
ArgsUsage: "<root>", ArgsUsage: "<root>",
Action: pruneState, Action: pruneState,
Flags: flags.Merge([]cli.Flag{ Flags: slices.Concat([]cli.Flag{
utils.BloomFilterSizeFlag, utils.BloomFilterSizeFlag,
}, utils.NetworkFlags, utils.DatabaseFlags), }, utils.NetworkFlags, utils.DatabaseFlags),
Description: ` Description: `
@ -70,7 +70,7 @@ WARNING: it's only supported in hash mode(--state.scheme=hash)".
Usage: "Recalculate state hash based on the snapshot for verification", Usage: "Recalculate state hash based on the snapshot for verification",
ArgsUsage: "<root>", ArgsUsage: "<root>",
Action: verifyState, Action: verifyState,
Flags: flags.Merge(utils.NetworkFlags, utils.DatabaseFlags), Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: ` Description: `
geth snapshot verify-state <state-root> geth snapshot verify-state <state-root>
will traverse the whole accounts and storages set based on the specified will traverse the whole accounts and storages set based on the specified
@ -83,7 +83,7 @@ In other words, this command does the snapshot to trie conversion.
Usage: "Check that there is no 'dangling' snap storage", Usage: "Check that there is no 'dangling' snap storage",
ArgsUsage: "<root>", ArgsUsage: "<root>",
Action: checkDanglingStorage, Action: checkDanglingStorage,
Flags: flags.Merge(utils.NetworkFlags, utils.DatabaseFlags), Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: ` Description: `
geth snapshot check-dangling-storage <state-root> traverses the snap storage geth snapshot check-dangling-storage <state-root> traverses the snap storage
data, and verifies that all snapshot storage data has a corresponding account. data, and verifies that all snapshot storage data has a corresponding account.
@ -94,7 +94,7 @@ data, and verifies that all snapshot storage data has a corresponding account.
Usage: "Check all snapshot layers for the specific account", Usage: "Check all snapshot layers for the specific account",
ArgsUsage: "<address | hash>", ArgsUsage: "<address | hash>",
Action: checkAccount, Action: checkAccount,
Flags: flags.Merge(utils.NetworkFlags, utils.DatabaseFlags), Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: ` Description: `
geth snapshot inspect-account <address | hash> checks all snapshot layers and prints out geth snapshot inspect-account <address | hash> checks all snapshot layers and prints out
information about the specified address. information about the specified address.
@ -105,7 +105,7 @@ information about the specified address.
Usage: "Traverse the state with given root hash and perform quick verification", Usage: "Traverse the state with given root hash and perform quick verification",
ArgsUsage: "<root>", ArgsUsage: "<root>",
Action: traverseState, Action: traverseState,
Flags: flags.Merge(utils.NetworkFlags, utils.DatabaseFlags), Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: ` Description: `
geth snapshot traverse-state <state-root> geth snapshot traverse-state <state-root>
will traverse the whole state from the given state root and will abort if any will traverse the whole state from the given state root and will abort if any
@ -120,7 +120,7 @@ It's also usable without snapshot enabled.
Usage: "Traverse the state with given root hash and perform detailed verification", Usage: "Traverse the state with given root hash and perform detailed verification",
ArgsUsage: "<root>", ArgsUsage: "<root>",
Action: traverseRawState, Action: traverseRawState,
Flags: flags.Merge(utils.NetworkFlags, utils.DatabaseFlags), Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: ` Description: `
geth snapshot traverse-rawstate <state-root> geth snapshot traverse-rawstate <state-root>
will traverse the whole state from the given root and will abort if any referenced will traverse the whole state from the given root and will abort if any referenced
@ -136,7 +136,7 @@ It's also usable without snapshot enabled.
Usage: "Dump a specific block from storage (same as 'geth dump' but using snapshots)", Usage: "Dump a specific block from storage (same as 'geth dump' but using snapshots)",
ArgsUsage: "[? <blockHash> | <blockNum>]", ArgsUsage: "[? <blockHash> | <blockNum>]",
Action: dumpState, Action: dumpState,
Flags: flags.Merge([]cli.Flag{ Flags: slices.Concat([]cli.Flag{
utils.ExcludeCodeFlag, utils.ExcludeCodeFlag,
utils.ExcludeStorageFlag, utils.ExcludeStorageFlag,
utils.StartKeyFlag, utils.StartKeyFlag,
@ -457,7 +457,7 @@ func traverseRawState(ctx *cli.Context) error {
log.Error("Failed to open iterator", "root", root, "err", err) log.Error("Failed to open iterator", "root", root, "err", err)
return err return err
} }
reader, err := triedb.Reader(root) reader, err := triedb.NodeReader(root)
if err != nil { if err != nil {
log.Error("State is non-existent", "root", root) log.Error("State is non-existent", "root", root)
return nil return nil

View file

@ -8,7 +8,7 @@
"byzantiumBlock": 0, "byzantiumBlock": 0,
"constantinopleBlock": 0, "constantinopleBlock": 0,
"petersburgBlock": 0, "petersburgBlock": 0,
"terminalTotalDifficultyPassed": true, "terminalTotalDifficulty": 0,
"clique": { "clique": {
"period": 5, "period": 5,
"epoch": 30000 "epoch": 30000
@ -22,4 +22,4 @@
"balance": "300000" "balance": "300000"
} }
} }
} }

View file

@ -22,11 +22,11 @@ import (
"errors" "errors"
"fmt" "fmt"
"os" "os"
"slices"
"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/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-verkle" "github.com/ethereum/go-verkle"
cli "github.com/urfave/cli/v2" cli "github.com/urfave/cli/v2"
@ -45,7 +45,7 @@ var (
Usage: "verify the conversion of a MPT into a verkle tree", Usage: "verify the conversion of a MPT into a verkle tree",
ArgsUsage: "<root>", ArgsUsage: "<root>",
Action: verifyVerkle, Action: verifyVerkle,
Flags: flags.Merge(utils.NetworkFlags, utils.DatabaseFlags), Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: ` Description: `
geth verkle verify <state-root> geth verkle verify <state-root>
This command takes a root commitment and attempts to rebuild the tree. This command takes a root commitment and attempts to rebuild the tree.
@ -56,7 +56,7 @@ This command takes a root commitment and attempts to rebuild the tree.
Usage: "Dump a verkle tree to a DOT file", Usage: "Dump a verkle tree to a DOT file",
ArgsUsage: "<root> <key1> [<key 2> ...]", ArgsUsage: "<root> <key1> [<key 2> ...]",
Action: expandVerkle, Action: expandVerkle,
Flags: flags.Merge(utils.NetworkFlags, utils.DatabaseFlags), Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
Description: ` Description: `
geth verkle dump <state-root> <key 1> [<key 2> ...] geth verkle dump <state-root> <key 1> [<key 2> ...]
This command will produce a dot file representing the tree, rooted at <root>. This command will produce a dot file representing the tree, rooted at <root>.

View file

@ -182,7 +182,6 @@ func TestKeyID(t *testing.T) {
{"third key", args{id: extractKeyId(gethPubKeys[2])}, "FD9813B2D2098484"}, {"third key", args{id: extractKeyId(gethPubKeys[2])}, "FD9813B2D2098484"},
} }
for _, tt := range tests { for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
t.Parallel() t.Parallel()
if got := keyID(tt.args.id); got != tt.want { if got := keyID(tt.args.id); got != tt.want {

View file

@ -44,6 +44,7 @@ import (
bparams "github.com/ethereum/go-ethereum/beacon/params" bparams "github.com/ethereum/go-ethereum/beacon/params"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/fdlimit" "github.com/ethereum/go-ethereum/common/fdlimit"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/txpool/blobpool" "github.com/ethereum/go-ethereum/core/txpool/blobpool"
@ -190,12 +191,6 @@ var (
Usage: "Custom node name", Usage: "Custom node name",
Category: flags.NetworkingCategory, Category: flags.NetworkingCategory,
} }
DocRootFlag = &flags.DirectoryFlag{
Name: "docroot",
Usage: "Document Root for HTTPClient file scheme",
Value: flags.DirectoryString(flags.HomeDir()),
Category: flags.APICategory,
}
ExitWhenSyncedFlag = &cli.BoolFlag{ ExitWhenSyncedFlag = &cli.BoolFlag{
Name: "exitwhensynced", Name: "exitwhensynced",
Usage: "Exits after block synchronisation completes", Usage: "Exits after block synchronisation completes",
@ -231,8 +226,7 @@ var (
Value: 0, Value: 0,
} }
defaultSyncMode = ethconfig.Defaults.SyncMode SnapshotFlag = &cli.BoolFlag{
SnapshotFlag = &cli.BoolFlag{
Name: "snapshot", Name: "snapshot",
Usage: `Enables snapshot-database mode (default = enable)`, Usage: `Enables snapshot-database mode (default = enable)`,
Value: true, Value: true,
@ -264,10 +258,10 @@ var (
Usage: "Manually specify the Verkle fork timestamp, overriding the bundled setting", Usage: "Manually specify the Verkle fork timestamp, overriding the bundled setting",
Category: flags.EthCategory, Category: flags.EthCategory,
} }
SyncModeFlag = &flags.TextMarshalerFlag{ SyncModeFlag = &cli.StringFlag{
Name: "syncmode", Name: "syncmode",
Usage: `Blockchain sync mode ("snap" or "full")`, Usage: `Blockchain sync mode ("snap" or "full")`,
Value: &defaultSyncMode, Value: ethconfig.Defaults.SyncMode.String(),
Category: flags.StateCategory, Category: flags.StateCategory,
} }
GCModeFlag = &cli.StringFlag{ GCModeFlag = &cli.StringFlag{
@ -340,7 +334,7 @@ var (
Usage: "Target EL engine API URL", Usage: "Target EL engine API URL",
Category: flags.BeaconCategory, Category: flags.BeaconCategory,
} }
BlsyncJWTSecretFlag = &cli.StringFlag{ BlsyncJWTSecretFlag = &flags.DirectoryFlag{
Name: "blsync.jwtsecret", Name: "blsync.jwtsecret",
Usage: "Path to a JWT secret to use for target engine API endpoint", Usage: "Path to a JWT secret to use for target engine API endpoint",
Category: flags.BeaconCategory, Category: flags.BeaconCategory,
@ -544,12 +538,6 @@ var (
} }
// Account settings // Account settings
UnlockedAccountFlag = &cli.StringFlag{
Name: "unlock",
Usage: "Comma separated list of accounts to unlock",
Value: "",
Category: flags.AccountCategory,
}
PasswordFileFlag = &cli.PathFlag{ PasswordFileFlag = &cli.PathFlag{
Name: "password", Name: "password",
Usage: "Password file to use for non-interactive password input", Usage: "Password file to use for non-interactive password input",
@ -562,12 +550,6 @@ var (
Value: "", Value: "",
Category: flags.AccountCategory, Category: flags.AccountCategory,
} }
InsecureUnlockAllowedFlag = &cli.BoolFlag{
Name: "allow-insecure-unlock",
Usage: "Allow insecure account unlocking when account-related RPCs are exposed by http",
Category: flags.AccountCategory,
}
// EVM settings // EVM settings
VMEnableDebugFlag = &cli.BoolFlag{ VMEnableDebugFlag = &cli.BoolFlag{
Name: "vmdebug", Name: "vmdebug",
@ -582,6 +564,7 @@ var (
VMTraceJsonConfigFlag = &cli.StringFlag{ VMTraceJsonConfigFlag = &cli.StringFlag{
Name: "vmtrace.jsonconfig", Name: "vmtrace.jsonconfig",
Usage: "Tracer configuration (JSON)", Usage: "Tracer configuration (JSON)",
Value: "{}",
Category: flags.VMCategory, Category: flags.VMCategory,
} }
// API options. // API options.
@ -779,11 +762,6 @@ var (
Value: node.DefaultConfig.BatchResponseMaxSize, Value: node.DefaultConfig.BatchResponseMaxSize,
Category: flags.APICategory, Category: flags.APICategory,
} }
EnablePersonal = &cli.BoolFlag{
Name: "rpc.enabledeprecatedpersonal",
Usage: "Enables the (deprecated) personal namespace",
Category: flags.APICategory,
}
// Network Settings // Network Settings
MaxPeersFlag = &cli.IntFlag{ MaxPeersFlag = &cli.IntFlag{
@ -1333,33 +1311,6 @@ func MakeDatabaseHandles(max int) int {
return int(raised / 2) // Leave half for networking and other stuff return int(raised / 2) // Leave half for networking and other stuff
} }
// MakeAddress converts an account specified directly as a hex encoded string or
// a key index in the key store to an internal account representation.
func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error) {
// If the specified account is a valid address, return it
if common.IsHexAddress(account) {
return accounts.Account{Address: common.HexToAddress(account)}, nil
}
// Otherwise try to interpret the account as a keystore index
index, err := strconv.Atoi(account)
if err != nil || index < 0 {
return accounts.Account{}, fmt.Errorf("invalid account address or index %q", account)
}
log.Warn("-------------------------------------------------------------------")
log.Warn("Referring to accounts by order in the keystore folder is dangerous!")
log.Warn("This functionality is deprecated and will be removed in the future!")
log.Warn("Please use explicit addresses! (can search via `geth account list`)")
log.Warn("-------------------------------------------------------------------")
accs := ks.Accounts()
if len(accs) <= index {
return accounts.Account{}, fmt.Errorf("index %d higher than number of accounts %d", index, len(accs))
}
return accs[index], nil
}
// setEtherbase retrieves the etherbase from the directly specified command line flags. // setEtherbase retrieves the etherbase from the directly specified command line flags.
func setEtherbase(ctx *cli.Context, cfg *ethconfig.Config) { func setEtherbase(ctx *cli.Context, cfg *ethconfig.Config) {
if ctx.IsSet(MinerEtherbaseFlag.Name) { if ctx.IsSet(MinerEtherbaseFlag.Name) {
@ -1382,27 +1333,6 @@ func setEtherbase(ctx *cli.Context, cfg *ethconfig.Config) {
cfg.Miner.Etherbase = common.BytesToAddress(b) cfg.Miner.Etherbase = common.BytesToAddress(b)
} }
// MakePasswordList reads password lines from the file specified by the global --password flag.
func MakePasswordList(ctx *cli.Context) []string {
path := ctx.Path(PasswordFileFlag.Name)
if path == "" {
return nil
}
text, err := os.ReadFile(path)
if err != nil {
Fatalf("Failed to read password file: %v", err)
}
lines := strings.Split(string(text), "\n")
// Sanitise DOS line endings.
for i := range lines {
lines[i] = strings.TrimRight(lines[i], "\r")
}
return lines
}
func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) { func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) {
setNodeKey(ctx, cfg) setNodeKey(ctx, cfg)
setNAT(ctx, cfg) setNAT(ctx, cfg)
@ -1461,9 +1391,8 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) {
if ctx.IsSet(JWTSecretFlag.Name) { if ctx.IsSet(JWTSecretFlag.Name) {
cfg.JWTSecret = ctx.String(JWTSecretFlag.Name) cfg.JWTSecret = ctx.String(JWTSecretFlag.Name)
} }
if ctx.IsSet(EnablePersonal.Name) { if ctx.IsSet(EnablePersonal.Name) {
cfg.EnablePersonal = true log.Warn(fmt.Sprintf("Option --%s is deprecated. The 'personal' RPC namespace has been removed.", EnablePersonal.Name))
} }
if ctx.IsSet(ExternalSignerFlag.Name) { if ctx.IsSet(ExternalSignerFlag.Name) {
@ -1491,7 +1420,7 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) {
} }
if ctx.IsSet(InsecureUnlockAllowedFlag.Name) { if ctx.IsSet(InsecureUnlockAllowedFlag.Name) {
cfg.InsecureUnlockAllowed = ctx.Bool(InsecureUnlockAllowedFlag.Name) log.Warn(fmt.Sprintf("Option %q is deprecated and has no effect", InsecureUnlockAllowedFlag.Name))
} }
if ctx.IsSet(DBEngineFlag.Name) { if ctx.IsSet(DBEngineFlag.Name) {
@ -1771,7 +1700,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
if ctx.IsSet(SyncTargetFlag.Name) { if ctx.IsSet(SyncTargetFlag.Name) {
cfg.SyncMode = downloader.FullSync // dev sync target forces full sync cfg.SyncMode = downloader.FullSync // dev sync target forces full sync
} else if ctx.IsSet(SyncModeFlag.Name) { } else if ctx.IsSet(SyncModeFlag.Name) {
cfg.SyncMode = *flags.GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode) if err = cfg.SyncMode.UnmarshalText([]byte(ctx.String(SyncModeFlag.Name))); err != nil {
Fatalf("invalid --syncmode flag: %v", err)
}
} }
if ctx.IsSet(NetworkIdFlag.Name) { if ctx.IsSet(NetworkIdFlag.Name) {
@ -1862,11 +1793,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
cfg.SnapshotCache = 0 // Disabled cfg.SnapshotCache = 0 // Disabled
} }
} }
if ctx.IsSet(DocRootFlag.Name) {
cfg.DocRoot = ctx.String(DocRootFlag.Name)
}
if ctx.IsSet(VMEnableDebugFlag.Name) { if ctx.IsSet(VMEnableDebugFlag.Name) {
// TODO(fjl): force-enable this in --dev mode // TODO(fjl): force-enable this in --dev mode
cfg.EnablePreimageRecording = ctx.Bool(VMEnableDebugFlag.Name) cfg.EnablePreimageRecording = ctx.Bool(VMEnableDebugFlag.Name)
@ -1928,14 +1854,15 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
passphrase string passphrase string
err error err error
) )
if path := ctx.Path(PasswordFileFlag.Name); path != "" {
if list := MakePasswordList(ctx); len(list) > 0 { if text, err := os.ReadFile(path); err != nil {
// Just take the first value. Although the function returns a possible multiple values and Fatalf("Failed to read password file: %v", err)
// some usages iterate through them as attempts, that doesn't make sense in this setting, } else {
// when we're definitely concerned with only one account. if lines := strings.Split(string(text), "\n"); len(lines) > 0 {
passphrase = list[0] passphrase = strings.TrimRight(lines[0], "\r") // Sanitise DOS line endings.
}
}
} }
// Unlock the developer account by local keystore. // Unlock the developer account by local keystore.
var ks *keystore.KeyStore var ks *keystore.KeyStore
if keystores := stack.AccountManager().Backends(keystore.KeyStoreType); len(keystores) > 0 { if keystores := stack.AccountManager().Backends(keystore.KeyStoreType); len(keystores) > 0 {
@ -1980,9 +1907,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
if err != nil { if err != nil {
Fatalf("Could not read genesis from database: %v", err) Fatalf("Could not read genesis from database: %v", err)
} }
if !genesis.Config.TerminalTotalDifficultyPassed {
Fatalf("Bad developer-mode genesis configuration: terminalTotalDifficultyPassed must be true")
}
if genesis.Config.TerminalTotalDifficulty == nil { if genesis.Config.TerminalTotalDifficulty == nil {
Fatalf("Bad developer-mode genesis configuration: terminalTotalDifficulty must be specified") Fatalf("Bad developer-mode genesis configuration: terminalTotalDifficulty must be specified")
} else if genesis.Config.TerminalTotalDifficulty.Cmp(big.NewInt(0)) != 0 { } else if genesis.Config.TerminalTotalDifficulty.Cmp(big.NewInt(0)) != 0 {
@ -2016,17 +1940,87 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
// VM tracing config. // VM tracing config.
if ctx.IsSet(VMTraceFlag.Name) { if ctx.IsSet(VMTraceFlag.Name) {
if name := ctx.String(VMTraceFlag.Name); name != "" { if name := ctx.String(VMTraceFlag.Name); name != "" {
var config string
if ctx.IsSet(VMTraceJsonConfigFlag.Name) {
config = ctx.String(VMTraceJsonConfigFlag.Name)
}
cfg.VMTrace = name cfg.VMTrace = name
cfg.VMTraceJsonConfig = config cfg.VMTraceJsonConfig = ctx.String(VMTraceJsonConfigFlag.Name)
} }
} }
} }
// MakeBeaconLightConfig constructs a beacon light client config based on the
// related command line flags.
func MakeBeaconLightConfig(ctx *cli.Context) bparams.ClientConfig {
var config bparams.ClientConfig
customConfig := ctx.IsSet(BeaconConfigFlag.Name)
CheckExclusive(ctx, MainnetFlag, SepoliaFlag, HoleskyFlag, BeaconConfigFlag)
switch {
case ctx.Bool(MainnetFlag.Name):
config.ChainConfig = *bparams.MainnetLightConfig
case ctx.Bool(SepoliaFlag.Name):
config.ChainConfig = *bparams.SepoliaLightConfig
case ctx.Bool(HoleskyFlag.Name):
config.ChainConfig = *bparams.HoleskyLightConfig
default:
if !customConfig {
config.ChainConfig = *bparams.MainnetLightConfig
}
}
// Genesis root and time should always be specified together with custom chain config
if customConfig {
if !ctx.IsSet(BeaconGenesisRootFlag.Name) {
Fatalf("Custom beacon chain config is specified but genesis root is missing")
}
if !ctx.IsSet(BeaconGenesisTimeFlag.Name) {
Fatalf("Custom beacon chain config is specified but genesis time is missing")
}
if !ctx.IsSet(BeaconCheckpointFlag.Name) {
Fatalf("Custom beacon chain config is specified but checkpoint is missing")
}
config.ChainConfig = bparams.ChainConfig{
GenesisTime: ctx.Uint64(BeaconGenesisTimeFlag.Name),
}
if c, err := hexutil.Decode(ctx.String(BeaconGenesisRootFlag.Name)); err == nil && len(c) <= 32 {
copy(config.GenesisValidatorsRoot[:len(c)], c)
} else {
Fatalf("Invalid hex string", "beacon.genesis.gvroot", ctx.String(BeaconGenesisRootFlag.Name), "error", err)
}
configFile := ctx.String(BeaconConfigFlag.Name)
if err := config.ChainConfig.LoadForks(configFile); err != nil {
Fatalf("Could not load beacon chain config", "file", configFile, "error", err)
}
log.Info("Using custom beacon chain config", "file", configFile)
} else {
if ctx.IsSet(BeaconGenesisRootFlag.Name) {
Fatalf("Genesis root is specified but custom beacon chain config is missing")
}
if ctx.IsSet(BeaconGenesisTimeFlag.Name) {
Fatalf("Genesis time is specified but custom beacon chain config is missing")
}
}
// Checkpoint is required with custom chain config and is optional with pre-defined config
if ctx.IsSet(BeaconCheckpointFlag.Name) {
if c, err := hexutil.Decode(ctx.String(BeaconCheckpointFlag.Name)); err == nil && len(c) <= 32 {
copy(config.Checkpoint[:len(c)], c)
} else {
Fatalf("Invalid hex string", "beacon.checkpoint", ctx.String(BeaconCheckpointFlag.Name), "error", err)
}
}
config.Apis = ctx.StringSlice(BeaconApiFlag.Name)
if config.Apis == nil {
Fatalf("Beacon node light client API URL not specified")
}
config.CustomHeader = make(map[string]string)
for _, s := range ctx.StringSlice(BeaconApiHeaderFlag.Name) {
kv := strings.Split(s, ":")
if len(kv) != 2 {
Fatalf("Invalid custom API header entry: %s", s)
}
config.CustomHeader[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1])
}
config.Threshold = ctx.Int(BeaconThresholdFlag.Name)
config.NoFilter = ctx.Bool(BeaconNoFilterFlag.Name)
return config
}
// SetDNSDiscoveryDefaults configures DNS discovery with the given URL if // SetDNSDiscoveryDefaults configures DNS discovery with the given URL if
// no URLs are set. // no URLs are set.
func SetDNSDiscoveryDefaults(cfg *ethconfig.Config, genesis common.Hash) { func SetDNSDiscoveryDefaults(cfg *ethconfig.Config, genesis common.Hash) {
@ -2339,10 +2333,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
} }
if ctx.IsSet(VMTraceFlag.Name) { if ctx.IsSet(VMTraceFlag.Name) {
if name := ctx.String(VMTraceFlag.Name); name != "" { if name := ctx.String(VMTraceFlag.Name); name != "" {
var config json.RawMessage config := json.RawMessage(ctx.String(VMTraceJsonConfigFlag.Name))
if ctx.IsSet(VMTraceJsonConfigFlag.Name) {
config = json.RawMessage(ctx.String(VMTraceJsonConfigFlag.Name))
}
t, err := tracers.LiveDirectory.New(name, config) t, err := tracers.LiveDirectory.New(name, config)
if err != nil { if err != nil {
Fatalf("Failed to create tracer %q: %v", name, err) Fatalf("Failed to create tracer %q: %v", name, err)

View file

@ -153,6 +153,23 @@ var (
Usage: "Enable expensive metrics collection and reporting (deprecated)", Usage: "Enable expensive metrics collection and reporting (deprecated)",
Category: flags.DeprecatedCategory, Category: flags.DeprecatedCategory,
} }
// Deprecated Oct 2024
EnablePersonal = &cli.BoolFlag{
Name: "rpc.enabledeprecatedpersonal",
Usage: "This used to enable the 'personal' namespace.",
Category: flags.DeprecatedCategory,
}
UnlockedAccountFlag = &cli.StringFlag{
Name: "unlock",
Usage: "Comma separated list of accounts to unlock (deprecated)",
Value: "",
Category: flags.DeprecatedCategory,
}
InsecureUnlockAllowedFlag = &cli.BoolFlag{
Name: "allow-insecure-unlock",
Usage: "Allow insecure account unlocking when account-related RPCs are exposed by http (deprecated)",
Category: flags.DeprecatedCategory,
}
) )
// showDeprecated displays deprecated flags that will be soon removed from the codebase. // showDeprecated displays deprecated flags that will be soon removed from the codebase.

View file

@ -56,7 +56,6 @@ func Test_SplitTagsFlag(t *testing.T) {
}, },
} }
for _, tt := range tests { for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
t.Parallel() t.Parallel()
if got := SplitTagsFlag(tt.args); !reflect.DeepEqual(got, tt.want) { if got := SplitTagsFlag(tt.args); !reflect.DeepEqual(got, tt.want) {

View file

@ -49,20 +49,3 @@ func GetPassPhrase(text string, confirmation bool) string {
return password return password
} }
// GetPassPhraseWithList retrieves the password associated with an account, either fetched
// from a list of preloaded passphrases, or requested interactively from the user.
func GetPassPhraseWithList(text string, confirmation bool, index int, passwords []string) string {
// If a list of passwords was supplied, retrieve from them
if len(passwords) > 0 {
if index < len(passwords) {
return passwords[index]
}
return passwords[len(passwords)-1]
}
// Otherwise prompt the user for the password
password := GetPassPhrase(text, confirmation)
return password
}

View file

@ -1,78 +0,0 @@
// Copyright 2020 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
// Package utils contains internal helper functions for go-ethereum commands.
package utils
import (
"testing"
)
func TestGetPassPhraseWithList(t *testing.T) {
t.Parallel()
type args struct {
text string
confirmation bool
index int
passwords []string
}
tests := []struct {
name string
args args
want string
}{
{
"test1",
args{
"text1",
false,
0,
[]string{"zero", "one", "two"},
},
"zero",
},
{
"test2",
args{
"text2",
false,
5,
[]string{"zero", "one", "two"},
},
"two",
},
{
"test3",
args{
"text3",
true,
1,
[]string{"zero", "one", "two"},
},
"one",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if got := GetPassPhraseWithList(tt.args.text, tt.args.confirmation, tt.args.index, tt.args.passwords); got != tt.want {
t.Errorf("GetPassPhraseWithList() = %v, want %v", got, tt.want)
}
})
}
}

View file

@ -20,18 +20,13 @@ package math
import ( import (
"fmt" "fmt"
"math/big" "math/big"
"github.com/holiman/uint256"
) )
// Various big integer limit values. // Various big integer limit values.
var ( var (
tt255 = BigPow(2, 255)
tt256 = BigPow(2, 256) tt256 = BigPow(2, 256)
tt256m1 = new(big.Int).Sub(tt256, big.NewInt(1)) tt256m1 = new(big.Int).Sub(tt256, big.NewInt(1))
tt63 = BigPow(2, 63)
MaxBig256 = new(big.Int).Set(tt256m1) MaxBig256 = new(big.Int).Set(tt256m1)
MaxBig63 = new(big.Int).Sub(tt63, big.NewInt(1))
) )
const ( const (
@ -163,56 +158,6 @@ func BigPow(a, b int64) *big.Int {
return r.Exp(r, big.NewInt(b), nil) return r.Exp(r, big.NewInt(b), nil)
} }
// BigMax returns the larger of x or y.
func BigMax(x, y *big.Int) *big.Int {
if x.Cmp(y) < 0 {
return y
}
return x
}
func BigMaxUint(x, y *uint256.Int) *uint256.Int {
if x.Lt(y) {
return y
}
return x
}
// BigMin returns the smaller of x or y.
func BigMin(x, y *big.Int) *big.Int {
if x.Cmp(y) > 0 {
return y
}
return x
}
func BigMinUint256(x, y *uint256.Int) *uint256.Int {
if x.Gt(y) {
return y
}
return x
}
// todo: @anshalshukla - check implementation correctness
func BigIntToUint256Int(x *big.Int) *uint256.Int {
return new(uint256.Int).SetBytes(x.Bytes())
}
// FirstBitSet returns the index of the first 1 bit in v, counting from LSB.
func FirstBitSet(v *big.Int) int {
for i := 0; i < v.BitLen(); i++ {
if v.Bit(i) > 0 {
return i
}
}
return v.BitLen()
}
// PaddedBigBytes encodes a big integer as a big-endian byte slice. The length // PaddedBigBytes encodes a big integer as a big-endian byte slice. The length
// of the slice is at least n bytes. // of the slice is at least n bytes.
func PaddedBigBytes(bigint *big.Int, n int) []byte { func PaddedBigBytes(bigint *big.Int, n int) []byte {
@ -226,36 +171,6 @@ func PaddedBigBytes(bigint *big.Int, n int) []byte {
return ret return ret
} }
// bigEndianByteAt returns the byte at position n,
// in Big-Endian encoding
// So n==0 returns the least significant byte
func bigEndianByteAt(bigint *big.Int, n int) byte {
words := bigint.Bits()
// Check word-bucket the byte will reside in
i := n / wordBytes
if i >= len(words) {
return byte(0)
}
word := words[i]
// Offset of the byte
shift := 8 * uint(n%wordBytes)
return byte(word >> shift)
}
// Byte returns the byte at position n,
// with the supplied padlength in Little-Endian encoding.
// n==0 returns the MSB
// Example: bigint '5', padlength 32, n=31 => 5
func Byte(bigint *big.Int, padlength, n int) byte {
if n >= padlength {
return byte(0)
}
return bigEndianByteAt(bigint, padlength-1-n)
}
// ReadBits encodes the absolute value of bigint as big-endian bytes. Callers must ensure // ReadBits encodes the absolute value of bigint as big-endian bytes. Callers must ensure
// that buf has enough space. If buf is too short the result will be incomplete. // that buf has enough space. If buf is too short the result will be incomplete.
func ReadBits(bigint *big.Int, buf []byte) { func ReadBits(bigint *big.Int, buf []byte) {
@ -279,40 +194,3 @@ func U256(x *big.Int) *big.Int {
func U256Bytes(n *big.Int) []byte { func U256Bytes(n *big.Int) []byte {
return PaddedBigBytes(U256(n), 32) return PaddedBigBytes(U256(n), 32)
} }
// S256 interprets x as a two's complement number.
// x must not exceed 256 bits (the result is undefined if it does) and is not modified.
//
// S256(0) = 0
// S256(1) = 1
// S256(2**255) = -2**255
// S256(2**256-1) = -1
func S256(x *big.Int) *big.Int {
if x.Cmp(tt255) < 0 {
return x
}
return new(big.Int).Sub(x, tt256)
}
// Exp implements exponentiation by squaring.
// Exp returns a newly-allocated big integer and does not change
// base or exponent. The result is truncated to 256 bits.
//
// Courtesy @karalabe and @chfast
func Exp(base, exponent *big.Int) *big.Int {
copyBase := new(big.Int).Set(base)
result := big.NewInt(1)
for _, word := range exponent.Bits() {
for i := 0; i < wordBits; i++ {
if word&1 == 1 {
U256(result.Mul(result, copyBase))
}
U256(copyBase.Mul(copyBase, copyBase))
word >>= 1
}
}
return result
}

View file

@ -21,8 +21,6 @@ import (
"encoding/hex" "encoding/hex"
"math/big" "math/big"
"testing" "testing"
"github.com/ethereum/go-ethereum/common"
) )
func TestHexOrDecimal256(t *testing.T) { func TestHexOrDecimal256(t *testing.T) {
@ -72,53 +70,6 @@ func TestMustParseBig256(t *testing.T) {
MustParseBig256("ggg") MustParseBig256("ggg")
} }
func TestBigMax(t *testing.T) {
a := big.NewInt(10)
b := big.NewInt(5)
max1 := BigMax(a, b)
if max1 != a {
t.Errorf("Expected %d got %d", a, max1)
}
max2 := BigMax(b, a)
if max2 != a {
t.Errorf("Expected %d got %d", a, max2)
}
}
func TestBigMin(t *testing.T) {
a := big.NewInt(10)
b := big.NewInt(5)
min1 := BigMin(a, b)
if min1 != b {
t.Errorf("Expected %d got %d", b, min1)
}
min2 := BigMin(b, a)
if min2 != b {
t.Errorf("Expected %d got %d", b, min2)
}
}
func TestFirstBigSet(t *testing.T) {
tests := []struct {
num *big.Int
ix int
}{
{big.NewInt(0), 0},
{big.NewInt(1), 0},
{big.NewInt(2), 1},
{big.NewInt(0x100), 8},
}
for _, test := range tests {
if ix := FirstBitSet(test.num); ix != test.ix {
t.Errorf("FirstBitSet(b%b) = %d, want %d", test.num, ix, test.ix)
}
}
}
func TestPaddedBigBytes(t *testing.T) { func TestPaddedBigBytes(t *testing.T) {
tests := []struct { tests := []struct {
num *big.Int num *big.Int
@ -158,20 +109,6 @@ func BenchmarkPaddedBigBytesSmallOnePadding(b *testing.B) {
} }
} }
func BenchmarkByteAtBrandNew(b *testing.B) {
bigint := MustParseBig256("0x18F8F8F1000111000110011100222004330052300000000000000000FEFCF3CC")
for i := 0; i < b.N; i++ {
bigEndianByteAt(bigint, 15)
}
}
func BenchmarkByteAt(b *testing.B) {
bigint := MustParseBig256("0x18F8F8F1000111000110011100222004330052300000000000000000FEFCF3CC")
for i := 0; i < b.N; i++ {
bigEndianByteAt(bigint, 15)
}
}
func BenchmarkByteAtOld(b *testing.B) { func BenchmarkByteAtOld(b *testing.B) {
bigint := MustParseBig256("0x18F8F8F1000111000110011100222004330052300000000000000000FEFCF3CC") bigint := MustParseBig256("0x18F8F8F1000111000110011100222004330052300000000000000000FEFCF3CC")
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
@ -222,107 +159,3 @@ func TestU256Bytes(t *testing.T) {
t.Errorf("expected %x got %x", ubytes, unsigned) t.Errorf("expected %x got %x", ubytes, unsigned)
} }
} }
func TestBigEndianByteAt(t *testing.T) {
tests := []struct {
x string
y int
exp byte
}{
{"00", 0, 0x00},
{"01", 1, 0x00},
{"00", 1, 0x00},
{"01", 0, 0x01},
{"0000000000000000000000000000000000000000000000000000000000102030", 0, 0x30},
{"0000000000000000000000000000000000000000000000000000000000102030", 1, 0x20},
{"ABCDEF0908070605040302010000000000000000000000000000000000000000", 31, 0xAB},
{"ABCDEF0908070605040302010000000000000000000000000000000000000000", 32, 0x00},
{"ABCDEF0908070605040302010000000000000000000000000000000000000000", 500, 0x00},
}
for _, test := range tests {
v := new(big.Int).SetBytes(common.Hex2Bytes(test.x))
actual := bigEndianByteAt(v, test.y)
if actual != test.exp {
t.Fatalf("Expected [%v] %v:th byte to be %v, was %v.", test.x, test.y, test.exp, actual)
}
}
}
func TestLittleEndianByteAt(t *testing.T) {
tests := []struct {
x string
y int
exp byte
}{
{"00", 0, 0x00},
{"01", 1, 0x00},
{"00", 1, 0x00},
{"01", 0, 0x00},
{"0000000000000000000000000000000000000000000000000000000000102030", 0, 0x00},
{"0000000000000000000000000000000000000000000000000000000000102030", 1, 0x00},
{"ABCDEF0908070605040302010000000000000000000000000000000000000000", 31, 0x00},
{"ABCDEF0908070605040302010000000000000000000000000000000000000000", 32, 0x00},
{"ABCDEF0908070605040302010000000000000000000000000000000000000000", 0, 0xAB},
{"ABCDEF0908070605040302010000000000000000000000000000000000000000", 1, 0xCD},
{"00CDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff", 0, 0x00},
{"00CDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff", 1, 0xCD},
{"0000000000000000000000000000000000000000000000000000000000102030", 31, 0x30},
{"0000000000000000000000000000000000000000000000000000000000102030", 30, 0x20},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 32, 0x0},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 31, 0xFF},
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 0xFFFF, 0x0},
}
for _, test := range tests {
v := new(big.Int).SetBytes(common.Hex2Bytes(test.x))
actual := Byte(v, 32, test.y)
if actual != test.exp {
t.Fatalf("Expected [%v] %v:th byte to be %v, was %v.", test.x, test.y, test.exp, actual)
}
}
}
func TestS256(t *testing.T) {
tests := []struct{ x, y *big.Int }{
{x: big.NewInt(0), y: big.NewInt(0)},
{x: big.NewInt(1), y: big.NewInt(1)},
{x: big.NewInt(2), y: big.NewInt(2)},
{
x: new(big.Int).Sub(BigPow(2, 255), big.NewInt(1)),
y: new(big.Int).Sub(BigPow(2, 255), big.NewInt(1)),
},
{
x: BigPow(2, 255),
y: new(big.Int).Neg(BigPow(2, 255)),
},
{
x: new(big.Int).Sub(BigPow(2, 256), big.NewInt(1)),
y: big.NewInt(-1),
},
{
x: new(big.Int).Sub(BigPow(2, 256), big.NewInt(2)),
y: big.NewInt(-2),
},
}
for _, test := range tests {
if y := S256(test.x); y.Cmp(test.y) != 0 {
t.Errorf("S256(%x) = %x, want %x", test.x, y, test.y)
}
}
}
func TestExp(t *testing.T) {
tests := []struct{ base, exponent, result *big.Int }{
{base: big.NewInt(0), exponent: big.NewInt(0), result: big.NewInt(1)},
{base: big.NewInt(1), exponent: big.NewInt(0), result: big.NewInt(1)},
{base: big.NewInt(1), exponent: big.NewInt(1), result: big.NewInt(1)},
{base: big.NewInt(1), exponent: big.NewInt(2), result: big.NewInt(1)},
{base: big.NewInt(3), exponent: big.NewInt(144), result: MustParseBig256("507528786056415600719754159741696356908742250191663887263627442114881")},
{base: big.NewInt(2), exponent: big.NewInt(255), result: MustParseBig256("57896044618658097711785492504343953926634992332820282019728792003956564819968")},
}
for _, test := range tests {
if result := Exp(test.base, test.exponent); result.Cmp(test.result) != 0 {
t.Errorf("Exp(%d, %d) = %d, want %d", test.base, test.exponent, result, test.result)
}
}
}

View file

@ -22,22 +22,6 @@ import (
"strconv" "strconv"
) )
// Integer limit values.
const (
MaxInt8 = 1<<7 - 1
MinInt8 = -1 << 7
MaxInt16 = 1<<15 - 1
MinInt16 = -1 << 15
MaxInt32 = 1<<31 - 1
MinInt32 = -1 << 31
MaxInt64 = 1<<63 - 1
MinInt64 = -1 << 63
MaxUint8 = 1<<8 - 1
MaxUint16 = 1<<16 - 1
MaxUint32 = 1<<32 - 1
MaxUint64 = 1<<64 - 1
)
// HexOrDecimal64 marshals uint64 as hex or decimal. // HexOrDecimal64 marshals uint64 as hex or decimal.
type HexOrDecimal64 uint64 type HexOrDecimal64 uint64

View file

@ -17,6 +17,7 @@
package math package math
import ( import (
"math"
"testing" "testing"
) )
@ -36,8 +37,8 @@ func TestOverflow(t *testing.T) {
op operation op operation
}{ }{
// add operations // add operations
{MaxUint64, 1, true, add}, {math.MaxUint64, 1, true, add},
{MaxUint64 - 1, 1, false, add}, {math.MaxUint64 - 1, 1, false, add},
// sub operations // sub operations
{0, 1, true, sub}, {0, 1, true, sub},
@ -46,8 +47,8 @@ func TestOverflow(t *testing.T) {
// mul operations // mul operations
{0, 0, false, mul}, {0, 0, false, mul},
{10, 10, false, mul}, {10, 10, false, mul},
{MaxUint64, 2, true, mul}, {math.MaxUint64, 2, true, mul},
{MaxUint64, 1, false, mul}, {math.MaxUint64, 1, false, mul},
} { } {
var overflows bool var overflows bool

View file

@ -28,7 +28,6 @@ func FileExist(filePath string) bool {
if err != nil && os.IsNotExist(err) { if err != nil && os.IsNotExist(err) {
return false return false
} }
return true return true
} }

View file

@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
@ -115,9 +116,6 @@ func errOut(n int, err error) chan error {
func (beacon *Beacon) splitHeaders(chain consensus.ChainHeaderReader, headers []*types.Header) ([]*types.Header, []*types.Header, error) { func (beacon *Beacon) splitHeaders(chain consensus.ChainHeaderReader, headers []*types.Header) ([]*types.Header, []*types.Header, error) {
// TTD is not defined yet, all headers should be in legacy format. // TTD is not defined yet, all headers should be in legacy format.
ttd := chain.Config().TerminalTotalDifficulty ttd := chain.Config().TerminalTotalDifficulty
if ttd == nil {
return headers, nil, nil
}
ptd := chain.GetTd(headers[0].ParentHash, headers[0].Number.Uint64()-1) ptd := chain.GetTd(headers[0].ParentHash, headers[0].Number.Uint64()-1)
if ptd == nil { if ptd == nil {
return nil, nil, consensus.ErrUnknownAncestor return nil, nil, consensus.ErrUnknownAncestor
@ -349,7 +347,7 @@ func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.H
} }
// Finalize implements consensus.Engine and processes withdrawals on top. // Finalize implements consensus.Engine and processes withdrawals on top.
func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body) { func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state vm.StateDB, body *types.Body) {
if !beacon.IsPoSHeader(header) { if !beacon.IsPoSHeader(header) {
beacon.ethone.Finalize(chain, header, state, body) beacon.ethone.Finalize(chain, header, state, body)
return return
@ -401,21 +399,25 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
if parent == nil { if parent == nil {
return nil, fmt.Errorf("nil parent header for block %d", header.Number) return nil, fmt.Errorf("nil parent header for block %d", header.Number)
} }
preTrie, err := state.Database().OpenTrie(parent.Root) preTrie, err := state.Database().OpenTrie(parent.Root)
if err != nil { if err != nil {
return nil, fmt.Errorf("error opening pre-state tree root: %w", err) return nil, fmt.Errorf("error opening pre-state tree root: %w", err)
} }
vktPreTrie, okpre := preTrie.(*trie.VerkleTrie) vktPreTrie, okpre := preTrie.(*trie.VerkleTrie)
vktPostTrie, okpost := state.GetTrie().(*trie.VerkleTrie) vktPostTrie, okpost := state.GetTrie().(*trie.VerkleTrie)
// The witness is only attached iff both parent and current block are
// using verkle tree.
if okpre && okpost { if okpre && okpost {
if len(keys) > 0 { if len(keys) > 0 {
verkleProof, stateDiff, err := vktPreTrie.Proof(vktPostTrie, keys, vktPreTrie.FlatdbNodeResolver) verkleProof, stateDiff, err := vktPreTrie.Proof(vktPostTrie, keys)
if err != nil { if err != nil {
return nil, fmt.Errorf("error generating verkle proof for block %d: %w", header.Number, err) return nil, fmt.Errorf("error generating verkle proof for block %d: %w", header.Number, err)
} }
block = block.WithWitness(&types.ExecutionWitness{StateDiff: stateDiff, VerkleProof: verkleProof}) block = block.WithWitness(&types.ExecutionWitness{
StateDiff: stateDiff,
VerkleProof: verkleProof,
})
} }
} }
} }
@ -495,9 +497,6 @@ func (beacon *Beacon) SetThreads(threads int) {
// It depends on the parentHash already being stored in the database. // It depends on the parentHash already being stored in the database.
// If the parentHash is not stored in the database a UnknownAncestor error is returned. // If the parentHash is not stored in the database a UnknownAncestor error is returned.
func IsTTDReached(chain consensus.ChainHeaderReader, parentHash common.Hash, parentNumber uint64) (bool, error) { func IsTTDReached(chain consensus.ChainHeaderReader, parentHash common.Hash, parentNumber uint64) (bool, error) {
if chain.Config().TerminalTotalDifficulty == nil {
return false, nil
}
td := chain.GetTd(parentHash, parentNumber) td := chain.GetTd(parentHash, parentNumber)
if td == nil { if td == nil {
return false, consensus.ErrUnknownAncestor return false, consensus.ErrUnknownAncestor

View file

@ -27,7 +27,6 @@ import (
"sync" "sync"
"time" "time"
"github.com/ethereum/go-ethereum/accounts"
"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"
"github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/common/lru"
@ -36,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/consensus/misc/eip1559"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "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/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
@ -50,8 +50,6 @@ const (
checkpointInterval = 1024 // Number of blocks after which to save the vote snapshot to the database checkpointInterval = 1024 // Number of blocks after which to save the vote snapshot to the database
inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory inmemorySnapshots = 128 // Number of recent vote snapshots to keep in memory
inmemorySignatures = 4096 // Number of recent block signatures to keep in memory inmemorySignatures = 4096 // Number of recent block signatures to keep in memory
wiggleTime = 500 * time.Millisecond // Random delay (per signer) to allow concurrent signers
) )
// Clique proof-of-authority protocol constants. // Clique proof-of-authority protocol constants.
@ -140,9 +138,6 @@ var (
errRecentlySigned = errors.New("recently signed") errRecentlySigned = errors.New("recently signed")
) )
// SignerFn hashes and signs the data to be signed by a backing account.
type SignerFn func(signer accounts.Account, mimeType string, message []byte) ([]byte, error)
// ecrecover extracts the Ethereum account address from a signed header. // ecrecover extracts the Ethereum account address from a signed header.
func ecrecover(header *types.Header, sigcache *sigLRU) (common.Address, error) { func ecrecover(header *types.Header, sigcache *sigLRU) (common.Address, error) {
// If the signature's already cached, return that // If the signature's already cached, return that
@ -184,7 +179,6 @@ type Clique struct {
proposals map[common.Address]bool // Current list of proposals we are pushing proposals map[common.Address]bool // Current list of proposals we are pushing
signer common.Address // Ethereum address of the signing key signer common.Address // Ethereum address of the signing key
signFn SignerFn // Signer function to authorize hashes with
lock sync.RWMutex // Protects the signer and proposals fields lock sync.RWMutex // Protects the signer and proposals fields
// The fields below are for testing only // The fields below are for testing only
@ -619,7 +613,7 @@ func (c *Clique) Prepare(chain consensus.ChainHeaderReader, header *types.Header
// Finalize implements consensus.Engine. There is no post-transaction // Finalize implements consensus.Engine. There is no post-transaction
// consensus rules in clique, do nothing here. // consensus rules in clique, do nothing here.
func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body) { func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state vm.StateDB, body *types.Body) {
// No block rewards in PoA, so the state remains as is // No block rewards in PoA, so the state remains as is
} }
@ -641,17 +635,17 @@ func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *
// Authorize injects a private key into the consensus engine to mint new blocks // Authorize injects a private key into the consensus engine to mint new blocks
// with. // with.
func (c *Clique) Authorize(signer common.Address, signFn SignerFn) { func (c *Clique) Authorize(signer common.Address) {
c.lock.Lock() c.lock.Lock()
defer c.lock.Unlock() defer c.lock.Unlock()
c.signer = signer c.signer = signer
c.signFn = signFn
} }
// Seal implements consensus.Engine, attempting to create a sealed block using // Seal implements consensus.Engine, attempting to create a sealed block using
// the local signing credentials. // the local signing credentials.
func (c *Clique) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { func (c *Clique) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
// (PoS): Geth doesn't support sealing on clique but we'll keep it for running bor in dev mode.
header := block.Header() header := block.Header()
// Sealing the genesis block is not supported // Sealing the genesis block is not supported

View file

@ -23,6 +23,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
) )
@ -88,7 +89,7 @@ type Engine interface {
// //
// Note: The state database might be updated to reflect any consensus rules // Note: The state database might be updated to reflect any consensus rules
// that happen at finalization (e.g. block rewards). // that happen at finalization (e.g. block rewards).
Finalize(chain ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body) Finalize(chain ChainHeaderReader, header *types.Header, state vm.StateDB, body *types.Body)
// FinalizeAndAssemble runs any post-transaction state modifications (e.g. block // FinalizeAndAssemble runs any post-transaction state modifications (e.g. block
// rewards or process withdrawals) and assembles the final block. // rewards or process withdrawals) and assembles the final block.

View file

@ -24,13 +24,13 @@ import (
mapset "github.com/deckarep/golang-set/v2" mapset "github.com/deckarep/golang-set/v2"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/consensus/misc"
"github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/consensus/misc/eip1559"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
@ -481,7 +481,9 @@ func calcDifficultyFrontier(time uint64, parent *types.Header) *big.Int {
expDiff := periodCount.Sub(periodCount, big2) expDiff := periodCount.Sub(periodCount, big2)
expDiff.Exp(big2, expDiff, nil) expDiff.Exp(big2, expDiff, nil)
diff.Add(diff, expDiff) diff.Add(diff, expDiff)
diff = math.BigMax(diff, params.MinimumDifficulty) if diff.Cmp(params.MinimumDifficulty) < 0 {
diff = params.MinimumDifficulty
}
} }
return diff return diff
} }
@ -503,7 +505,7 @@ func (ethash *Ethash) Prepare(chain consensus.ChainHeaderReader, header *types.H
} }
// Finalize implements consensus.Engine, accumulating the block and uncle rewards. // Finalize implements consensus.Engine, accumulating the block and uncle rewards.
func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body) { func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state vm.StateDB, body *types.Body) {
// Accumulate any block and uncle rewards // Accumulate any block and uncle rewards
accumulateRewards(chain.Config(), state, header, body.Uncles) accumulateRewards(chain.Config(), state, header, body.Uncles)
} }
@ -566,7 +568,7 @@ func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) {
// accumulateRewards credits the coinbase of the given block with the mining // accumulateRewards credits the coinbase of the given block with the mining
// reward. The total reward consists of the static block reward and rewards for // reward. The total reward consists of the static block reward and rewards for
// included uncles. The coinbase of each uncle block is also rewarded. // included uncles. The coinbase of each uncle block is also rewarded.
func accumulateRewards(config *params.ChainConfig, stateDB *state.StateDB, header *types.Header, uncles []*types.Header) { func accumulateRewards(config *params.ChainConfig, stateDB vm.StateDB, header *types.Header, uncles []*types.Header) {
// Select the correct block reward based on chain progression // Select the correct block reward based on chain progression
blockReward := FrontierBlockReward blockReward := FrontierBlockReward
if config.IsByzantium(header.Number) { if config.IsByzantium(header.Number) {

View file

@ -21,11 +21,10 @@ import (
"errors" "errors"
"math/big" "math/big"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
) )
var ( var (
@ -74,7 +73,7 @@ func VerifyDAOHeaderExtraData(config *params.ChainConfig, header *types.Header)
// ApplyDAOHardFork modifies the state database according to the DAO hard-fork // ApplyDAOHardFork modifies the state database according to the DAO hard-fork
// rules, transferring all balances of a set of DAO accounts to a single refund // rules, transferring all balances of a set of DAO accounts to a single refund
// contract. // contract.
func ApplyDAOHardFork(statedb *state.StateDB) { func ApplyDAOHardFork(statedb vm.StateDB) {
// Retrieve the contract to refund balances into // Retrieve the contract to refund balances into
if !statedb.Exist(params.DAORefundContract) { if !statedb.Exist(params.DAORefundContract) {
statedb.CreateAccount(params.DAORefundContract) statedb.CreateAccount(params.DAORefundContract)
@ -82,7 +81,8 @@ func ApplyDAOHardFork(statedb *state.StateDB) {
// Move every DAO account and extra-balance account funds into the refund contract // Move every DAO account and extra-balance account funds into the refund contract
for _, addr := range params.DAODrainList() { for _, addr := range params.DAODrainList() {
statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr), tracing.BalanceIncreaseDaoContract) balance := statedb.GetBalance(addr)
statedb.SetBalance(addr, new(uint256.Int), tracing.BalanceDecreaseDaoAccount) statedb.AddBalance(params.DAORefundContract, balance, tracing.BalanceIncreaseDaoContract)
statedb.SubBalance(addr, balance, tracing.BalanceDecreaseDaoAccount)
} }
} }

View file

@ -24,7 +24,6 @@ import (
"github.com/holiman/uint256" "github.com/holiman/uint256"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/consensus/misc"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
@ -82,19 +81,23 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int {
num.Mul(num, parent.BaseFee) num.Mul(num, parent.BaseFee)
num.Div(num, denom.SetUint64(parentGasTarget)) num.Div(num, denom.SetUint64(parentGasTarget))
num.Div(num, denom.SetUint64(baseFeeChangeDenominatorUint64)) num.Div(num, denom.SetUint64(baseFeeChangeDenominatorUint64))
baseFeeDelta := math.BigMax(num, common.Big1) if num.Cmp(common.Big1) < 0 {
return num.Add(parent.BaseFee, common.Big1)
return num.Add(parent.BaseFee, baseFeeDelta) }
return num.Add(parent.BaseFee, num)
} else { } else {
// Otherwise if the parent block used less gas than its target, the baseFee should decrease. // Otherwise if the parent block used less gas than its target, the baseFee should decrease.
// max(0, parentBaseFee * gasUsedDelta / parentGasTarget / baseFeeChangeDenominator) // max(0, parentBaseFee * gasUsedDelta / parentGasTarget / baseFeeChangeDenominator)
num.SetUint64(parentGasTarget - parent.GasUsed) num.SetUint64(parentGasTarget - parent.GasUsed)
num.Mul(num, parent.BaseFee) num.Mul(num, parent.BaseFee)
num.Div(num, denom.SetUint64(parentGasTarget)) num.Div(num, denom.SetUint64(parentGasTarget))
num.Div(num, denom.SetUint64(baseFeeChangeDenominatorUint64)) num.Div(num, denom.SetUint64(config.BaseFeeChangeDenominator()))
baseFee := num.Sub(parent.BaseFee, num)
return math.BigMax(baseFee, common.Big0) baseFee := num.Sub(parent.BaseFee, num)
if baseFee.Cmp(common.Big0) < 0 {
baseFee = common.Big0
}
return baseFee
} }
} }

View file

@ -19,15 +19,12 @@ package console
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"io" "io"
"reflect" "reflect"
"strings" "strings"
"time" "time"
"github.com/dop251/goja" "github.com/dop251/goja"
"github.com/ethereum/go-ethereum/accounts/scwallet"
"github.com/ethereum/go-ethereum/accounts/usbwallet"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/console/prompt" "github.com/ethereum/go-ethereum/console/prompt"
"github.com/ethereum/go-ethereum/internal/jsre" "github.com/ethereum/go-ethereum/internal/jsre"
@ -51,302 +48,6 @@ func newBridge(client *rpc.Client, prompter prompt.UserPrompter, printer io.Writ
} }
} }
func getJeth(vm *goja.Runtime) *goja.Object {
jeth := vm.Get("jeth")
if jeth == nil {
panic(vm.ToValue("jeth object does not exist"))
}
return jeth.ToObject(vm)
}
// NewAccount is a wrapper around the personal.newAccount RPC method that uses a
// non-echoing password prompt to acquire the passphrase and executes the original
// RPC method (saved in jeth.newAccount) with it to actually execute the RPC call.
func (b *bridge) NewAccount(call jsre.Call) (goja.Value, error) {
var (
password string
confirm string
err error
)
switch {
// No password was specified, prompt the user for it
case len(call.Arguments) == 0:
if password, err = b.prompter.PromptPassword("Passphrase: "); err != nil {
return nil, err
}
if confirm, err = b.prompter.PromptPassword("Repeat passphrase: "); err != nil {
return nil, err
}
if password != confirm {
return nil, errors.New("passwords don't match")
}
// A single string password was specified, use that
case len(call.Arguments) == 1 && call.Argument(0).ToString() != nil:
password = call.Argument(0).ToString().String()
default:
return nil, errors.New("expected 0 or 1 string argument")
}
// Password acquired, execute the call and return
newAccount, callable := goja.AssertFunction(getJeth(call.VM).Get("newAccount"))
if !callable {
return nil, errors.New("jeth.newAccount is not callable")
}
ret, err := newAccount(goja.Null(), call.VM.ToValue(password))
if err != nil {
return nil, err
}
return ret, nil
}
// OpenWallet is a wrapper around personal.openWallet which can interpret and
// react to certain error messages, such as the Trezor PIN matrix request.
func (b *bridge) OpenWallet(call jsre.Call) (goja.Value, error) {
// Make sure we have a wallet specified to open
if call.Argument(0).ToObject(call.VM).ClassName() != "String" {
return nil, errors.New("first argument must be the wallet URL to open")
}
wallet := call.Argument(0)
var passwd goja.Value
if goja.IsUndefined(call.Argument(1)) || goja.IsNull(call.Argument(1)) {
passwd = call.VM.ToValue("")
} else {
passwd = call.Argument(1)
}
// Open the wallet and return if successful in itself
openWallet, callable := goja.AssertFunction(getJeth(call.VM).Get("openWallet"))
if !callable {
return nil, errors.New("jeth.openWallet is not callable")
}
val, err := openWallet(goja.Null(), wallet, passwd)
if err == nil {
return val, nil
}
// Wallet open failed, report error unless it's a PIN or PUK entry
switch {
case strings.HasSuffix(err.Error(), usbwallet.ErrTrezorPINNeeded.Error()):
val, err = b.readPinAndReopenWallet(call)
if err == nil {
return val, nil
}
val, err = b.readPassphraseAndReopenWallet(call)
if err != nil {
return nil, err
}
case strings.HasSuffix(err.Error(), scwallet.ErrPairingPasswordNeeded.Error()):
// PUK input requested, fetch from the user and call open again
input, err := b.prompter.PromptPassword("Please enter the pairing password: ")
if err != nil {
return nil, err
}
passwd = call.VM.ToValue(input)
if val, err = openWallet(goja.Null(), wallet, passwd); err != nil {
if !strings.HasSuffix(err.Error(), scwallet.ErrPINNeeded.Error()) {
return nil, err
}
// PIN input requested, fetch from the user and call open again
input, err := b.prompter.PromptPassword("Please enter current PIN: ")
if err != nil {
return nil, err
}
if val, err = openWallet(goja.Null(), wallet, call.VM.ToValue(input)); err != nil {
return nil, err
}
}
case strings.HasSuffix(err.Error(), scwallet.ErrPINUnblockNeeded.Error()):
// PIN unblock requested, fetch PUK and new PIN from the user
var pukpin string
input, err := b.prompter.PromptPassword("Please enter current PUK: ")
if err != nil {
return nil, err
}
pukpin = input
input, err = b.prompter.PromptPassword("Please enter new PIN: ")
if err != nil {
return nil, err
}
pukpin += input
if val, err = openWallet(goja.Null(), wallet, call.VM.ToValue(pukpin)); err != nil {
return nil, err
}
case strings.HasSuffix(err.Error(), scwallet.ErrPINNeeded.Error()):
// PIN input requested, fetch from the user and call open again
input, err := b.prompter.PromptPassword("Please enter current PIN: ")
if err != nil {
return nil, err
}
if val, err = openWallet(goja.Null(), wallet, call.VM.ToValue(input)); err != nil {
return nil, err
}
default:
// Unknown error occurred, drop to the user
return nil, err
}
return val, nil
}
func (b *bridge) readPassphraseAndReopenWallet(call jsre.Call) (goja.Value, error) {
wallet := call.Argument(0)
input, err := b.prompter.PromptPassword("Please enter your passphrase: ")
if err != nil {
return nil, err
}
openWallet, callable := goja.AssertFunction(getJeth(call.VM).Get("openWallet"))
if !callable {
return nil, errors.New("jeth.openWallet is not callable")
}
return openWallet(goja.Null(), wallet, call.VM.ToValue(input))
}
func (b *bridge) readPinAndReopenWallet(call jsre.Call) (goja.Value, error) {
wallet := call.Argument(0)
// Trezor PIN matrix input requested, display the matrix to the user and fetch the data
fmt.Fprintf(b.printer, "Look at the device for number positions\n\n")
fmt.Fprintf(b.printer, "7 | 8 | 9\n")
fmt.Fprintf(b.printer, "--+---+--\n")
fmt.Fprintf(b.printer, "4 | 5 | 6\n")
fmt.Fprintf(b.printer, "--+---+--\n")
fmt.Fprintf(b.printer, "1 | 2 | 3\n\n")
input, err := b.prompter.PromptPassword("Please enter current PIN: ")
if err != nil {
return nil, err
}
openWallet, callable := goja.AssertFunction(getJeth(call.VM).Get("openWallet"))
if !callable {
return nil, errors.New("jeth.openWallet is not callable")
}
return openWallet(goja.Null(), wallet, call.VM.ToValue(input))
}
// UnlockAccount is a wrapper around the personal.unlockAccount RPC method that
// uses a non-echoing password prompt to acquire the passphrase and executes the
// original RPC method (saved in jeth.unlockAccount) with it to actually execute
// the RPC call.
func (b *bridge) UnlockAccount(call jsre.Call) (goja.Value, error) {
if len(call.Arguments) < 1 {
return nil, errors.New("usage: unlockAccount(account, [ password, duration ])")
}
account := call.Argument(0)
// Make sure we have an account specified to unlock.
if goja.IsUndefined(account) || goja.IsNull(account) || account.ExportType().Kind() != reflect.String {
return nil, errors.New("first argument must be the account to unlock")
}
// If password is not given or is the null value, prompt the user for it.
var passwd goja.Value
if goja.IsUndefined(call.Argument(1)) || goja.IsNull(call.Argument(1)) {
fmt.Fprintf(b.printer, "Unlock account %s\n", account)
input, err := b.prompter.PromptPassword("Passphrase: ")
if err != nil {
return nil, err
}
passwd = call.VM.ToValue(input)
} else {
if call.Argument(1).ExportType().Kind() != reflect.String {
return nil, errors.New("password must be a string")
}
passwd = call.Argument(1)
}
// Third argument is the duration how long the account should be unlocked.
duration := goja.Null()
if !goja.IsUndefined(call.Argument(2)) && !goja.IsNull(call.Argument(2)) {
if !isNumber(call.Argument(2)) {
return nil, errors.New("unlock duration must be a number")
}
duration = call.Argument(2)
}
// Send the request to the backend and return.
unlockAccount, callable := goja.AssertFunction(getJeth(call.VM).Get("unlockAccount"))
if !callable {
return nil, errors.New("jeth.unlockAccount is not callable")
}
return unlockAccount(goja.Null(), account, passwd, duration)
}
// Sign is a wrapper around the personal.sign RPC method that uses a non-echoing password
// prompt to acquire the passphrase and executes the original RPC method (saved in
// jeth.sign) with it to actually execute the RPC call.
func (b *bridge) Sign(call jsre.Call) (goja.Value, error) {
if nArgs := len(call.Arguments); nArgs < 2 {
return nil, errors.New("usage: sign(message, account, [ password ])")
}
var (
message = call.Argument(0)
account = call.Argument(1)
passwd = call.Argument(2)
)
if goja.IsUndefined(message) || message.ExportType().Kind() != reflect.String {
return nil, errors.New("first argument must be the message to sign")
}
if goja.IsUndefined(account) || account.ExportType().Kind() != reflect.String {
return nil, errors.New("second argument must be the account to sign with")
}
// if the password is not given or null ask the user and ensure password is a string
if goja.IsUndefined(passwd) || goja.IsNull(passwd) {
fmt.Fprintf(b.printer, "Give password for account %s\n", account)
input, err := b.prompter.PromptPassword("Password: ")
if err != nil {
return nil, err
}
passwd = call.VM.ToValue(input)
} else if passwd.ExportType().Kind() != reflect.String {
return nil, errors.New("third argument must be the password to unlock the account")
}
// Send the request to the backend and return
sign, callable := goja.AssertFunction(getJeth(call.VM).Get("sign"))
if !callable {
return nil, errors.New("jeth.sign is not callable")
}
return sign(goja.Null(), message, account, passwd)
}
// Sleep will block the console for the specified number of seconds. // Sleep will block the console for the specified number of seconds.
func (b *bridge) Sleep(call jsre.Call) (goja.Value, error) { func (b *bridge) Sleep(call jsre.Call) (goja.Value, error) {
if nArgs := len(call.Arguments); nArgs < 1 { if nArgs := len(call.Arguments); nArgs < 1 {

View file

@ -147,7 +147,6 @@ func (c *Console) init(preload []string) error {
// Add bridge overrides for web3.js functionality. // Add bridge overrides for web3.js functionality.
c.jsre.Do(func(vm *goja.Runtime) { c.jsre.Do(func(vm *goja.Runtime) {
c.initAdmin(vm, bridge) c.initAdmin(vm, bridge)
c.initPersonal(vm, bridge)
}) })
// Preload JavaScript files. // Preload JavaScript files.
@ -268,32 +267,6 @@ func (c *Console) initAdmin(vm *goja.Runtime, bridge *bridge) {
} }
} }
// initPersonal redirects account-related API methods through the bridge.
//
// If the console is in interactive mode and the 'personal' API is available, override
// the openWallet, unlockAccount, newAccount and sign methods since these require user
// interaction. The original web3 callbacks are stored in 'jeth'. These will be called
// by the bridge after the prompt and send the original web3 request to the backend.
func (c *Console) initPersonal(vm *goja.Runtime, bridge *bridge) {
personal := getObject(vm, "personal")
if personal == nil || c.prompter == nil {
return
}
log.Warn("Enabling deprecated personal namespace")
jeth := vm.NewObject()
vm.Set("jeth", jeth)
jeth.Set("openWallet", personal.Get("openWallet"))
jeth.Set("unlockAccount", personal.Get("unlockAccount"))
jeth.Set("newAccount", personal.Get("newAccount"))
jeth.Set("sign", personal.Get("sign"))
personal.Set("openWallet", jsre.MakeCallback(vm, bridge.OpenWallet))
personal.Set("unlockAccount", jsre.MakeCallback(vm, bridge.UnlockAccount))
personal.Set("newAccount", jsre.MakeCallback(vm, bridge.NewAccount))
personal.Set("sign", jsre.MakeCallback(vm, bridge.Sign))
}
func (c *Console) clearHistory() { func (c *Console) clearHistory() {
c.history = nil c.history = nil
c.prompter.ClearHistory() c.prompter.ClearHistory()

View file

@ -26,12 +26,13 @@ import (
// Iterator for disassembled EVM instructions // Iterator for disassembled EVM instructions
type instructionIterator struct { type instructionIterator struct {
code []byte code []byte
pc uint64 pc uint64
arg []byte arg []byte
op vm.OpCode op vm.OpCode
error error error error
started bool started bool
eofEnabled bool
} }
// NewInstructionIterator creates a new instruction iterator. // NewInstructionIterator creates a new instruction iterator.
@ -42,6 +43,13 @@ func NewInstructionIterator(code []byte) *instructionIterator {
return it return it
} }
// NewEOFInstructionIterator creates a new instruction iterator for EOF-code.
func NewEOFInstructionIterator(code []byte) *instructionIterator {
it := NewInstructionIterator(code)
it.eofEnabled = true
return it
}
// Next returns true if there is a next instruction and moves on. // Next returns true if there is a next instruction and moves on.
func (it *instructionIterator) Next() bool { func (it *instructionIterator) Next() bool {
if it.error != nil || uint64(len(it.code)) <= it.pc { if it.error != nil || uint64(len(it.code)) <= it.pc {
@ -65,13 +73,26 @@ func (it *instructionIterator) Next() bool {
// We reached the end. // We reached the end.
return false return false
} }
it.op = vm.OpCode(it.code[it.pc]) it.op = vm.OpCode(it.code[it.pc])
if it.op.IsPush() { var a int
a := uint64(it.op) - uint64(vm.PUSH0) if !it.eofEnabled { // Legacy code
u := it.pc + 1 + a if it.op.IsPush() {
a = int(it.op) - int(vm.PUSH0)
}
} else { // EOF code
if it.op == vm.RJUMPV {
// RJUMPV is unique as it has a variable sized operand. The total size is
// determined by the count byte which immediately follows RJUMPV.
maxIndex := int(it.code[it.pc+1])
a = (maxIndex+1)*2 + 1
} else {
a = vm.Immediates(it.op)
}
}
if a > 0 {
u := it.pc + 1 + uint64(a)
if uint64(len(it.code)) <= it.pc || uint64(len(it.code)) < u { if uint64(len(it.code)) <= it.pc || uint64(len(it.code)) < u {
it.error = fmt.Errorf("incomplete push instruction at %v", it.pc) it.error = fmt.Errorf("incomplete instruction at %v", it.pc)
return false return false
} }
@ -109,7 +130,6 @@ func PrintDisassembled(code string) error {
if err != nil { if err != nil {
return err return err
} }
it := NewInstructionIterator(script) it := NewInstructionIterator(script)
for it.Next() { for it.Next() {
if it.Arg() != nil && 0 < len(it.Arg()) { if it.Arg() != nil && 0 < len(it.Arg()) {

View file

@ -17,42 +17,78 @@
package asm package asm
import ( import (
"testing"
"encoding/hex" "encoding/hex"
"fmt"
"strings"
"testing"
) )
// Tests disassembling instructions // Tests disassembling instructions
func TestInstructionIterator(t *testing.T) { func TestInstructionIterator(t *testing.T) {
for i, tc := range []struct { for i, tc := range []struct {
want int code string
code string legacyWant string
wantErr string eofWant string
}{ }{
{2, "61000000", ""}, // valid code {"", "", ""}, // empty
{0, "6100", "incomplete push instruction at 0"}, // invalid code {"6100", `err: incomplete instruction at 0`, `err: incomplete instruction at 0`},
{2, "5900", ""}, // push0 {"61000000", `
{0, "", ""}, // empty 00000: PUSH2 0x0000
00003: STOP`, `
00000: PUSH2 0x0000
00003: STOP`},
{"5F00", `
00000: PUSH0
00001: STOP`, `
00000: PUSH0
00001: STOP`},
{"d1aabb00", `00000: DATALOADN
00001: opcode 0xaa not defined
00002: opcode 0xbb not defined
00003: STOP`, `
00000: DATALOADN 0xaabb
00003: STOP`}, // DATALOADN(aabb),STOP
{"d1aa", `
00000: DATALOADN
00001: opcode 0xaa not defined`, "err: incomplete instruction at 0\n"}, // DATALOADN(aa) invalid
{"e20211223344556600", `
00000: RJUMPV
00001: MUL
00002: GT
00003: opcode 0x22 not defined
00004: CALLER
00005: DIFFICULTY
00006: SSTORE
err: incomplete instruction at 7`, `
00000: RJUMPV 0x02112233445566
00008: STOP`}, // RJUMPV( 6 bytes), STOP
} { } {
var ( var (
have int
code, _ = hex.DecodeString(tc.code) code, _ = hex.DecodeString(tc.code)
it = NewInstructionIterator(code) legacy = strings.TrimSpace(disassembly(NewInstructionIterator(code)))
eof = strings.TrimSpace(disassembly(NewEOFInstructionIterator(code)))
) )
for it.Next() { if want := strings.TrimSpace(tc.legacyWant); legacy != want {
have++ t.Errorf("test %d: wrong (legacy) output. have:\n%q\nwant:\n%q\n", i, legacy, want)
} }
var haveErr = "" if want := strings.TrimSpace(tc.eofWant); eof != want {
if it.Error() != nil { t.Errorf("test %d: wrong (eof) output. have:\n%q\nwant:\n%q\n", i, eof, want)
haveErr = it.Error().Error()
}
if haveErr != tc.wantErr {
t.Errorf("test %d: encountered error: %q want %q", i, haveErr, tc.wantErr)
continue
}
if have != tc.want {
t.Errorf("wrong instruction count, have %d want %d", have, tc.want)
} }
} }
} }
func disassembly(it *instructionIterator) string {
var out = new(strings.Builder)
for it.Next() {
if it.Arg() != nil && 0 < len(it.Arg()) {
fmt.Fprintf(out, "%05x: %v %#x\n", it.PC(), it.Op(), it.Arg())
} else {
fmt.Fprintf(out, "%05x: %v\n", it.PC(), it.Op())
}
}
if err := it.Error(); err != nil {
fmt.Fprintf(out, "err: %v\n", err)
}
return out.String()
}

View file

@ -29,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethdb/pebble"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
@ -80,9 +81,15 @@ var (
// value-transfer transaction with n bytes of extra data in each // value-transfer transaction with n bytes of extra data in each
// block. // block.
func genValueTx(nbytes int) func(int, *BlockGen) { func genValueTx(nbytes int) func(int, *BlockGen) {
// We can reuse the data for all transactions.
// During signing, the method tx.WithSignature(s, sig)
// performs:
// cpy := tx.inner.copy()
// cpy.setSignatureValues(signer.ChainID(), v, r, s)
// After this operation, the data can be reused by the caller.
data := make([]byte, nbytes)
return func(i int, gen *BlockGen) { return func(i int, gen *BlockGen) {
toaddr := common.Address{} toaddr := common.Address{}
data := make([]byte, nbytes)
gas, _ := IntrinsicGas(data, nil, false, false, false, false) gas, _ := IntrinsicGas(data, nil, false, false, false, false)
signer := gen.Signer() signer := gen.Signer()
gasPrice := big.NewInt(0) gasPrice := big.NewInt(0)
@ -182,22 +189,16 @@ func genUncles(i int, gen *BlockGen) {
func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) { func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
// Create the database in memory or in a temporary directory. // Create the database in memory or in a temporary directory.
var db ethdb.Database var db ethdb.Database
var err error
if !disk { if !disk {
db = rawdb.NewMemoryDatabase() db = rawdb.NewMemoryDatabase()
} else { } else {
dir := b.TempDir() pdb, err := pebble.New(b.TempDir(), 128, 128, "", false)
db, err = rawdb.NewLevelDBDatabase(dir, 128, 128, "", false)
if err != nil { if err != nil {
b.Fatalf("cannot create temporary database: %v", err) b.Fatalf("cannot create temporary database: %v", err)
} }
db = rawdb.NewDatabase(pdb)
defer db.Close() defer db.Close()
} }
// Generate a chain of b.N blocks using the supplied block // Generate a chain of b.N blocks using the supplied block
// generator function. // generator function.
gspec := &Genesis{ gspec := &Genesis{
@ -225,15 +226,27 @@ func BenchmarkChainRead_full_10k(b *testing.B) {
benchReadChain(b, true, 10000) benchReadChain(b, true, 10000)
} }
func BenchmarkChainRead_header_100k(b *testing.B) { func BenchmarkChainRead_header_100k(b *testing.B) {
if testing.Short() {
b.Skip("Skipping in short-mode")
}
benchReadChain(b, false, 100000) benchReadChain(b, false, 100000)
} }
func BenchmarkChainRead_full_100k(b *testing.B) { func BenchmarkChainRead_full_100k(b *testing.B) {
if testing.Short() {
b.Skip("Skipping in short-mode")
}
benchReadChain(b, true, 100000) benchReadChain(b, true, 100000)
} }
func BenchmarkChainRead_header_500k(b *testing.B) { func BenchmarkChainRead_header_500k(b *testing.B) {
if testing.Short() {
b.Skip("Skipping in short-mode")
}
benchReadChain(b, false, 500000) benchReadChain(b, false, 500000)
} }
func BenchmarkChainRead_full_500k(b *testing.B) { func BenchmarkChainRead_full_500k(b *testing.B) {
if testing.Short() {
b.Skip("Skipping in short-mode")
}
benchReadChain(b, true, 500000) benchReadChain(b, true, 500000)
} }
func BenchmarkChainWrite_header_10k(b *testing.B) { func BenchmarkChainWrite_header_10k(b *testing.B) {
@ -249,9 +262,15 @@ func BenchmarkChainWrite_full_100k(b *testing.B) {
benchWriteChain(b, true, 100000) benchWriteChain(b, true, 100000)
} }
func BenchmarkChainWrite_header_500k(b *testing.B) { func BenchmarkChainWrite_header_500k(b *testing.B) {
if testing.Short() {
b.Skip("Skipping in short-mode")
}
benchWriteChain(b, false, 500000) benchWriteChain(b, false, 500000)
} }
func BenchmarkChainWrite_full_500k(b *testing.B) { func BenchmarkChainWrite_full_500k(b *testing.B) {
if testing.Short() {
b.Skip("Skipping in short-mode")
}
benchWriteChain(b, true, 500000) benchWriteChain(b, true, 500000)
} }
@ -296,13 +315,11 @@ func makeChainForBench(db ethdb.Database, genesis *Genesis, full bool, count uin
func benchWriteChain(b *testing.B, full bool, count uint64) { func benchWriteChain(b *testing.B, full bool, count uint64) {
genesis := &Genesis{Config: params.AllEthashProtocolChanges} genesis := &Genesis{Config: params.AllEthashProtocolChanges}
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
dir := b.TempDir() pdb, err := pebble.New(b.TempDir(), 1024, 128, "", false)
db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "", false)
if err != nil { if err != nil {
b.Fatalf("error opening database at %v: %v", dir, err) b.Fatalf("error opening database: %v", err)
} }
db := rawdb.NewDatabase(pdb)
makeChainForBench(db, genesis, full, count) makeChainForBench(db, genesis, full, count)
db.Close() db.Close()
} }
@ -311,10 +328,11 @@ func benchWriteChain(b *testing.B, full bool, count uint64) {
func benchReadChain(b *testing.B, full bool, count uint64) { func benchReadChain(b *testing.B, full bool, count uint64) {
dir := b.TempDir() dir := b.TempDir()
db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "", false) pdb, err := pebble.New(dir, 1024, 128, "", false)
if err != nil { if err != nil {
b.Fatalf("error opening database at %v: %v", dir, err) b.Fatalf("error opening database: %v", err)
} }
db := rawdb.NewDatabase(pdb)
genesis := &Genesis{Config: params.AllEthashProtocolChanges} genesis := &Genesis{Config: params.AllEthashProtocolChanges}
makeChainForBench(db, genesis, full, count) makeChainForBench(db, genesis, full, count)
@ -327,15 +345,16 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "", false) pdb, err = pebble.New(dir, 1024, 128, "", false)
if err != nil { if err != nil {
b.Fatalf("error opening database at %v: %v", dir, err) b.Fatalf("error opening database: %v", err)
} }
chain, err := NewBlockChain(db, &cacheConfig, genesis, nil, ethash.NewFaker(), vm.Config{}, nil, nil, nil) db = rawdb.NewDatabase(pdb)
chain, err := NewBlockChain(db, &cacheConfig, genesis, nil, ethash.NewFaker(), vm.Config{}, nil)
if err != nil { if err != nil {
b.Fatalf("error creating chain: %v", err) b.Fatalf("error creating chain: %v", err)
} }
for n := uint64(0); n < count; n++ { for n := uint64(0); n < count; n++ {
header := chain.GetHeaderByNumber(n) header := chain.GetHeaderByNumber(n)
if full { if full {

View file

@ -127,7 +127,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
// such as amount of used gas, the receipt roots and the state root itself. // such as amount of used gas, the receipt roots and the state root itself.
func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, res *ProcessResult, stateless bool) error { func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, res *ProcessResult, stateless bool) error {
if res == nil { if res == nil {
return fmt.Errorf("nil ProcessResult value") return errors.New("nil ProcessResult value")
} }
header := block.Header() header := block.Header()
if block.GasUsed() != res.GasUsed { if block.GasUsed() != res.GasUsed {
@ -151,10 +151,12 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
} }
// Validate the parsed requests match the expected header value. // Validate the parsed requests match the expected header value.
if header.RequestsHash != nil { if header.RequestsHash != nil {
depositSha := types.DeriveSha(res.Requests, trie.NewStackTrie(nil)) reqhash := types.CalcRequestsHash(res.Requests)
if depositSha != *header.RequestsHash { if reqhash != *header.RequestsHash {
return fmt.Errorf("invalid deposit root hash (remote: %x local: %x)", *header.RequestsHash, depositSha) return fmt.Errorf("invalid requests hash (remote: %x local: %x)", *header.RequestsHash, reqhash)
} }
} else if res.Requests != nil {
return errors.New("block has requests before prague fork")
} }
// Validate the state root against the received state root and throw // Validate the state root against the received state root and throw
// an error if they don't match. // an error if they don't match.

View file

@ -117,6 +117,9 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) {
} }
copy(gspec.ExtraData[32:], addr[:]) copy(gspec.ExtraData[32:], addr[:])
// chain_maker has no blockchain to retrieve the TTD from, setting to nil
// is a hack to signal it to generate pre-merge blocks
gspec.Config.TerminalTotalDifficulty = nil
td := 0 td := 0
genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 8, nil) genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 8, nil)
@ -154,7 +157,6 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) {
preBlocks = blocks preBlocks = blocks
gspec.Config.TerminalTotalDifficulty = big.NewInt(int64(td)) gspec.Config.TerminalTotalDifficulty = big.NewInt(int64(td))
t.Logf("Set ttd to %v\n", gspec.Config.TerminalTotalDifficulty)
postBlocks, _ = GenerateChain(gspec.Config, preBlocks[len(preBlocks)-1], engine, genDb, 8, func(i int, gen *BlockGen) { postBlocks, _ = GenerateChain(gspec.Config, preBlocks[len(preBlocks)-1], engine, genDb, 8, func(i int, gen *BlockGen) {
gen.SetPoS() gen.SetPoS()
}) })

View file

@ -18,15 +18,13 @@
package core package core
import ( import (
"compress/gzip"
"context" "context"
"errors" "errors"
"fmt" "fmt"
"io" "io"
"math/big" "math/big"
"os"
"path/filepath"
"runtime" "runtime"
"slices"
"sort" "sort"
"strings" "strings"
"sync" "sync"
@ -180,9 +178,9 @@ func (c *CacheConfig) triedbConfig(isVerkle bool) *triedb.Config {
} }
if c.StateScheme == rawdb.PathScheme { if c.StateScheme == rawdb.PathScheme {
config.PathDB = &pathdb.Config{ config.PathDB = &pathdb.Config{
StateHistory: c.StateHistory, StateHistory: c.StateHistory,
CleanCacheSize: c.TrieCleanLimit * 1024 * 1024, CleanCacheSize: c.TrieCleanLimit * 1024 * 1024,
DirtyCacheSize: c.TrieDirtyLimit * 1024 * 1024, WriteBufferSize: c.TrieDirtyLimit * 1024 * 1024,
} }
} }
return config return config
@ -248,7 +246,6 @@ type BlockChain struct {
hc *HeaderChain hc *HeaderChain
rmLogsFeed event.Feed rmLogsFeed event.Feed
chainFeed event.Feed chainFeed event.Feed
chainSideFeed event.Feed
chainHeadFeed event.Feed chainHeadFeed event.Feed
logsFeed event.Feed logsFeed event.Feed
blockProcFeed event.Feed blockProcFeed event.Feed
@ -807,18 +804,14 @@ func (bc *BlockChain) SetHead(head uint64) error {
} }
// Send chain head event to update the transaction pool // Send chain head event to update the transaction pool
header := bc.CurrentBlock() header := bc.CurrentBlock()
block := bc.GetBlock(header.Hash(), header.Number.Uint64()) if block := bc.GetBlock(header.Hash(), header.Number.Uint64()); block == nil {
if block == nil {
// This should never happen. In practice, previously currentBlock // This should never happen. In practice, previously currentBlock
// contained the entire block whereas now only a "marker", so there // contained the entire block whereas now only a "marker", so there
// is an ever so slight chance for a race we should handle. // is an ever so slight chance for a race we should handle.
log.Error("Current block not found in database", "block", header.Number, "hash", header.Hash()) log.Error("Current block not found in database", "block", header.Number, "hash", header.Hash())
return fmt.Errorf("current block missing: #%d [%x..]", header.Number, header.Hash().Bytes()[:4]) return fmt.Errorf("current block missing: #%d [%x..]", header.Number, header.Hash().Bytes()[:4])
} }
bc.chainHeadFeed.Send(ChainHeadEvent{Header: header})
bc.chainHeadFeed.Send(ChainHeadEvent{Block: block})
return nil return nil
} }
@ -832,18 +825,14 @@ func (bc *BlockChain) SetHeadWithTimestamp(timestamp uint64) error {
} }
// Send chain head event to update the transaction pool // Send chain head event to update the transaction pool
header := bc.CurrentBlock() header := bc.CurrentBlock()
block := bc.GetBlock(header.Hash(), header.Number.Uint64()) if block := bc.GetBlock(header.Hash(), header.Number.Uint64()); block == nil {
if block == nil {
// This should never happen. In practice, previously currentBlock // This should never happen. In practice, previously currentBlock
// contained the entire block whereas now only a "marker", so there // contained the entire block whereas now only a "marker", so there
// is an ever so slight chance for a race we should handle. // is an ever so slight chance for a race we should handle.
log.Error("Current block not found in database", "block", header.Number, "hash", header.Hash()) log.Error("Current block not found in database", "block", header.Number, "hash", header.Hash())
return fmt.Errorf("current block missing: #%d [%x..]", header.Number, header.Hash().Bytes()[:4]) return fmt.Errorf("current block missing: #%d [%x..]", header.Number, header.Hash().Bytes()[:4])
} }
bc.chainHeadFeed.Send(ChainHeadEvent{Header: header})
bc.chainHeadFeed.Send(ChainHeadEvent{Block: block})
return nil return nil
} }
@ -1799,7 +1788,7 @@ func (bc *BlockChain) writeBlockWithoutState(block *types.Block, td *big.Int) (e
func (bc *BlockChain) writeKnownBlock(block *types.Block) error { func (bc *BlockChain) writeKnownBlock(block *types.Block) error {
current := bc.CurrentBlock() current := bc.CurrentBlock()
if block.ParentHash() != current.Hash() { if block.ParentHash() != current.Hash() {
if err := bc.reorg(current, block); err != nil { if err := bc.reorg(current, block.Header()); err != nil {
return err return err
} }
} }
@ -1965,7 +1954,7 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types
if reorg { if reorg {
// Reorganise the chain if the parent is not the head block // Reorganise the chain if the parent is not the head block
if block.ParentHash() != currentBlock.Hash() { if block.ParentHash() != currentBlock.Hash() {
if err = bc.reorg(currentBlock, block); err != nil { if err = bc.reorg(currentBlock, block.Header()); err != nil {
return NonStatTy, err return NonStatTy, err
} }
} }
@ -1978,26 +1967,23 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types
// Set new head. // Set new head.
if status == CanonStatTy { if status == CanonStatTy {
bc.writeHeadBlock(block) bc.writeHeadBlock(block)
}
if status == CanonStatTy { bc.chainFeed.Send(ChainEvent{Header: block.Header()})
bc.chainFeed.Send(ChainEvent{Block: block, Hash: block.Hash(), Logs: logs})
if len(logs) > 0 { if len(logs) > 0 {
bc.logsFeed.Send(logs) bc.logsFeed.Send(logs)
} }
// send state sync logs into logs feed // send state sync logs into logs feed
if len(stateSyncLogs) > 0 { if len(stateSyncLogs) > 0 {
bc.logsFeed.Send(stateSyncLogs) bc.logsFeed.Send(stateSyncLogs)
} }
// In theory, we should fire a ChainHeadEvent when we inject // In theory, we should fire a ChainHeadEvent when we inject
// a canonical block, but sometimes we can insert a batch of // a canonical block, but sometimes we can insert a batch of
// canonical blocks. Avoid firing too many ChainHeadEvents, // canonical blocks. Avoid firing too many ChainHeadEvents,
// we will fire an accumulated ChainHeadEvent and disable fire // we will fire an accumulated ChainHeadEvent and disable fire
// event here. // event here.
if emitHeadEvent { if emitHeadEvent {
bc.chainHeadFeed.Send(ChainHeadEvent{Block: block}) bc.chainHeadFeed.Send(ChainHeadEvent{Header: block.Header()})
// BOR state sync feed related changes // BOR state sync feed related changes
for _, data := range bc.stateSyncData { for _, data := range bc.stateSyncData {
bc.stateSyncFeed.Send(StateSyncEvent{Data: data}) bc.stateSyncFeed.Send(StateSyncEvent{Data: data})
@ -2102,7 +2088,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
// Fire a single chain head event if we've progressed the chain // Fire a single chain head event if we've progressed the chain
defer func() { defer func() {
if lastCanon != nil && bc.CurrentBlock().Hash() == lastCanon.Hash() { if lastCanon != nil && bc.CurrentBlock().Hash() == lastCanon.Hash() {
bc.chainHeadFeed.Send(ChainHeadEvent{lastCanon}) bc.chainHeadFeed.Send(ChainHeadEvent{Header: lastCanon.Header()})
} }
}() }()
// Start the parallel header verifier // Start the parallel header verifier
@ -2334,6 +2320,27 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
if parent == nil { if parent == nil {
parent = bc.GetHeader(block.ParentHash(), block.NumberU64()-1) parent = bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
} }
statedb, err := state.New(parent.Root, bc.statedb)
if err != nil {
return nil, it.index, err
}
// If we are past Byzantium, enable prefetching to pull in trie node paths
// while processing transactions. Before Byzantium the prefetcher is mostly
// useless due to the intermediate root hashing after each transaction.
if bc.chainConfig.IsByzantium(block.Number()) {
// Generate witnesses either if we're self-testing, or if it's the
// only block being inserted. A bit crude, but witnesses are huge,
// so we refuse to make an entire chain of them.
if bc.vmConfig.StatelessSelfValidation || (makeWitness && len(chain) == 1) {
witness, err = stateless.NewWitness(block.Header(), bc)
if err != nil {
return nil, it.index, err
}
}
statedb.StartPrefetcher("chain", witness)
}
activeState = statedb
// If we have a followup block, run that against the current state to pre-cache // If we have a followup block, run that against the current state to pre-cache
// transactions and probabilistically some of the account/storage trie nodes. // transactions and probabilistically some of the account/storage trie nodes.
@ -2846,8 +2853,8 @@ func (bc *BlockChain) recoverAncestors(block *types.Block, makeWitness bool) (co
return block.Hash(), nil return block.Hash(), nil
} }
// collectLogs collects the logs that were generated or removed during // collectLogs collects the logs that were generated or removed during the
// the processing of a block. These logs are later announced as deleted or reborn. // processing of a block. These logs are later announced as deleted or reborn.
func (bc *BlockChain) collectLogs(b *types.Block, removed bool) []*types.Log { func (bc *BlockChain) collectLogs(b *types.Block, removed bool) []*types.Log {
var blobGasPrice *big.Int var blobGasPrice *big.Int
excessBlobGas := b.ExcessBlobGas() excessBlobGas := b.ExcessBlobGas()
@ -2882,80 +2889,55 @@ func (bc *BlockChain) collectLogs(b *types.Block, removed bool) []*types.Log {
// reorg takes two blocks, an old chain and a new chain and will reconstruct the // reorg takes two blocks, an old chain and a new chain and will reconstruct the
// blocks and inserts them to be part of the new canonical chain and accumulates // blocks and inserts them to be part of the new canonical chain and accumulates
// potential missing transactions and post an event about them. // potential missing transactions and post an event about them.
//
// Note the new head block won't be processed here, callers need to handle it // Note the new head block won't be processed here, callers need to handle it
// externally. // externally.
// nolint:gocognit func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Header) error {
func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error {
var ( var (
newChain types.Blocks newChain []*types.Header
oldChain types.Blocks oldChain []*types.Header
commonBlock *types.Block commonBlock *types.Header
deletedTxs []common.Hash
addedTxs []common.Hash
) )
oldBlock := bc.GetBlock(oldHead.Hash(), oldHead.Number.Uint64())
if oldBlock == nil {
return errors.New("current head block missing")
}
newBlock := newHead
// Reduce the longer chain to the same number as the shorter one // Reduce the longer chain to the same number as the shorter one
if oldBlock.NumberU64() > newBlock.NumberU64() { if oldHead.Number.Uint64() > newHead.Number.Uint64() {
// Old chain is longer, gather all transactions and logs as deleted ones // Old chain is longer, gather all transactions and logs as deleted ones
for ; oldBlock != nil && oldBlock.NumberU64() != newBlock.NumberU64(); oldBlock = bc.GetBlock(oldBlock.ParentHash(), oldBlock.NumberU64()-1) { for ; oldHead != nil && oldHead.Number.Uint64() != newHead.Number.Uint64(); oldHead = bc.GetHeader(oldHead.ParentHash, oldHead.Number.Uint64()-1) {
oldChain = append(oldChain, oldBlock) oldChain = append(oldChain, oldHead)
for _, tx := range oldBlock.Transactions() {
deletedTxs = append(deletedTxs, tx.Hash())
}
} }
} else { } else {
// New chain is longer, stash all blocks away for subsequent insertion // New chain is longer, stash all blocks away for subsequent insertion
for ; newBlock != nil && newBlock.NumberU64() != oldBlock.NumberU64(); newBlock = bc.GetBlock(newBlock.ParentHash(), newBlock.NumberU64()-1) { for ; newHead != nil && newHead.Number.Uint64() != oldHead.Number.Uint64(); newHead = bc.GetHeader(newHead.ParentHash, newHead.Number.Uint64()-1) {
newChain = append(newChain, newBlock) newChain = append(newChain, newHead)
} }
} }
if oldHead == nil {
if oldBlock == nil {
return errInvalidOldChain return errInvalidOldChain
} }
if newHead == nil {
if newBlock == nil {
return errInvalidNewChain return errInvalidNewChain
} }
// Both sides of the reorg are at the same number, reduce both until the common // Both sides of the reorg are at the same number, reduce both until the common
// ancestor is found // ancestor is found
for { for {
// If the common ancestor was found, bail out // If the common ancestor was found, bail out
if oldBlock.Hash() == newBlock.Hash() { if oldHead.Hash() == newHead.Hash() {
commonBlock = oldBlock commonBlock = oldHead
break break
} }
// Remove an old block as well as stash away a new block // Remove an old block as well as stash away a new block
oldChain = append(oldChain, oldBlock) oldChain = append(oldChain, oldHead)
newChain = append(newChain, newHead)
for _, tx := range oldBlock.Transactions() {
deletedTxs = append(deletedTxs, tx.Hash())
}
newChain = append(newChain, newBlock)
// Step back with both chains // Step back with both chains
oldBlock = bc.GetBlock(oldBlock.ParentHash(), oldBlock.NumberU64()-1) oldHead = bc.GetHeader(oldHead.ParentHash, oldHead.Number.Uint64()-1)
if oldBlock == nil { if oldHead == nil {
return errInvalidOldChain return errInvalidOldChain
} }
newHead = bc.GetHeader(newHead.ParentHash, newHead.Number.Uint64()-1)
newBlock = bc.GetBlock(newBlock.ParentHash(), newBlock.NumberU64()-1) if newHead == nil {
if newBlock == nil {
return errInvalidNewChain return errInvalidNewChain
} }
} }
// Ensure the user sees large reorgs // Ensure the user sees large reorgs
if len(oldChain) > 0 && len(newChain) > 0 { if len(oldChain) > 0 && len(newChain) > 0 {
bc.chain2HeadFeed.Send(Chain2HeadEvent{ bc.chain2HeadFeed.Send(Chain2HeadEvent{
@ -2971,8 +2953,7 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error {
msg = "Large chain reorg detected" msg = "Large chain reorg detected"
logFn = log.Warn logFn = log.Warn
} }
logFn(msg, "number", commonBlock.Number, "hash", commonBlock.Hash(),
logFn(msg, "number", commonBlock.Number(), "hash", commonBlock.Hash(),
"drop", len(oldChain), "dropfrom", oldChain[0].Hash(), "add", len(newChain), "addfrom", newChain[0].Hash()) "drop", len(oldChain), "dropfrom", oldChain[0].Hash(), "add", len(newChain), "addfrom", newChain[0].Hash())
blockReorgAddMeter.Mark(int64(len(newChain))) blockReorgAddMeter.Mark(int64(len(newChain)))
blockReorgDropMeter.Mark(int64(len(oldChain))) blockReorgDropMeter.Mark(int64(len(oldChain)))
@ -2980,87 +2961,112 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error {
} else if len(newChain) > 0 { } else if len(newChain) > 0 {
// Special case happens in the post merge stage that current head is // Special case happens in the post merge stage that current head is
// the ancestor of new head while these two blocks are not consecutive // the ancestor of new head while these two blocks are not consecutive
log.Info("Extend chain", "add", len(newChain), "number", newChain[0].Number(), "hash", newChain[0].Hash()) log.Info("Extend chain", "add", len(newChain), "number", newChain[0].Number, "hash", newChain[0].Hash())
blockReorgAddMeter.Mark(int64(len(newChain))) blockReorgAddMeter.Mark(int64(len(newChain)))
} else { } else {
// len(newChain) == 0 && len(oldChain) > 0 // len(newChain) == 0 && len(oldChain) > 0
// rewind the canonical chain to a lower point. // rewind the canonical chain to a lower point.
home, err := os.UserHomeDir() log.Error("Impossible reorg, please file an issue", "oldnum", oldHead.Number, "oldhash", oldHead.Hash(), "oldblocks", len(oldChain), "newnum", newHead.Number, "newhash", newHead.Hash(), "newblocks", len(newChain))
if err != nil {
fmt.Println("Impossible reorg : Unable to get user home dir", "Error", err)
}
outPath := filepath.Join(home, "impossible-reorgs", fmt.Sprintf("%v-impossibleReorg", time.Now().Format(time.RFC3339)))
if _, err := os.Stat(outPath); errors.Is(err, os.ErrNotExist) {
err := os.MkdirAll(outPath, os.ModePerm)
if err != nil {
log.Error("Impossible reorg : Unable to create Dir", "Error", err)
}
} else {
err = ExportBlocks(oldChain, filepath.Join(outPath, "oldChain.gz"))
if err != nil {
log.Error("Impossible reorg : Unable to export oldChain", "Error", err)
}
err = ExportBlocks([]*types.Block{oldBlock}, filepath.Join(outPath, "oldBlock.gz"))
if err != nil {
log.Error("Impossible reorg : Unable to export oldBlock", "Error", err)
}
err = ExportBlocks([]*types.Block{newBlock}, filepath.Join(outPath, "newBlock.gz"))
if err != nil {
log.Error("Impossible reorg : Unable to export newBlock", "Error", err)
}
}
log.Error("Impossible reorg, please file an issue", "oldnum", oldBlock.Number(), "oldhash", oldBlock.Hash(), "oldblocks", len(oldChain), "newnum", newBlock.Number(), "newhash", newBlock.Hash(), "newblocks", len(newChain))
} }
// Acquire the tx-lookup lock before mutation. This step is essential // Acquire the tx-lookup lock before mutation. This step is essential
// as the txlookups should be changed atomically, and all subsequent // as the txlookups should be changed atomically, and all subsequent
// reads should be blocked until the mutation is complete. // reads should be blocked until the mutation is complete.
bc.txLookupLock.Lock() bc.txLookupLock.Lock()
// Insert the new chain segment in incremental order, from the old // Reorg can be executed, start reducing the chain's old blocks and appending
// to the new. The new chain head (newChain[0]) is not inserted here, // the new blocks
// as it will be handled separately outside of this function var (
for i := len(newChain) - 1; i >= 1; i-- { deletedTxs []common.Hash
// Insert the block in the canonical way, re-writing history rebirthTxs []common.Hash
bc.writeHeadBlock(newChain[i])
// Collect the new added transactions. deletedLogs []*types.Log
for _, tx := range newChain[i].Transactions() { rebirthLogs []*types.Log
addedTxs = append(addedTxs, tx.Hash()) )
// Deleted log emission on the API uses forward order, which is borked, but
// we'll leave it in for legacy reasons.
//
// TODO(karalabe): This should be nuked out, no idea how, deprecate some APIs?
{
for i := len(oldChain) - 1; i >= 0; i-- {
block := bc.GetBlock(oldChain[i].Hash(), oldChain[i].Number.Uint64())
if block == nil {
return errInvalidOldChain // Corrupt database, mostly here to avoid weird panics
}
if logs := bc.collectLogs(block, true); len(logs) > 0 {
deletedLogs = append(deletedLogs, logs...)
}
if len(deletedLogs) > 512 {
bc.rmLogsFeed.Send(RemovedLogsEvent{deletedLogs})
deletedLogs = nil
}
}
if len(deletedLogs) > 0 {
bc.rmLogsFeed.Send(RemovedLogsEvent{deletedLogs})
} }
} }
// Undo old blocks in reverse order
for i := 0; i < len(oldChain); i++ {
// Collect all the deleted transactions
block := bc.GetBlock(oldChain[i].Hash(), oldChain[i].Number.Uint64())
if block == nil {
return errInvalidOldChain // Corrupt database, mostly here to avoid weird panics
}
for _, tx := range block.Transactions() {
deletedTxs = append(deletedTxs, tx.Hash())
}
// Collect deleted logs and emit them for new integrations
if logs := bc.collectLogs(block, true); len(logs) > 0 {
// Emit revertals latest first, older then
slices.Reverse(logs)
// TODO(karalabe): Hook into the reverse emission part
}
}
// Apply new blocks in forward order
for i := len(newChain) - 1; i >= 1; i-- {
// Collect all the included transactions
block := bc.GetBlock(newChain[i].Hash(), newChain[i].Number.Uint64())
if block == nil {
return errInvalidNewChain // Corrupt database, mostly here to avoid weird panics
}
for _, tx := range block.Transactions() {
rebirthTxs = append(rebirthTxs, tx.Hash())
}
// Collect inserted logs and emit them
if logs := bc.collectLogs(block, false); len(logs) > 0 {
rebirthLogs = append(rebirthLogs, logs...)
}
if len(rebirthLogs) > 512 {
bc.logsFeed.Send(rebirthLogs)
rebirthLogs = nil
}
// Update the head block
bc.writeHeadBlock(block)
}
if len(rebirthLogs) > 0 {
bc.logsFeed.Send(rebirthLogs)
}
// Delete useless indexes right now which includes the non-canonical // Delete useless indexes right now which includes the non-canonical
// transaction indexes, canonical chain indexes which above the head. // transaction indexes, canonical chain indexes which above the head.
var ( batch := bc.db.NewBatch()
indexesBatch = bc.db.NewBatch() for _, tx := range types.HashDifference(deletedTxs, rebirthTxs) {
diffs = types.HashDifference(deletedTxs, addedTxs) rawdb.DeleteTxLookupEntry(batch, tx)
)
for _, tx := range diffs {
rawdb.DeleteTxLookupEntry(indexesBatch, tx)
} }
// Delete all hash markers that are not part of the new canonical chain. // Delete all hash markers that are not part of the new canonical chain.
// Because the reorg function does not handle new chain head, all hash // Because the reorg function does not handle new chain head, all hash
// markers greater than or equal to new chain head should be deleted. // markers greater than or equal to new chain head should be deleted.
number := commonBlock.NumberU64() number := commonBlock.Number
if len(newChain) > 1 { if len(newChain) > 1 {
number = newChain[1].NumberU64() number = newChain[1].Number
} }
for i := number.Uint64() + 1; ; i++ {
for i := number + 1; ; i++ {
hash := rawdb.ReadCanonicalHash(bc.db, i) hash := rawdb.ReadCanonicalHash(bc.db, i)
if hash == (common.Hash{}) { if hash == (common.Hash{}) {
break break
} }
rawdb.DeleteCanonicalHash(batch, i)
rawdb.DeleteCanonicalHash(indexesBatch, i)
} }
if err := batch.Write(); err != nil {
if err := indexesBatch.Write(); err != nil {
log.Crit("Failed to delete useless indexes", "err", err) log.Crit("Failed to delete useless indexes", "err", err)
} }
// Reset the tx lookup cache to clear stale txlookup cache. // Reset the tx lookup cache to clear stale txlookup cache.
@ -3069,88 +3075,6 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error {
// Release the tx-lookup lock after mutation. // Release the tx-lookup lock after mutation.
bc.txLookupLock.Unlock() bc.txLookupLock.Unlock()
// Send out events for logs from the old canon chain, and 'reborn'
// logs from the new canon chain. The number of logs can be very
// high, so the events are sent in batches of size around 512.
// Deleted logs + blocks:
var deletedLogs []*types.Log
for i := len(oldChain) - 1; i >= 0; i-- {
// Also send event for blocks removed from the canon chain.
bc.chainSideFeed.Send(ChainSideEvent{Block: oldChain[i]})
// Collect deleted logs for notification
if logs := bc.collectLogs(oldChain[i], true); len(logs) > 0 {
deletedLogs = append(deletedLogs, logs...)
}
if len(deletedLogs) > 512 {
bc.rmLogsFeed.Send(RemovedLogsEvent{deletedLogs})
deletedLogs = nil
}
}
if len(deletedLogs) > 0 {
bc.rmLogsFeed.Send(RemovedLogsEvent{deletedLogs})
}
// New logs:
var rebirthLogs []*types.Log
for i := len(newChain) - 1; i >= 1; i-- {
if logs := bc.collectLogs(newChain[i], false); len(logs) > 0 {
rebirthLogs = append(rebirthLogs, logs...)
}
if len(rebirthLogs) > 512 {
bc.logsFeed.Send(rebirthLogs)
rebirthLogs = nil
}
}
if len(rebirthLogs) > 0 {
bc.logsFeed.Send(rebirthLogs)
}
return nil
}
// ExportBlocks exports blocks into the specified file, truncating any data
// already present in the file.
func ExportBlocks(blocks []*types.Block, fn string) error {
log.Info("Exporting blockchain", "file", fn)
// Open the file handle and potentially wrap with a gzip stream
fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
if err != nil {
return err
}
defer fh.Close()
var writer io.Writer = fh
if strings.HasSuffix(fn, ".gz") {
writer = gzip.NewWriter(writer)
defer writer.(*gzip.Writer).Close()
}
// Iterate over the blocks and export them
if err := ExportN(writer, blocks); err != nil {
return err
}
log.Info("Exported blocks", "file", fn)
return nil
}
// ExportBlock writes a block to the given writer.
func ExportN(w io.Writer, blocks []*types.Block) error {
for _, block := range blocks {
if err := block.EncodeRLP(w); err != nil {
return err
}
}
return nil return nil
} }
@ -3190,7 +3114,7 @@ func (bc *BlockChain) SetCanonical(head *types.Block) (common.Hash, error) {
start := time.Now() start := time.Now()
if head.ParentHash() != bc.CurrentBlock().Hash() { if head.ParentHash() != bc.CurrentBlock().Hash() {
if err := bc.reorg(bc.CurrentBlock(), head); err != nil { if err := bc.reorg(bc.CurrentBlock(), head.Header()); err != nil {
return common.Hash{}, err return common.Hash{}, err
} }
} }
@ -3199,13 +3123,11 @@ func (bc *BlockChain) SetCanonical(head *types.Block) (common.Hash, error) {
// Emit events // Emit events
logs := bc.collectLogs(head, false) logs := bc.collectLogs(head, false)
bc.chainFeed.Send(ChainEvent{Block: head, Hash: head.Hash(), Logs: logs}) bc.chainFeed.Send(ChainEvent{Header: head.Header()})
if len(logs) > 0 { if len(logs) > 0 {
bc.logsFeed.Send(logs) bc.logsFeed.Send(logs)
} }
bc.chainHeadFeed.Send(ChainHeadEvent{Header: head.Header()})
bc.chainHeadFeed.Send(ChainHeadEvent{Block: head})
context := []interface{}{ context := []interface{}{
"number", head.Number(), "number", head.Number(),

View file

@ -484,11 +484,6 @@ func (bc *BlockChain) SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Su
return bc.scope.Track(bc.chainHeadFeed.Subscribe(ch)) return bc.scope.Track(bc.chainHeadFeed.Subscribe(ch))
} }
// SubscribeChainSideEvent registers a subscription of ChainSideEvent.
func (bc *BlockChain) SubscribeChainSideEvent(ch chan<- ChainSideEvent) event.Subscription {
return bc.scope.Track(bc.chainSideFeed.Subscribe(ch))
}
// SubscribeLogsEvent registers a subscription of []*types.Log. // SubscribeLogsEvent registers a subscription of []*types.Log.
func (bc *BlockChain) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { func (bc *BlockChain) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
return bc.scope.Track(bc.logsFeed.Subscribe(ch)) return bc.scope.Track(bc.logsFeed.Subscribe(ch))

View file

@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb/pebble"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
@ -1804,15 +1805,13 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s
datadir := t.TempDir() datadir := t.TempDir()
ancient := filepath.Join(datadir, "ancient") ancient := filepath.Join(datadir, "ancient")
db, err := rawdb.Open(rawdb.OpenOptions{ pdb, err := pebble.New(datadir, 0, 0, "", false)
Directory: datadir,
AncientsDirectory: ancient,
Ephemeral: true,
IsLastOffset: false,
DisableFreeze: false,
})
if err != nil { if err != nil {
t.Fatalf("Failed to create persistent database: %v", err) t.Fatalf("Failed to create persistent key-value database: %v", err)
}
db, err := rawdb.NewDatabaseWithFreezer(pdb, ancient, "", false)
if err != nil {
t.Fatalf("Failed to create persistent freezer database: %v", err)
} }
defer db.Close() // Might double close, should be fine defer db.Close() // Might double close, should be fine
@ -1891,15 +1890,13 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s
chain.stopWithoutSaving() chain.stopWithoutSaving()
// Start a new blockchain back up and see where the repair leads us // Start a new blockchain back up and see where the repair leads us
db, err = rawdb.Open(rawdb.OpenOptions{ pdb, err = pebble.New(datadir, 0, 0, "", false)
Directory: datadir,
AncientsDirectory: ancient,
Ephemeral: true,
IsLastOffset: false,
DisableFreeze: false,
})
if err != nil { if err != nil {
t.Fatalf("Failed to reopen persistent database: %v", err) t.Fatalf("Failed to reopen persistent key-value database: %v", err)
}
db, err = rawdb.NewDatabaseWithFreezer(pdb, ancient, "", false)
if err != nil {
t.Fatalf("Failed to reopen persistent freezer database: %v", err)
} }
defer db.Close() defer db.Close()
@ -1958,14 +1955,13 @@ func testIssue23496(t *testing.T, scheme string) {
datadir := t.TempDir() datadir := t.TempDir()
ancient := filepath.Join(datadir, "ancient") ancient := filepath.Join(datadir, "ancient")
db, err := rawdb.Open(rawdb.OpenOptions{ pdb, err := pebble.New(datadir, 0, 0, "", false)
Directory: datadir,
AncientsDirectory: ancient,
IsLastOffset: false,
DisableFreeze: false,
})
if err != nil { if err != nil {
t.Fatalf("Failed to create persistent database: %v", err) t.Fatalf("Failed to create persistent key-value database: %v", err)
}
db, err := rawdb.NewDatabaseWithFreezer(pdb, ancient, "", false)
if err != nil {
t.Fatalf("Failed to create persistent freezer database: %v", err)
} }
defer db.Close() // Might double close, should be fine defer db.Close() // Might double close, should be fine
@ -2017,15 +2013,13 @@ func testIssue23496(t *testing.T, scheme string) {
chain.stopWithoutSaving() chain.stopWithoutSaving()
// Start a new blockchain back up and see where the repair leads us // Start a new blockchain back up and see where the repair leads us
db, err = rawdb.Open(rawdb.OpenOptions{ pdb, err = pebble.New(datadir, 0, 0, "", false)
Directory: datadir,
AncientsDirectory: ancient,
Ephemeral: true,
IsLastOffset: false,
DisableFreeze: false,
})
if err != nil { if err != nil {
t.Fatalf("Failed to reopen persistent database: %v", err) t.Fatalf("Failed to reopen persistent key-value database: %v", err)
}
db, err = rawdb.NewDatabaseWithFreezer(pdb, ancient, "", false)
if err != nil {
t.Fatalf("Failed to reopen persistent freezer database: %v", err)
} }
defer db.Close() defer db.Close()

View file

@ -33,6 +33,7 @@ import (
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb/pebble"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/triedb" "github.com/ethereum/go-ethereum/triedb"
"github.com/ethereum/go-ethereum/triedb/hashdb" "github.com/ethereum/go-ethereum/triedb/hashdb"
@ -1968,15 +1969,13 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme
datadir := t.TempDir() datadir := t.TempDir()
ancient := filepath.Join(datadir, "ancient") ancient := filepath.Join(datadir, "ancient")
db, err := rawdb.Open(rawdb.OpenOptions{ pdb, err := pebble.New(datadir, 0, 0, "", false)
Directory: datadir,
AncientsDirectory: ancient,
Ephemeral: true,
IsLastOffset: false,
DisableFreeze: false,
})
if err != nil { if err != nil {
t.Fatalf("Failed to create persistent database: %v", err) t.Fatalf("Failed to create persistent key-value database: %v", err)
}
db, err := rawdb.NewDatabaseWithFreezer(pdb, ancient, "", false)
if err != nil {
t.Fatalf("Failed to create persistent freezer database: %v", err)
} }
defer db.Close() defer db.Close()

View file

@ -35,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethdb/pebble"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
@ -66,15 +67,13 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo
datadir := t.TempDir() datadir := t.TempDir()
ancient := filepath.Join(datadir, "ancient") ancient := filepath.Join(datadir, "ancient")
db, err := rawdb.Open(rawdb.OpenOptions{ pdb, err := pebble.New(datadir, 0, 0, "", false)
Directory: datadir,
AncientsDirectory: ancient,
Ephemeral: true,
IsLastOffset: false,
DisableFreeze: false,
})
if err != nil { if err != nil {
t.Fatalf("Failed to create persistent database: %v", err) t.Fatalf("Failed to create persistent key-value database: %v", err)
}
db, err := rawdb.NewDatabaseWithFreezer(pdb, ancient, "", false)
if err != nil {
t.Fatalf("Failed to create persistent freezer database: %v", err)
} }
// Initialize a fresh chain // Initialize a fresh chain
var ( var (
@ -260,15 +259,13 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) {
chain.triedb.Close() chain.triedb.Close()
// Start a new blockchain back up and see where the repair leads us // Start a new blockchain back up and see where the repair leads us
newdb, err := rawdb.Open(rawdb.OpenOptions{ pdb, err := pebble.New(snaptest.datadir, 0, 0, "", false)
Directory: snaptest.datadir,
AncientsDirectory: snaptest.ancient,
Ephemeral: true,
IsLastOffset: false,
DisableFreeze: false,
})
if err != nil { if err != nil {
t.Fatalf("Failed to reopen persistent database: %v", err) t.Fatalf("Failed to create persistent key-value database: %v", err)
}
newdb, err := rawdb.NewDatabaseWithFreezer(pdb, snaptest.ancient, "", false)
if err != nil {
t.Fatalf("Failed to create persistent freezer database: %v", err)
} }
defer newdb.Close() defer newdb.Close()

View file

@ -20,6 +20,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
gomath "math"
"math/big" "math/big"
"math/rand" "math/rand"
"os" "os"
@ -29,7 +30,6 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/beacon"
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
@ -40,6 +40,7 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/eth/tracers/logger"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethdb/pebble"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
"github.com/holiman/uint256" "github.com/holiman/uint256"
@ -1511,94 +1512,6 @@ func checkLogEvents(t *testing.T, logsCh <-chan []*types.Log, rmLogsCh <-chan Re
} }
} }
func TestReorgSideEvent(t *testing.T) {
testReorgSideEvent(t, rawdb.HashScheme)
testReorgSideEvent(t, rawdb.PathScheme)
}
func testReorgSideEvent(t *testing.T, scheme string) {
var (
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
gspec = &Genesis{
Config: params.TestChainConfig,
Alloc: types.GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}},
}
signer = types.LatestSigner(gspec.Config)
)
blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
defer blockchain.Stop()
_, chain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 3, func(i int, gen *BlockGen) {})
if _, err := blockchain.InsertChain(chain); err != nil {
t.Fatalf("failed to insert chain: %v", err)
}
_, replacementBlocks, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 4, func(i int, gen *BlockGen) {
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, gen.header.BaseFee, nil), signer, key1)
if i == 2 {
gen.OffsetTime(-9)
}
if err != nil {
t.Fatalf("failed to create tx: %v", err)
}
gen.AddTx(tx)
})
chainSideCh := make(chan ChainSideEvent, 64)
blockchain.SubscribeChainSideEvent(chainSideCh)
if _, err := blockchain.InsertChain(replacementBlocks); err != nil {
t.Fatalf("failed to insert chain: %v", err)
}
// first two block of the secondary chain are for a brief moment considered
// side chains because up to that point the first one is considered the
// heavier chain.
expectedSideHashes := map[common.Hash]bool{
replacementBlocks[0].Hash(): true,
replacementBlocks[1].Hash(): true,
chain[0].Hash(): true,
chain[1].Hash(): true,
chain[2].Hash(): true,
}
i := 0
const timeoutDura = 10 * time.Second
timeout := time.NewTimer(timeoutDura)
done:
for {
select {
case ev := <-chainSideCh:
block := ev.Block
if _, ok := expectedSideHashes[block.Hash()]; !ok {
t.Errorf("%d: didn't expect %x to be in side chain", i, block.Hash())
}
i++
if i == len(expectedSideHashes) {
timeout.Stop()
break done
}
timeout.Reset(timeoutDura)
case <-timeout.C:
t.Fatal("Timeout. Possibly not all blocks were triggered for sideevent")
}
}
// make sure no more events are fired
select {
case e := <-chainSideCh:
t.Errorf("unexpected event fired: %v", e)
case <-time.After(250 * time.Millisecond):
}
}
// Tests if the canonical block can be fetched from the database during chain insertion. // Tests if the canonical block can be fetched from the database during chain insertion.
func TestCanonicalBlockRetrieval(t *testing.T) { func TestCanonicalBlockRetrieval(t *testing.T) {
testCanonicalBlockRetrieval(t, rawdb.HashScheme) testCanonicalBlockRetrieval(t, rawdb.HashScheme)
@ -2277,11 +2190,11 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
gspec = &Genesis{ gspec = &Genesis{
Config: &chainConfig, Config: &chainConfig,
Alloc: types.GenesisAlloc{addr: {Balance: big.NewInt(math.MaxInt64)}}, Alloc: types.GenesisAlloc{addr: {Balance: big.NewInt(gomath.MaxInt64)}},
BaseFee: big.NewInt(params.InitialBaseFee), BaseFee: big.NewInt(params.InitialBaseFee),
} }
signer = types.LatestSigner(gspec.Config) signer = types.LatestSigner(gspec.Config)
mergeBlock = math.MaxInt32 mergeBlock = gomath.MaxInt32
) )
// Generate and import the canonical chain // Generate and import the canonical chain
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil, nil) chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil, nil)
@ -2582,7 +2495,7 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i
Config: &chainConfig, Config: &chainConfig,
} }
engine = beacon.New(ethash.NewFaker()) engine = beacon.New(ethash.NewFaker())
mergeBlock = uint64(math.MaxUint64) mergeBlock = uint64(gomath.MaxUint64)
) )
// Apply merging since genesis // Apply merging since genesis
if mergeHeight == 0 { if mergeHeight == 0 {
@ -3059,13 +2972,13 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) {
datadir := t.TempDir() datadir := t.TempDir()
ancient := path.Join(datadir, "ancient") ancient := path.Join(datadir, "ancient")
db, err := rawdb.Open(rawdb.OpenOptions{ pdb, err := pebble.New(datadir, 0, 0, "", false)
Directory: datadir,
AncientsDirectory: ancient,
Ephemeral: true,
})
if err != nil { if err != nil {
t.Fatalf("Failed to create persistent database: %v", err) t.Fatalf("Failed to create persistent key-value database: %v", err)
}
db, err := rawdb.NewDatabaseWithFreezer(pdb, ancient, "", false)
if err != nil {
t.Fatalf("Failed to create persistent freezer database: %v", err)
} }
defer db.Close() defer db.Close()
@ -4577,11 +4490,7 @@ func TestEIP3651(t *testing.T) {
gspec.Config.BerlinBlock = common.Big0 gspec.Config.BerlinBlock = common.Big0
gspec.Config.LondonBlock = common.Big0 gspec.Config.LondonBlock = common.Big0
gspec.Config.TerminalTotalDifficulty = common.Big0 gspec.Config.TerminalTotalDifficulty = common.Big0
gspec.Config.TerminalTotalDifficultyPassed = true gspec.Config.ShanghaiTime = u64(0)
gspec.Config.ShanghaiBlock = common.Big0
// gspec.Config.CancunBlock = common.Big0
// gspec.Config.PragueBlock = common.Big0
// gspec.Config.VerkleBlock = common.Big0
signer := types.LatestSigner(gspec.Config) signer := types.LatestSigner(gspec.Config)
_, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) { _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) {
@ -4639,3 +4548,87 @@ func TestEIP3651(t *testing.T) {
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual) t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
} }
} }
// Simple deposit generator, source: https://gist.github.com/lightclient/54abb2af2465d6969fa6d1920b9ad9d7
var depositsGeneratorCode = common.FromHex("6080604052366103aa575f603067ffffffffffffffff811115610025576100246103ae565b5b6040519080825280601f01601f1916602001820160405280156100575781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f8151811061007d5761007c6103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f602067ffffffffffffffff8111156100c7576100c66103ae565b5b6040519080825280601f01601f1916602001820160405280156100f95781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f8151811061011f5761011e6103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f600867ffffffffffffffff811115610169576101686103ae565b5b6040519080825280601f01601f19166020018201604052801561019b5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f815181106101c1576101c06103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f606067ffffffffffffffff81111561020b5761020a6103ae565b5b6040519080825280601f01601f19166020018201604052801561023d5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f81518110610263576102626103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f600867ffffffffffffffff8111156102ad576102ac6103ae565b5b6040519080825280601f01601f1916602001820160405280156102df5781602001600182028036833780820191505090505b5090505f8054906101000a900460ff1660f81b815f81518110610305576103046103db565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f8081819054906101000a900460ff168092919061035090610441565b91906101000a81548160ff021916908360ff160217905550507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c585858585856040516103a09594939291906104d9565b60405180910390a1005b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f60ff82169050919050565b5f61044b82610435565b915060ff820361045e5761045d610408565b5b600182019050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6104ab82610469565b6104b58185610473565b93506104c5818560208601610483565b6104ce81610491565b840191505092915050565b5f60a0820190508181035f8301526104f181886104a1565b9050818103602083015261050581876104a1565b9050818103604083015261051981866104a1565b9050818103606083015261052d81856104a1565b9050818103608083015261054181846104a1565b9050969550505050505056fea26469706673582212208569967e58690162d7d6fe3513d07b393b4c15e70f41505cbbfd08f53eba739364736f6c63430008190033")
// This is a smoke test for EIP-7685 requests added in the Prague fork. The test first
// creates a block containing requests, and then inserts it into the chain to run
// validation.
func TestPragueRequests(t *testing.T) {
var (
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
config = *params.MergedTestChainConfig
signer = types.LatestSigner(&config)
engine = beacon.NewFaker()
)
gspec := &Genesis{
Config: &config,
Alloc: types.GenesisAlloc{
addr1: {Balance: big.NewInt(9999900000000000)},
config.DepositContractAddress: {Code: depositsGeneratorCode},
params.WithdrawalQueueAddress: {Code: params.WithdrawalQueueCode},
params.ConsolidationQueueAddress: {Code: params.ConsolidationQueueCode},
},
}
_, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) {
// create deposit
depositTx := types.MustSignNewTx(key1, signer, &types.DynamicFeeTx{
ChainID: gspec.Config.ChainID,
Nonce: 0,
To: &config.DepositContractAddress,
Gas: 500_000,
GasFeeCap: newGwei(5),
GasTipCap: big.NewInt(2),
})
b.AddTx(depositTx)
// create withdrawal request
withdrawalTx := types.MustSignNewTx(key1, signer, &types.DynamicFeeTx{
ChainID: gspec.Config.ChainID,
Nonce: 1,
To: &params.WithdrawalQueueAddress,
Gas: 500_000,
GasFeeCap: newGwei(5),
GasTipCap: big.NewInt(2),
Value: newGwei(1),
Data: common.FromHex("b917cfdc0d25b72d55cf94db328e1629b7f4fde2c30cdacf873b664416f76a0c7f7cc50c9f72a3cb84be88144cde91250000000000000d80"),
})
b.AddTx(withdrawalTx)
// create consolidation request
consolidationTx := types.MustSignNewTx(key1, signer, &types.DynamicFeeTx{
ChainID: gspec.Config.ChainID,
Nonce: 2,
To: &params.ConsolidationQueueAddress,
Gas: 500_000,
GasFeeCap: newGwei(5),
GasTipCap: big.NewInt(2),
Value: newGwei(1),
Data: common.FromHex("b917cfdc0d25b72d55cf94db328e1629b7f4fde2c30cdacf873b664416f76a0c7f7cc50c9f72a3cb84be88144cde9125b9812f7d0b1f2f969b52bbb2d316b0c2fa7c9dba85c428c5e6c27766bcc4b0c6e874702ff1eb1c7024b08524a9771601"),
})
b.AddTx(consolidationTx)
})
// Check block has the correct requests hash.
rh := blocks[0].RequestsHash()
if rh == nil {
t.Fatal("block has nil requests hash")
}
expectedRequestsHash := common.HexToHash("0x06ffb72b9f0823510b128bca6cd4f96f59b745de6791e9fc350b596e7605101e")
if *rh != expectedRequestsHash {
t.Fatalf("block has wrong requestsHash %v, want %v", *rh, expectedRequestsHash)
}
// Insert block to check validation.
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil)
if err != nil {
t.Fatalf("failed to create tester chain: %v", err)
}
defer chain.Stop()
if n, err := chain.InsertChain(blocks); err != nil {
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
}
}

View file

@ -227,21 +227,18 @@ func (c *ChainIndexer) eventLoop(currentHeader *types.Header, events chan ChainH
return return
} }
if ev.Header.ParentHash != prevHash {
header := ev.Block.Header()
if header.ParentHash != prevHash {
// Reorg to the common ancestor if needed (might not exist in light sync mode, skip reorg then) // Reorg to the common ancestor if needed (might not exist in light sync mode, skip reorg then)
// TODO(karalabe, zsfelfoldi): This seems a bit brittle, can we detect this case explicitly? // TODO(karalabe, zsfelfoldi): This seems a bit brittle, can we detect this case explicitly?
if rawdb.ReadCanonicalHash(c.chainDb, prevHeader.Number.Uint64()) != prevHash { if rawdb.ReadCanonicalHash(c.chainDb, prevHeader.Number.Uint64()) != prevHash {
if h := rawdb.FindCommonAncestor(c.chainDb, prevHeader, header); h != nil { if h := rawdb.FindCommonAncestor(c.chainDb, prevHeader, ev.Header); h != nil {
c.newHead(h.Number.Uint64(), true) c.newHead(h.Number.Uint64(), true)
} }
} }
} }
c.newHead(ev.Header.Number.Uint64(), false)
c.newHead(header.Number.Uint64(), false) prevHeader, prevHash = ev.Header, ev.Header.Hash()
prevHeader, prevHash = header, header.Hash()
} }
} }
} }

View file

@ -359,18 +359,34 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
gen(i, b) gen(i, b)
} }
var requests types.Requests var requests [][]byte
if config.IsPrague(b.header.Number) && config.Bor == nil { if config.IsPrague(b.header.Number, b.header.Time) {
// EIP-6110 deposits
var blockLogs []*types.Log
for _, r := range b.receipts { for _, r := range b.receipts {
d, err := ParseDepositLogs(r.Logs, config) blockLogs = append(blockLogs, r.Logs...)
if err != nil {
panic(fmt.Sprintf("failed to parse deposit log: %v", err))
}
requests = append(requests, d...)
} }
depositRequests, err := ParseDepositLogs(blockLogs, config)
if err != nil {
panic(fmt.Sprintf("failed to parse deposit log: %v", err))
}
requests = append(requests, depositRequests)
// create EVM for system calls
blockContext := NewEVMBlockContext(b.header, cm, &b.header.Coinbase)
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, cm.config, vm.Config{})
// EIP-7002 withdrawals
withdrawalRequests := ProcessWithdrawalQueue(vmenv, statedb)
requests = append(requests, withdrawalRequests)
// EIP-7251 consolidations
consolidationRequests := ProcessConsolidationQueue(vmenv, statedb)
requests = append(requests, consolidationRequests)
}
if requests != nil {
reqHash := types.CalcRequestsHash(requests)
b.header.RequestsHash = &reqHash
} }
body := types.Body{Transactions: b.txs, Uncles: b.uncles, Withdrawals: b.withdrawals, Requests: requests} body := types.Body{Transactions: b.txs, Uncles: b.uncles, Withdrawals: b.withdrawals}
block, err := b.engine.FinalizeAndAssemble(cm, b.header, statedb, &body, b.receipts) block, err := b.engine.FinalizeAndAssemble(cm, b.header, statedb, &body, b.receipts)
if err != nil { if err != nil {
panic(err) panic(err)
@ -461,16 +477,15 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine
// Save pre state for proof generation // Save pre state for proof generation
// preState := statedb.Copy() // preState := statedb.Copy()
// TODO uncomment when the 2935 PR is merged // Pre-execution system calls.
// if config.IsPrague(b.header.Number, b.header.Time) { if config.IsPrague(b.header.Number, b.header.Time) {
// if !config.IsPrague(b.parent.Number(), b.parent.Time()) { // EIP-2935
// Transition case: insert all 256 ancestors blockContext := NewEVMBlockContext(b.header, cm, &b.header.Coinbase)
// InsertBlockHashHistoryAtEip2935Fork(statedb, b.header.Number.Uint64()-1, b.header.ParentHash, chainreader) vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, cm.config, vm.Config{})
// } else { ProcessParentBlockHash(b.header.ParentHash, vmenv, statedb)
// ProcessParentBlockHash(statedb, b.header.Number.Uint64()-1, b.header.ParentHash) }
// }
// } // Execute any user modifications to the block.
// Execute any user modifications to the block
if gen != nil { if gen != nil {
gen(i, b) gen(i, b)
} }
@ -484,7 +499,7 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine
panic(err) panic(err)
} }
// Write state changes to db // Write state changes to DB.
root, err := statedb.Commit(b.header.Number.Uint64(), config.IsEIP158(b.header.Number)) root, err := statedb.Commit(b.header.Number.Uint64(), config.IsEIP158(b.header.Number))
if err != nil { if err != nil {
panic(fmt.Sprintf("state write error: %v", err)) panic(fmt.Sprintf("state write error: %v", err))

View file

@ -57,7 +57,6 @@ func TestGeneratePOSChain(t *testing.T) {
db = rawdb.NewMemoryDatabase() db = rawdb.NewMemoryDatabase()
) )
config.TerminalTotalDifficultyPassed = true
config.TerminalTotalDifficulty = common.Big0 config.TerminalTotalDifficulty = common.Big0
config.ShanghaiBlock = common.Big0 config.ShanghaiBlock = common.Big0
config.CancunBlock = common.Big0 config.CancunBlock = common.Big0

View file

@ -17,27 +17,19 @@
package core package core
import ( import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
) )
// NewTxsEvent is posted when a batch of transactions enter the transaction pool. // NewTxsEvent is posted when a batch of transactions enter the transaction pool.
type NewTxsEvent struct{ Txs []*types.Transaction } type NewTxsEvent struct{ Txs []*types.Transaction }
// NewMinedBlockEvent is posted when a block has been imported.
type NewMinedBlockEvent struct{ Block *types.Block }
// RemovedLogsEvent is posted when a reorg happens // RemovedLogsEvent is posted when a reorg happens
type RemovedLogsEvent struct{ Logs []*types.Log } type RemovedLogsEvent struct{ Logs []*types.Log }
type ChainEvent struct { type ChainEvent struct {
Block *types.Block Header *types.Header
Hash common.Hash
Logs []*types.Log
} }
type ChainSideEvent struct { type ChainHeadEvent struct {
Block *types.Block Header *types.Header
} }
type ChainHeadEvent struct{ Block *types.Block }

View file

@ -364,24 +364,25 @@ func TestTimeBasedForkInGenesis(t *testing.T) {
forkidHash = checksumToBytes(crc32.ChecksumIEEE(genesis.Hash().Bytes())) forkidHash = checksumToBytes(crc32.ChecksumIEEE(genesis.Hash().Bytes()))
config = func(shanghai, cancun uint64) *params.ChainConfig { config = func(shanghai, cancun uint64) *params.ChainConfig {
return &params.ChainConfig{ return &params.ChainConfig{
ChainID: big.NewInt(1337), ChainID: big.NewInt(1337),
HomesteadBlock: big.NewInt(0), HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil, DAOForkBlock: nil,
DAOForkSupport: true, DAOForkSupport: true,
EIP150Block: big.NewInt(0), EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0), EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0), EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0), ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0), ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0), IstanbulBlock: big.NewInt(0),
MuirGlacierBlock: big.NewInt(0), MuirGlacierBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0), BerlinBlock: big.NewInt(0),
LondonBlock: big.NewInt(0), LondonBlock: big.NewInt(0),
TerminalTotalDifficulty: big.NewInt(0), TerminalTotalDifficulty: big.NewInt(0),
TerminalTotalDifficultyPassed: true, MergeNetsplitBlock: big.NewInt(0),
MergeNetsplitBlock: big.NewInt(0), ShanghaiTime: &shanghai,
Ethash: new(params.EthashConfig), CancunTime: &cancun,
Ethash: new(params.EthashConfig),
} }
} }
) )

View file

@ -489,7 +489,6 @@ func (g *Genesis) toBlockWithRoot(root common.Hash) *types.Block {
} }
var ( var (
withdrawals []*types.Withdrawal withdrawals []*types.Withdrawal
requests types.Requests
) )
if conf := g.Config; conf != nil { if conf := g.Config; conf != nil {
num := big.NewInt(int64(g.Number)) num := big.NewInt(int64(g.Number))
@ -512,12 +511,13 @@ func (g *Genesis) toBlockWithRoot(root common.Hash) *types.Block {
head.BlobGasUsed = new(uint64) head.BlobGasUsed = new(uint64)
} }
} }
if conf.IsPrague(num) { if conf.IsPrague(num, g.Timestamp) {
head.RequestsHash = &types.EmptyRequestsHash emptyRequests := [][]byte{{0x00}, {0x01}, {0x02}}
requests = make(types.Requests, 0) rhash := types.CalcRequestsHash(emptyRequests)
head.RequestsHash = &rhash
} }
} }
return types.NewBlock(head, &types.Body{Withdrawals: withdrawals, Requests: requests}, nil, trie.NewStackTrie(nil)) return types.NewBlock(head, &types.Body{Withdrawals: withdrawals}, nil, trie.NewStackTrie(nil))
} }
// Commit writes the block and state of a genesis specification to the database. // Commit writes the block and state of a genesis specification to the database.
@ -680,10 +680,11 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis {
common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul
common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing
common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b
// Pre-deploy EIP-4788 system contract // Pre-deploy system contracts
params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0}, params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0},
// Pre-deploy EIP-2935 history contract. params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode, Balance: common.Big0},
params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode, Balance: common.Big0}, params.WithdrawalQueueAddress: {Nonce: 1, Code: params.WithdrawalQueueCode, Balance: common.Big0},
params.ConsolidationQueueAddress: {Nonce: 1, Code: params.ConsolidationQueueCode, Balance: common.Big0},
}, },
} }
if faucet != nil { if faucet != nil {

View file

@ -266,31 +266,30 @@ func TestVerkleGenesisCommit(t *testing.T) {
t.Skip("verkle trie is not yet supported in bor") t.Skip("verkle trie is not yet supported in bor")
var verkleTime uint64 = 0 var verkleTime uint64 = 0
verkleConfig := &params.ChainConfig{ verkleConfig := &params.ChainConfig{
ChainID: big.NewInt(1), ChainID: big.NewInt(1),
HomesteadBlock: big.NewInt(0), HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil, DAOForkBlock: nil,
DAOForkSupport: false, DAOForkSupport: false,
EIP150Block: big.NewInt(0), EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0), EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0), EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0), ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0), ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0), IstanbulBlock: big.NewInt(0),
MuirGlacierBlock: big.NewInt(0), MuirGlacierBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0), BerlinBlock: big.NewInt(0),
LondonBlock: big.NewInt(0), LondonBlock: big.NewInt(0),
ArrowGlacierBlock: big.NewInt(0), ArrowGlacierBlock: big.NewInt(0),
GrayGlacierBlock: big.NewInt(0), GrayGlacierBlock: big.NewInt(0),
MergeNetsplitBlock: nil, MergeNetsplitBlock: nil,
ShanghaiBlock: big.NewInt(0), ShanghaiTime: &verkleTime,
CancunBlock: big.NewInt(0), CancunTime: &verkleTime,
PragueBlock: big.NewInt(0), PragueTime: &verkleTime,
VerkleBlock: big.NewInt(0), VerkleTime: &verkleTime,
TerminalTotalDifficulty: big.NewInt(0), TerminalTotalDifficulty: big.NewInt(0),
TerminalTotalDifficultyPassed: true, Ethash: nil,
Ethash: nil, Clique: nil,
Clique: nil,
} }
genesis := &Genesis{ genesis := &Genesis{

Some files were not shown because too many files have changed in this diff Show more