mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-12 15:03:45 +00:00
Merge branch 'ethereum:master' into portal
This commit is contained in:
commit
65f1f82e74
31 changed files with 6956 additions and 496 deletions
|
|
@ -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 Linux Azure uploads
|
# This builder does the Linux Azure uploads
|
||||||
- stage: build
|
- stage: build
|
||||||
|
|
|
||||||
|
|
@ -338,8 +338,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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
payload := append(path, txrlp...)
|
payload := append(path, txrlp...)
|
||||||
|
|
@ -353,7 +367,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 {
|
||||||
|
|
@ -381,8 +397,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)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -1,129 +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("0x6509b691f4de4f7b083f2784938fd52f0e131675432b3fd85ea549af9aebd3d0"),
|
|
||||||
}
|
|
||||||
|
|
||||||
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("0x456e85f5608afab3465a0580bff8572255f6d97af0c5f939e3f7536b5edb2d3f"),
|
|
||||||
}
|
|
||||||
|
|
||||||
HoleskyConfig = lightClientConfig{
|
|
||||||
ChainConfig: (&types.ChainConfig{
|
|
||||||
GenesisValidatorsRoot: common.HexToHash("0x9143aa7c615a7f7115e2b6aac319c03529df8242ae705fba9df39b79c59fa8b1"),
|
|
||||||
GenesisTime: 1695902400,
|
|
||||||
}).
|
|
||||||
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}),
|
|
||||||
Checkpoint: common.HexToHash("0x6456a1317f54d4b4f2cb5bc9d153b5af0988fe767ef0609f0236cf29030bcff7"),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func makeChainConfig(ctx *cli.Context) lightClientConfig {
|
|
||||||
var config lightClientConfig
|
|
||||||
customConfig := ctx.IsSet(utils.BeaconConfigFlag.Name)
|
|
||||||
utils.CheckExclusive(ctx, utils.MainnetFlag, utils.SepoliaFlag, utils.HoleskyFlag, utils.BeaconConfigFlag)
|
|
||||||
switch {
|
|
||||||
case ctx.Bool(utils.MainnetFlag.Name):
|
|
||||||
config = MainnetConfig
|
|
||||||
case ctx.Bool(utils.SepoliaFlag.Name):
|
|
||||||
config = SepoliaConfig
|
|
||||||
case ctx.Bool(utils.HoleskyFlag.Name):
|
|
||||||
config = HoleskyConfig
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -76,24 +76,24 @@ 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
|
||||||
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,
|
||||||
|
|
@ -505,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
|
||||||
|
|
|
||||||
|
|
@ -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}},
|
¶ms.Fork{Epoch: 0, Version: []byte{0}},
|
||||||
})
|
})
|
||||||
tfAlternative = newTestForks(testGenesis, types.Forks{
|
tfAlternative = newTestForks(testGenesis, params.Forks{
|
||||||
&types.Fork{Epoch: 0, Version: []byte{0}},
|
¶ms.Fork{Epoch: 0, Version: []byte{0}},
|
||||||
&types.Fork{Epoch: 0x700, Version: []byte{1}},
|
¶ms.Fork{Epoch: 0x700, Version: []byte{1}},
|
||||||
})
|
})
|
||||||
tfAnotherGenesis = newTestForks(testGenesis2, types.Forks{
|
tfAnotherGenesis = newTestForks(testGenesis2, params.Forks{
|
||||||
&types.Fork{Epoch: 0, Version: []byte{0}},
|
¶ms.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) {
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
56
beacon/params/networks.go
Normal 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})
|
||||||
|
)
|
||||||
|
|
@ -70,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()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -76,36 +76,53 @@ 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 := execStats{
|
||||||
stats.allocs = result.AllocsPerOp()
|
Time: time.Duration(result.NsPerOp()),
|
||||||
stats.bytesAllocated = result.AllocedBytesPerOp()
|
Allocs: result.AllocsPerOp(),
|
||||||
} else {
|
BytesAllocated: result.AllocedBytesPerOp(),
|
||||||
var memStatsBefore, memStatsAfter goruntime.MemStats
|
GasUsed: gasUsed,
|
||||||
goruntime.ReadMemStats(&memStatsBefore)
|
}
|
||||||
startTime := time.Now()
|
return output, stats, err
|
||||||
output, gasLeft, err = execFunc()
|
|
||||||
stats.time = time.Since(startTime)
|
|
||||||
goruntime.ReadMemStats(&memStatsAfter)
|
|
||||||
stats.allocs = int64(memStatsAfter.Mallocs - memStatsBefore.Mallocs)
|
|
||||||
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 {
|
||||||
|
|
@ -265,12 +282,13 @@ func runCmd(ctx *cli.Context) error {
|
||||||
statedb.SetCode(receiver, code)
|
statedb.SetCode(receiver, code)
|
||||||
}
|
}
|
||||||
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)
|
||||||
|
|
@ -300,7 +318,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 {
|
||||||
fmt.Printf("%#x\n", output)
|
fmt.Printf("%#x\n", output)
|
||||||
|
|
|
||||||
|
|
@ -27,26 +27,51 @@ 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"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
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 {
|
||||||
|
|
@ -67,7 +92,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)
|
||||||
|
|
@ -76,15 +101,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
|
||||||
|
|
@ -94,31 +152,38 @@ func runStateTest(fname string, cfg vm.Config, dump bool) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
matchingTests := collectMatchedSubtests(ctx, testsByName)
|
||||||
|
|
||||||
// Iterate over all the tests, run them and aggregate the results
|
// Iterate over all the tests, run them and aggregate the results
|
||||||
results := make([]StatetestResult, 0, len(testsByName))
|
var results []StatetestResult
|
||||||
for key, test := range testsByName {
|
for _, test := range matchingTests {
|
||||||
for _, st := range test.Subtests() {
|
// Run the test and aggregate the result
|
||||||
// Run the test and aggregate the result
|
result := &StatetestResult{Name: test.name, Fork: test.st.Fork, Pass: true}
|
||||||
result := &StatetestResult{Name: key, Fork: st.Fork, Pass: true}
|
test.test.Run(test.st, cfg, false, rawdb.HashScheme, func(err error, tstate *tests.StateTestState) {
|
||||||
test.Run(st, cfg, false, rawdb.HashScheme, func(err error, tstate *tests.StateTestState) {
|
var root common.Hash
|
||||||
var root common.Hash
|
if tstate.StateDB != nil {
|
||||||
if tstate.StateDB != nil {
|
root = tstate.StateDB.IntermediateRoot(false)
|
||||||
root = tstate.StateDB.IntermediateRoot(false)
|
result.Root = &root
|
||||||
result.Root = &root
|
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
|
||||||
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
|
if dump { // Dump any state to aid debugging
|
||||||
if dump { // Dump any state to aid debugging
|
cpy, _ := state.New(root, tstate.StateDB.Database())
|
||||||
cpy, _ := state.New(root, tstate.StateDB.Database())
|
dump := cpy.RawDump(nil)
|
||||||
dump := cpy.RawDump(nil)
|
result.State = &dump
|
||||||
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, "", " ")
|
||||||
fmt.Println(string(out))
|
fmt.Println(string(out))
|
||||||
|
|
|
||||||
|
|
@ -240,7 +240,7 @@ func makeFullNode(ctx *cli.Context) *node.Node {
|
||||||
// Start blsync mode.
|
// Start blsync mode.
|
||||||
srv := rpc.NewServer()
|
srv := rpc.NewServer()
|
||||||
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 {
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,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"
|
||||||
|
|
@ -1970,6 +1971,81 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
|
|
||||||
|
|
@ -186,9 +186,9 @@ func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) {
|
||||||
// is optional and may be partially useful if it's not fully
|
// is optional and may be partially useful if it's not fully
|
||||||
// generated.
|
// generated.
|
||||||
if db.snap != nil {
|
if db.snap != nil {
|
||||||
sr, err := newStateReader(stateRoot, db.snap)
|
snap := db.snap.Snapshot(stateRoot)
|
||||||
if err == nil {
|
if snap != nil {
|
||||||
readers = append(readers, sr) // snap reader is optional
|
readers = append(readers, newStateReader(snap)) // snap reader is optional
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Set up the trie reader, which is expected to always be available
|
// Set up the trie reader, which is expected to always be available
|
||||||
|
|
|
||||||
|
|
@ -21,13 +21,13 @@ import (
|
||||||
"maps"
|
"maps"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"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/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/ethereum/go-ethereum/trie/utils"
|
"github.com/ethereum/go-ethereum/trie/utils"
|
||||||
"github.com/ethereum/go-ethereum/triedb"
|
"github.com/ethereum/go-ethereum/triedb"
|
||||||
|
"github.com/ethereum/go-ethereum/triedb/database"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Reader defines the interface for accessing accounts and storage slots
|
// Reader defines the interface for accessing accounts and storage slots
|
||||||
|
|
@ -52,23 +52,18 @@ type Reader interface {
|
||||||
Copy() Reader
|
Copy() Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
// stateReader is a wrapper over the state snapshot and implements the Reader
|
// stateReader wraps a database state reader.
|
||||||
// interface. It provides an efficient way to access flat state.
|
|
||||||
type stateReader struct {
|
type stateReader struct {
|
||||||
snap snapshot.Snapshot
|
reader database.StateReader
|
||||||
buff crypto.KeccakState
|
buff crypto.KeccakState
|
||||||
}
|
}
|
||||||
|
|
||||||
// newStateReader constructs a flat state reader with on the specified state root.
|
// newStateReader constructs a state reader with on the given state root.
|
||||||
func newStateReader(root common.Hash, snaps *snapshot.Tree) (*stateReader, error) {
|
func newStateReader(reader database.StateReader) *stateReader {
|
||||||
snap := snaps.Snapshot(root)
|
|
||||||
if snap == nil {
|
|
||||||
return nil, errors.New("snapshot is not available")
|
|
||||||
}
|
|
||||||
return &stateReader{
|
return &stateReader{
|
||||||
snap: snap,
|
reader: reader,
|
||||||
buff: crypto.NewKeccakState(),
|
buff: crypto.NewKeccakState(),
|
||||||
}, nil
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Account implements Reader, retrieving the account specified by the address.
|
// Account implements Reader, retrieving the account specified by the address.
|
||||||
|
|
@ -78,18 +73,18 @@ func newStateReader(root common.Hash, snaps *snapshot.Tree) (*stateReader, error
|
||||||
//
|
//
|
||||||
// The returned account might be nil if it's not existent.
|
// The returned account might be nil if it's not existent.
|
||||||
func (r *stateReader) Account(addr common.Address) (*types.StateAccount, error) {
|
func (r *stateReader) Account(addr common.Address) (*types.StateAccount, error) {
|
||||||
ret, err := r.snap.Account(crypto.HashData(r.buff, addr.Bytes()))
|
account, err := r.reader.Account(crypto.HashData(r.buff, addr.Bytes()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if ret == nil {
|
if account == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
acct := &types.StateAccount{
|
acct := &types.StateAccount{
|
||||||
Nonce: ret.Nonce,
|
Nonce: account.Nonce,
|
||||||
Balance: ret.Balance,
|
Balance: account.Balance,
|
||||||
CodeHash: ret.CodeHash,
|
CodeHash: account.CodeHash,
|
||||||
Root: common.BytesToHash(ret.Root),
|
Root: common.BytesToHash(account.Root),
|
||||||
}
|
}
|
||||||
if len(acct.CodeHash) == 0 {
|
if len(acct.CodeHash) == 0 {
|
||||||
acct.CodeHash = types.EmptyCodeHash.Bytes()
|
acct.CodeHash = types.EmptyCodeHash.Bytes()
|
||||||
|
|
@ -110,7 +105,7 @@ func (r *stateReader) Account(addr common.Address) (*types.StateAccount, error)
|
||||||
func (r *stateReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) {
|
func (r *stateReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) {
|
||||||
addrHash := crypto.HashData(r.buff, addr.Bytes())
|
addrHash := crypto.HashData(r.buff, addr.Bytes())
|
||||||
slotHash := crypto.HashData(r.buff, key.Bytes())
|
slotHash := crypto.HashData(r.buff, key.Bytes())
|
||||||
ret, err := r.snap.Storage(addrHash, slotHash)
|
ret, err := r.reader.Storage(addrHash, slotHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
|
|
@ -131,8 +126,8 @@ func (r *stateReader) Storage(addr common.Address, key common.Hash) (common.Hash
|
||||||
// Copy implements Reader, returning a deep-copied snap reader.
|
// Copy implements Reader, returning a deep-copied snap reader.
|
||||||
func (r *stateReader) Copy() Reader {
|
func (r *stateReader) Copy() Reader {
|
||||||
return &stateReader{
|
return &stateReader{
|
||||||
snap: r.snap,
|
reader: r.reader,
|
||||||
buff: crypto.NewKeccakState(),
|
buff: crypto.NewKeccakState(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -198,22 +198,46 @@ func (s *hookedStateDB) SetState(address common.Address, key common.Hash, value
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *hookedStateDB) SelfDestruct(address common.Address) uint256.Int {
|
func (s *hookedStateDB) SelfDestruct(address common.Address) uint256.Int {
|
||||||
prev := s.inner.SelfDestruct(address)
|
var prevCode []byte
|
||||||
if !prev.IsZero() {
|
var prevCodeHash common.Hash
|
||||||
if s.hooks.OnBalanceChange != nil {
|
|
||||||
s.hooks.OnBalanceChange(address, prev.ToBig(), new(big.Int), tracing.BalanceDecreaseSelfdestruct)
|
if s.hooks.OnCodeChange != nil {
|
||||||
}
|
prevCode = s.inner.GetCode(address)
|
||||||
|
prevCodeHash = s.inner.GetCodeHash(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prev := s.inner.SelfDestruct(address)
|
||||||
|
|
||||||
|
if s.hooks.OnBalanceChange != nil && !prev.IsZero() {
|
||||||
|
s.hooks.OnBalanceChange(address, prev.ToBig(), new(big.Int), tracing.BalanceDecreaseSelfdestruct)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.hooks.OnCodeChange != nil && len(prevCode) > 0 {
|
||||||
|
s.hooks.OnCodeChange(address, prevCodeHash, prevCode, types.EmptyCodeHash, nil)
|
||||||
|
}
|
||||||
|
|
||||||
return prev
|
return prev
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *hookedStateDB) SelfDestruct6780(address common.Address) (uint256.Int, bool) {
|
func (s *hookedStateDB) SelfDestruct6780(address common.Address) (uint256.Int, bool) {
|
||||||
prev, changed := s.inner.SelfDestruct6780(address)
|
var prevCode []byte
|
||||||
if !prev.IsZero() && changed {
|
var prevCodeHash common.Hash
|
||||||
if s.hooks.OnBalanceChange != nil {
|
|
||||||
s.hooks.OnBalanceChange(address, prev.ToBig(), new(big.Int), tracing.BalanceDecreaseSelfdestruct)
|
if s.hooks.OnCodeChange != nil {
|
||||||
}
|
prevCodeHash = s.inner.GetCodeHash(address)
|
||||||
|
prevCode = s.inner.GetCode(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prev, changed := s.inner.SelfDestruct6780(address)
|
||||||
|
|
||||||
|
if s.hooks.OnBalanceChange != nil && changed && !prev.IsZero() {
|
||||||
|
s.hooks.OnBalanceChange(address, prev.ToBig(), new(big.Int), tracing.BalanceDecreaseSelfdestruct)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.hooks.OnCodeChange != nil && changed && len(prevCode) > 0 {
|
||||||
|
s.hooks.OnCodeChange(address, prevCodeHash, prevCode, types.EmptyCodeHash, nil)
|
||||||
|
}
|
||||||
|
|
||||||
return prev, changed
|
return prev, changed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,12 @@
|
||||||
package eth
|
package eth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
|
|
@ -37,6 +39,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -142,10 +145,12 @@ func (b *testBackend) RunPeer(peer *Peer, handler Handler) error {
|
||||||
func (b *testBackend) PeerInfo(enode.ID) interface{} { panic("not implemented") }
|
func (b *testBackend) PeerInfo(enode.ID) interface{} { panic("not implemented") }
|
||||||
|
|
||||||
func (b *testBackend) AcceptTxs() bool {
|
func (b *testBackend) AcceptTxs() bool {
|
||||||
panic("data processing tests should be done in the handler package")
|
return true
|
||||||
|
//panic("data processing tests should be done in the handler package")
|
||||||
}
|
}
|
||||||
func (b *testBackend) Handle(*Peer, Packet) error {
|
func (b *testBackend) Handle(*Peer, Packet) error {
|
||||||
panic("data processing tests should be done in the handler package")
|
return nil
|
||||||
|
//panic("data processing tests should be done in the handler package")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that block headers can be retrieved from a remote chain based on user queries.
|
// Tests that block headers can be retrieved from a remote chain based on user queries.
|
||||||
|
|
@ -498,3 +503,76 @@ func testGetBlockReceipts(t *testing.T, protocol uint) {
|
||||||
t.Errorf("receipts mismatch: %v", err)
|
t.Errorf("receipts mismatch: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type decoder struct {
|
||||||
|
msg []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d decoder) Decode(val interface{}) error {
|
||||||
|
buffer := bytes.NewBuffer(d.msg)
|
||||||
|
s := rlp.NewStream(buffer, uint64(len(d.msg)))
|
||||||
|
return s.Decode(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d decoder) Time() time.Time {
|
||||||
|
return time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setup() (*testBackend, *testPeer) {
|
||||||
|
// Generate some transactions etc.
|
||||||
|
acc1Key, _ := crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
||||||
|
acc2Key, _ := crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
|
||||||
|
acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey)
|
||||||
|
acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey)
|
||||||
|
signer := types.HomesteadSigner{}
|
||||||
|
gen := func(n int, block *core.BlockGen) {
|
||||||
|
if n%2 == 0 {
|
||||||
|
w := &types.Withdrawal{
|
||||||
|
Address: common.Address{0xaa},
|
||||||
|
Amount: 42,
|
||||||
|
}
|
||||||
|
block.AddWithdrawal(w)
|
||||||
|
}
|
||||||
|
switch n {
|
||||||
|
case 0:
|
||||||
|
// In block 1, the test bank sends account #1 some ether.
|
||||||
|
tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), acc1Addr, big.NewInt(10_000_000_000_000_000), params.TxGas, block.BaseFee(), nil), signer, testKey)
|
||||||
|
block.AddTx(tx)
|
||||||
|
case 1:
|
||||||
|
// In block 2, the test bank sends some more ether to account #1.
|
||||||
|
// acc1Addr passes it on to account #2.
|
||||||
|
tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testAddr), acc1Addr, big.NewInt(1_000_000_000_000_000), params.TxGas, block.BaseFee(), nil), signer, testKey)
|
||||||
|
tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1_000_000_000_000_000), params.TxGas, block.BaseFee(), nil), signer, acc1Key)
|
||||||
|
block.AddTx(tx1)
|
||||||
|
block.AddTx(tx2)
|
||||||
|
case 2:
|
||||||
|
// Block 3 is empty but was mined by account #2.
|
||||||
|
block.SetCoinbase(acc2Addr)
|
||||||
|
block.SetExtra([]byte("yeehaw"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
backend := newTestBackendWithGenerator(maxBodiesServe+15, true, gen)
|
||||||
|
peer, _ := newTestPeer("peer", ETH68, backend)
|
||||||
|
// Discard all messages
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
msg, err := peer.app.ReadMsg()
|
||||||
|
if err == nil {
|
||||||
|
msg.Discard()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return backend, peer
|
||||||
|
}
|
||||||
|
|
||||||
|
func FuzzEthProtocolHandlers(f *testing.F) {
|
||||||
|
handlers := eth68
|
||||||
|
backend, peer := setup()
|
||||||
|
f.Fuzz(func(t *testing.T, code byte, msg []byte) {
|
||||||
|
handler := handlers[uint64(code)%protocolLengths[ETH68]]
|
||||||
|
if handler == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
handler(backend, decoder{msg: msg}, peer.Peer)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum"
|
"github.com/ethereum/go-ethereum"
|
||||||
|
|
@ -164,55 +165,85 @@ func TestGethClient(t *testing.T) {
|
||||||
|
|
||||||
func testAccessList(t *testing.T, client *rpc.Client) {
|
func testAccessList(t *testing.T, client *rpc.Client) {
|
||||||
ec := New(client)
|
ec := New(client)
|
||||||
// Test transfer
|
|
||||||
msg := ethereum.CallMsg{
|
for i, tc := range []struct {
|
||||||
From: testAddr,
|
msg ethereum.CallMsg
|
||||||
To: &common.Address{},
|
wantGas uint64
|
||||||
Gas: 21000,
|
wantErr string
|
||||||
GasPrice: big.NewInt(875000000),
|
wantVMErr string
|
||||||
Value: big.NewInt(1),
|
wantAL string
|
||||||
}
|
}{
|
||||||
al, gas, vmErr, err := ec.CreateAccessList(context.Background(), msg)
|
{ // Test transfer
|
||||||
if err != nil {
|
msg: ethereum.CallMsg{
|
||||||
t.Fatalf("unexpected error: %v", err)
|
From: testAddr,
|
||||||
}
|
To: &common.Address{},
|
||||||
if vmErr != "" {
|
Gas: 21000,
|
||||||
t.Fatalf("unexpected vm error: %v", vmErr)
|
GasPrice: big.NewInt(875000000),
|
||||||
}
|
Value: big.NewInt(1),
|
||||||
if gas != 21000 {
|
},
|
||||||
t.Fatalf("unexpected gas used: %v", gas)
|
wantGas: 21000,
|
||||||
}
|
wantAL: `[]`,
|
||||||
if len(*al) != 0 {
|
},
|
||||||
t.Fatalf("unexpected length of accesslist: %v", len(*al))
|
{ // Test reverting transaction
|
||||||
}
|
msg: ethereum.CallMsg{
|
||||||
// Test reverting transaction
|
From: testAddr,
|
||||||
msg = ethereum.CallMsg{
|
To: nil,
|
||||||
From: testAddr,
|
Gas: 100000,
|
||||||
To: nil,
|
GasPrice: big.NewInt(1000000000),
|
||||||
Gas: 100000,
|
Value: big.NewInt(1),
|
||||||
GasPrice: big.NewInt(1000000000),
|
Data: common.FromHex("0x608060806080608155fd"),
|
||||||
Value: big.NewInt(1),
|
},
|
||||||
Data: common.FromHex("0x608060806080608155fd"),
|
wantGas: 77496,
|
||||||
}
|
wantVMErr: "execution reverted",
|
||||||
al, gas, vmErr, err = ec.CreateAccessList(context.Background(), msg)
|
wantAL: `[
|
||||||
if err != nil {
|
{
|
||||||
t.Fatalf("unexpected error: %v", err)
|
"address": "0x3a220f351252089d385b29beca14e27f204c296a",
|
||||||
}
|
"storageKeys": [
|
||||||
if vmErr == "" {
|
"0x0000000000000000000000000000000000000000000000000000000000000081"
|
||||||
t.Fatalf("wanted vmErr, got none")
|
]
|
||||||
}
|
}
|
||||||
if gas == 21000 {
|
]`,
|
||||||
t.Fatalf("unexpected gas used: %v", gas)
|
},
|
||||||
}
|
{ // error when gasPrice is less than baseFee
|
||||||
if len(*al) != 1 || al.StorageKeys() != 1 {
|
msg: ethereum.CallMsg{
|
||||||
t.Fatalf("unexpected length of accesslist: %v", len(*al))
|
From: testAddr,
|
||||||
}
|
To: &common.Address{},
|
||||||
// address changes between calls, so we can't test for it.
|
Gas: 21000,
|
||||||
if (*al)[0].Address == common.HexToAddress("0x0") {
|
GasPrice: big.NewInt(1), // less than baseFee
|
||||||
t.Fatalf("unexpected address: %v", (*al)[0].Address)
|
Value: big.NewInt(1),
|
||||||
}
|
},
|
||||||
if (*al)[0].StorageKeys[0] != common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000081") {
|
wantErr: "max fee per gas less than block base fee",
|
||||||
t.Fatalf("unexpected storage key: %v", (*al)[0].StorageKeys[0])
|
},
|
||||||
|
{ // when gasPrice is not specified
|
||||||
|
msg: ethereum.CallMsg{
|
||||||
|
From: testAddr,
|
||||||
|
To: &common.Address{},
|
||||||
|
Gas: 21000,
|
||||||
|
Value: big.NewInt(1),
|
||||||
|
},
|
||||||
|
wantGas: 21000,
|
||||||
|
wantAL: `[]`,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
al, gas, vmErr, err := ec.CreateAccessList(context.Background(), tc.msg)
|
||||||
|
if tc.wantErr != "" {
|
||||||
|
if !strings.Contains(err.Error(), tc.wantErr) {
|
||||||
|
t.Fatalf("test %d: wrong error: %v", i, err)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
} else if err != nil {
|
||||||
|
t.Fatalf("test %d: wrong error: %v", i, err)
|
||||||
|
}
|
||||||
|
if have, want := vmErr, tc.wantVMErr; have != want {
|
||||||
|
t.Fatalf("test %d: vmErr wrong, have %v want %v", i, have, want)
|
||||||
|
}
|
||||||
|
if have, want := gas, tc.wantGas; have != want {
|
||||||
|
t.Fatalf("test %d: gas wrong, have %v want %v", i, have, want)
|
||||||
|
}
|
||||||
|
haveList, _ := json.MarshalIndent(al, "", " ")
|
||||||
|
if have, want := string(haveList), tc.wantAL; have != want {
|
||||||
|
t.Fatalf("test %d: access list wrong, have:\n%v\nwant:\n%v", i, have, want)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1287,9 +1287,18 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure any missing fields are filled, extract the recipient and input data
|
// Ensure any missing fields are filled, extract the recipient and input data
|
||||||
if err := args.setDefaults(ctx, b, true); err != nil {
|
if err = args.setFeeDefaults(ctx, b, header); err != nil {
|
||||||
return nil, 0, nil, err
|
return nil, 0, nil, err
|
||||||
}
|
}
|
||||||
|
if args.Nonce == nil {
|
||||||
|
nonce := hexutil.Uint64(db.GetNonce(args.from()))
|
||||||
|
args.Nonce = &nonce
|
||||||
|
}
|
||||||
|
blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil)
|
||||||
|
if err = args.CallDefaults(b.RPCGasCap(), blockCtx.BaseFee, b.ChainConfig().ChainID); err != nil {
|
||||||
|
return nil, 0, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var to common.Address
|
var to common.Address
|
||||||
if args.To != nil {
|
if args.To != nil {
|
||||||
to = *args.To
|
to = *args.To
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend, skipGas
|
||||||
if err := args.setBlobTxSidecar(ctx); err != nil {
|
if err := args.setBlobTxSidecar(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := args.setFeeDefaults(ctx, b); err != nil {
|
if err := args.setFeeDefaults(ctx, b, b.CurrentHeader()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -183,8 +183,7 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend, skipGas
|
||||||
}
|
}
|
||||||
|
|
||||||
// setFeeDefaults fills in default fee values for unspecified tx fields.
|
// setFeeDefaults fills in default fee values for unspecified tx fields.
|
||||||
func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend) error {
|
func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend, head *types.Header) error {
|
||||||
head := b.CurrentHeader()
|
|
||||||
// Sanity check the EIP-4844 fee parameters.
|
// Sanity check the EIP-4844 fee parameters.
|
||||||
if args.BlobFeeCap != nil && args.BlobFeeCap.ToInt().Sign() == 0 {
|
if args.BlobFeeCap != nil && args.BlobFeeCap.ToInt().Sign() == 0 {
|
||||||
return errors.New("maxFeePerBlobGas, if specified, must be non-zero")
|
return errors.New("maxFeePerBlobGas, if specified, must be non-zero")
|
||||||
|
|
|
||||||
|
|
@ -238,7 +238,7 @@ func TestSetFeeDefaults(t *testing.T) {
|
||||||
t.Fatalf("failed to set fork: %v", err)
|
t.Fatalf("failed to set fork: %v", err)
|
||||||
}
|
}
|
||||||
got := test.in
|
got := test.in
|
||||||
err := got.setFeeDefaults(ctx, b)
|
err := got.setFeeDefaults(ctx, b, b.CurrentHeader())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if test.err == nil {
|
if test.err == nil {
|
||||||
t.Fatalf("test %d (%s): unexpected error: %s", i, test.name, err)
|
t.Fatalf("test %d (%s): unexpected error: %s", i, test.name, err)
|
||||||
|
|
|
||||||
|
|
@ -220,6 +220,10 @@ compile_fuzzer github.com/ethereum/go-ethereum/tests/fuzzers/secp256k1 \
|
||||||
Fuzz fuzzSecp256k1\
|
Fuzz fuzzSecp256k1\
|
||||||
$repo/tests/fuzzers/secp256k1/secp_test.go
|
$repo/tests/fuzzers/secp256k1/secp_test.go
|
||||||
|
|
||||||
|
compile_fuzzer github.com/ethereum/go-ethereum/eth/protocols/eth \
|
||||||
|
FuzzEthProtocolHandlers fuzz_eth_protocol_handlers \
|
||||||
|
$repo/eth/protocols/eth/handler_test.go
|
||||||
|
|
||||||
|
|
||||||
#compile_fuzzer tests/fuzzers/vflux FuzzClientPool fuzzClientPool
|
#compile_fuzzer tests/fuzzers/vflux FuzzClientPool fuzzClientPool
|
||||||
#compile_fuzzer tests/fuzzers/difficulty Fuzz fuzzDifficulty
|
#compile_fuzzer tests/fuzzers/difficulty Fuzz fuzzDifficulty
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,18 @@ package apitypes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"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/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBytesPadding(t *testing.T) {
|
func TestBytesPadding(t *testing.T) {
|
||||||
|
|
@ -244,45 +250,42 @@ func TestConvertAddressDataToSlice(t *testing.T) {
|
||||||
func TestTypedDataArrayValidate(t *testing.T) {
|
func TestTypedDataArrayValidate(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
typedData := TypedData{
|
type testDataInput struct {
|
||||||
Types: Types{
|
Name string `json:"name"`
|
||||||
"BulkOrder": []Type{
|
Domain TypedDataDomain `json:"domain"`
|
||||||
// Should be able to accept fixed size arrays
|
PrimaryType string `json:"primaryType"`
|
||||||
{Name: "tree", Type: "OrderComponents[2][2]"},
|
Types Types `json:"types"`
|
||||||
},
|
Message TypedDataMessage `json:"data"`
|
||||||
"OrderComponents": []Type{
|
Digest string `json:"digest"`
|
||||||
{Name: "offerer", Type: "address"},
|
|
||||||
{Name: "amount", Type: "uint8"},
|
|
||||||
},
|
|
||||||
"EIP712Domain": []Type{
|
|
||||||
{Name: "name", Type: "string"},
|
|
||||||
{Name: "version", Type: "string"},
|
|
||||||
{Name: "chainId", Type: "uint8"},
|
|
||||||
{Name: "verifyingContract", Type: "address"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PrimaryType: "BulkOrder",
|
|
||||||
Domain: TypedDataDomain{
|
|
||||||
VerifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
|
|
||||||
},
|
|
||||||
Message: TypedDataMessage{},
|
|
||||||
}
|
}
|
||||||
|
fc, err := os.ReadFile("./testdata/typed-data.json")
|
||||||
|
require.NoError(t, err, "error reading test data file")
|
||||||
|
|
||||||
if err := typedData.validate(); err != nil {
|
var tests []testDataInput
|
||||||
t.Errorf("expected typed data to pass validation, got: %v", err)
|
err = json.Unmarshal(fc, &tests)
|
||||||
}
|
require.NoError(t, err, "error unmarshalling test data file contents")
|
||||||
|
|
||||||
// Should be able to accept dynamic arrays
|
for _, tc := range tests {
|
||||||
typedData.Types["BulkOrder"][0].Type = "OrderComponents[]"
|
t.Run(tc.Name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
if err := typedData.validate(); err != nil {
|
td := TypedData{
|
||||||
t.Errorf("expected typed data to pass validation, got: %v", err)
|
Types: tc.Types,
|
||||||
}
|
PrimaryType: tc.PrimaryType,
|
||||||
|
Domain: tc.Domain,
|
||||||
|
Message: tc.Message,
|
||||||
|
}
|
||||||
|
|
||||||
// Should be able to accept standard types
|
domainSeparator, tErr := td.HashStruct("EIP712Domain", td.Domain.Map())
|
||||||
typedData.Types["BulkOrder"][0].Type = "OrderComponents"
|
assert.NoError(t, tErr, "failed to hash domain separator: %v", tErr)
|
||||||
|
|
||||||
if err := typedData.validate(); err != nil {
|
messageHash, tErr := td.HashStruct(td.PrimaryType, td.Message)
|
||||||
t.Errorf("expected typed data to pass validation, got: %v", err)
|
assert.NoError(t, tErr, "failed to hash message: %v", tErr)
|
||||||
|
|
||||||
|
digest := crypto.Keccak256Hash([]byte(fmt.Sprintf("%s%s%s", "\x19\x01", string(domainSeparator), string(messageHash))))
|
||||||
|
assert.Equal(t, tc.Digest, digest.String(), "digest doesn't not match")
|
||||||
|
|
||||||
|
assert.NoError(t, td.validate(), "validation failed", tErr)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
6089
signer/core/apitypes/testdata/typed-data.json
vendored
Normal file
6089
signer/core/apitypes/testdata/typed-data.json
vendored
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -325,18 +325,17 @@ type Type struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isArray returns true if the type is a fixed or variable sized array.
|
||||||
|
// This method may return false positives, in case the Type is not a valid
|
||||||
|
// expression, e.g. "fooo[[[[".
|
||||||
func (t *Type) isArray() bool {
|
func (t *Type) isArray() bool {
|
||||||
return strings.HasSuffix(t.Type, "[]")
|
return strings.IndexByte(t.Type, '[') > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// typeName returns the canonical name of the type. If the type is 'Person[]', then
|
// typeName returns the canonical name of the type. If the type is 'Person[]' or 'Person[2]', then
|
||||||
// this method returns 'Person'
|
// this method returns 'Person'
|
||||||
func (t *Type) typeName() string {
|
func (t *Type) typeName() string {
|
||||||
if strings.Contains(t.Type, "[") {
|
return strings.Split(t.Type, "[")[0]
|
||||||
re := regexp.MustCompile(`\[\d*\]`)
|
|
||||||
return re.ReplaceAllString(t.Type, "")
|
|
||||||
}
|
|
||||||
return t.Type
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Types map[string][]Type
|
type Types map[string][]Type
|
||||||
|
|
@ -387,7 +386,7 @@ func (typedData *TypedData) HashStruct(primaryType string, data TypedDataMessage
|
||||||
|
|
||||||
// Dependencies returns an array of custom types ordered by their hierarchical reference tree
|
// Dependencies returns an array of custom types ordered by their hierarchical reference tree
|
||||||
func (typedData *TypedData) Dependencies(primaryType string, found []string) []string {
|
func (typedData *TypedData) Dependencies(primaryType string, found []string) []string {
|
||||||
primaryType = strings.TrimSuffix(primaryType, "[]")
|
primaryType = strings.Split(primaryType, "[")[0]
|
||||||
|
|
||||||
if slices.Contains(found, primaryType) {
|
if slices.Contains(found, primaryType) {
|
||||||
return found
|
return found
|
||||||
|
|
@ -465,34 +464,11 @@ func (typedData *TypedData) EncodeData(primaryType string, data map[string]inter
|
||||||
encType := field.Type
|
encType := field.Type
|
||||||
encValue := data[field.Name]
|
encValue := data[field.Name]
|
||||||
if encType[len(encType)-1:] == "]" {
|
if encType[len(encType)-1:] == "]" {
|
||||||
arrayValue, err := convertDataToSlice(encValue)
|
encodedData, err := typedData.encodeArrayValue(encValue, encType, depth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, dataMismatchError(encType, encValue)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
buffer.Write(encodedData)
|
||||||
arrayBuffer := bytes.Buffer{}
|
|
||||||
parsedType := strings.Split(encType, "[")[0]
|
|
||||||
for _, item := range arrayValue {
|
|
||||||
if typedData.Types[parsedType] != nil {
|
|
||||||
mapValue, ok := item.(map[string]interface{})
|
|
||||||
if !ok {
|
|
||||||
return nil, dataMismatchError(parsedType, item)
|
|
||||||
}
|
|
||||||
encodedData, err := typedData.EncodeData(parsedType, mapValue, depth+1)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
arrayBuffer.Write(crypto.Keccak256(encodedData))
|
|
||||||
} else {
|
|
||||||
bytesValue, err := typedData.EncodePrimitiveValue(parsedType, item, depth)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
arrayBuffer.Write(bytesValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.Write(crypto.Keccak256(arrayBuffer.Bytes()))
|
|
||||||
} else if typedData.Types[field.Type] != nil {
|
} else if typedData.Types[field.Type] != nil {
|
||||||
mapValue, ok := encValue.(map[string]interface{})
|
mapValue, ok := encValue.(map[string]interface{})
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
@ -514,6 +490,46 @@ func (typedData *TypedData) EncodeData(primaryType string, data map[string]inter
|
||||||
return buffer.Bytes(), nil
|
return buffer.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (typedData *TypedData) encodeArrayValue(encValue interface{}, encType string, depth int) (hexutil.Bytes, error) {
|
||||||
|
arrayValue, err := convertDataToSlice(encValue)
|
||||||
|
if err != nil {
|
||||||
|
return nil, dataMismatchError(encType, encValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
arrayBuffer := new(bytes.Buffer)
|
||||||
|
parsedType := strings.Split(encType, "[")[0]
|
||||||
|
for _, item := range arrayValue {
|
||||||
|
if reflect.TypeOf(item).Kind() == reflect.Slice ||
|
||||||
|
reflect.TypeOf(item).Kind() == reflect.Array {
|
||||||
|
encodedData, err := typedData.encodeArrayValue(item, parsedType, depth+1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
arrayBuffer.Write(encodedData)
|
||||||
|
} else {
|
||||||
|
if typedData.Types[parsedType] != nil {
|
||||||
|
mapValue, ok := item.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return nil, dataMismatchError(parsedType, item)
|
||||||
|
}
|
||||||
|
encodedData, err := typedData.EncodeData(parsedType, mapValue, depth+1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
digest := crypto.Keccak256(encodedData)
|
||||||
|
arrayBuffer.Write(digest)
|
||||||
|
} else {
|
||||||
|
bytesValue, err := typedData.EncodePrimitiveValue(parsedType, item, depth)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
arrayBuffer.Write(bytesValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return crypto.Keccak256(arrayBuffer.Bytes()), nil
|
||||||
|
}
|
||||||
|
|
||||||
// Attempt to parse bytes in different formats: byte array, hex string, hexutil.Bytes.
|
// Attempt to parse bytes in different formats: byte array, hex string, hexutil.Bytes.
|
||||||
func parseBytes(encType interface{}) ([]byte, bool) {
|
func parseBytes(encType interface{}) ([]byte, bool) {
|
||||||
// Handle array types.
|
// Handle array types.
|
||||||
|
|
@ -871,7 +887,8 @@ func init() {
|
||||||
|
|
||||||
// Checks if the primitive value is valid
|
// Checks if the primitive value is valid
|
||||||
func isPrimitiveTypeValid(primitiveType string) bool {
|
func isPrimitiveTypeValid(primitiveType string) bool {
|
||||||
_, ok := validPrimitiveTypes[primitiveType]
|
input := strings.Split(primitiveType, "[")[0]
|
||||||
|
_, ok := validPrimitiveTypes[input]
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,9 @@ func TestIsPrimitive(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
// Expected positives
|
// Expected positives
|
||||||
for i, tc := range []string{
|
for i, tc := range []string{
|
||||||
"int24", "int24[]", "uint88", "uint88[]", "uint", "uint[]", "int256", "int256[]",
|
"int24", "int24[]", "int[]", "int[2]", "uint88", "uint88[]", "uint", "uint[]", "uint[2]", "int256", "int256[]",
|
||||||
"uint96", "uint96[]", "int96", "int96[]", "bytes17[]", "bytes17",
|
"uint96", "uint96[]", "int96", "int96[]", "bytes17[]", "bytes17", "address[2]", "bool[4]", "string[5]", "bytes[2]",
|
||||||
|
"bytes32", "bytes32[]", "bytes32[4]",
|
||||||
} {
|
} {
|
||||||
if !isPrimitiveTypeValid(tc) {
|
if !isPrimitiveTypeValid(tc) {
|
||||||
t.Errorf("test %d: expected '%v' to be a valid primitive", i, tc)
|
t.Errorf("test %d: expected '%v' to be a valid primitive", i, tc)
|
||||||
|
|
@ -141,3 +142,94 @@ func TestBlobTxs(t *testing.T) {
|
||||||
}
|
}
|
||||||
t.Logf("tx %v", string(data))
|
t.Logf("tx %v", string(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestType_IsArray(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
// Expected positives
|
||||||
|
for i, tc := range []Type{
|
||||||
|
{
|
||||||
|
Name: "type1",
|
||||||
|
Type: "int24[]",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "type2",
|
||||||
|
Type: "int24[2]",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "type3",
|
||||||
|
Type: "int24[2][2][2]",
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
if !tc.isArray() {
|
||||||
|
t.Errorf("test %d: expected '%v' to be an array", i, tc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Expected negatives
|
||||||
|
for i, tc := range []Type{
|
||||||
|
{
|
||||||
|
Name: "type1",
|
||||||
|
Type: "int24",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "type2",
|
||||||
|
Type: "uint88",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "type3",
|
||||||
|
Type: "bytes32",
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
if tc.isArray() {
|
||||||
|
t.Errorf("test %d: expected '%v' to not be an array", i, tc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestType_TypeName(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
for i, tc := range []struct {
|
||||||
|
Input Type
|
||||||
|
Expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Input: Type{
|
||||||
|
Name: "type1",
|
||||||
|
Type: "int24[]",
|
||||||
|
},
|
||||||
|
Expected: "int24",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: Type{
|
||||||
|
Name: "type2",
|
||||||
|
Type: "int26[2][2][2]",
|
||||||
|
},
|
||||||
|
Expected: "int26",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: Type{
|
||||||
|
Name: "type3",
|
||||||
|
Type: "int24",
|
||||||
|
},
|
||||||
|
Expected: "int24",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: Type{
|
||||||
|
Name: "type4",
|
||||||
|
Type: "uint88",
|
||||||
|
},
|
||||||
|
Expected: "uint88",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Input: Type{
|
||||||
|
Name: "type5",
|
||||||
|
Type: "bytes32[2]",
|
||||||
|
},
|
||||||
|
Expected: "bytes32",
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
if tc.Input.typeName() != tc.Expected {
|
||||||
|
t.Errorf("test %d: expected typeName value of '%v' but got '%v'", i, tc.Expected, tc.Input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -196,7 +196,7 @@ func (t *StateTest) checkError(subtest StateSubtest, err error) error {
|
||||||
|
|
||||||
// Run executes a specific subtest and verifies the post-state and logs
|
// Run executes a specific subtest and verifies the post-state and logs
|
||||||
func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config, snapshotter bool, scheme string, postCheck func(err error, st *StateTestState)) (result error) {
|
func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config, snapshotter bool, scheme string, postCheck func(err error, st *StateTestState)) (result error) {
|
||||||
st, root, err := t.RunNoVerify(subtest, vmconfig, snapshotter, scheme)
|
st, root, _, err := t.RunNoVerify(subtest, vmconfig, snapshotter, scheme)
|
||||||
// Invoke the callback at the end of function for further analysis.
|
// Invoke the callback at the end of function for further analysis.
|
||||||
defer func() {
|
defer func() {
|
||||||
postCheck(result, &st)
|
postCheck(result, &st)
|
||||||
|
|
@ -228,10 +228,10 @@ func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config, snapshotter bo
|
||||||
|
|
||||||
// RunNoVerify runs a specific subtest and returns the statedb and post-state root.
|
// RunNoVerify runs a specific subtest and returns the statedb and post-state root.
|
||||||
// Remember to call state.Close after verifying the test result!
|
// Remember to call state.Close after verifying the test result!
|
||||||
func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapshotter bool, scheme string) (st StateTestState, root common.Hash, err error) {
|
func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapshotter bool, scheme string) (st StateTestState, root common.Hash, gasUsed uint64, err error) {
|
||||||
config, eips, err := GetChainConfig(subtest.Fork)
|
config, eips, err := GetChainConfig(subtest.Fork)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return st, common.Hash{}, UnsupportedForkError{subtest.Fork}
|
return st, common.Hash{}, 0, UnsupportedForkError{subtest.Fork}
|
||||||
}
|
}
|
||||||
vmconfig.ExtraEips = eips
|
vmconfig.ExtraEips = eips
|
||||||
|
|
||||||
|
|
@ -250,7 +250,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
|
||||||
post := t.json.Post[subtest.Fork][subtest.Index]
|
post := t.json.Post[subtest.Fork][subtest.Index]
|
||||||
msg, err := t.json.Tx.toMessage(post, baseFee)
|
msg, err := t.json.Tx.toMessage(post, baseFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return st, common.Hash{}, err
|
return st, common.Hash{}, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // Blob transactions may be present after the Cancun fork.
|
{ // Blob transactions may be present after the Cancun fork.
|
||||||
|
|
@ -260,7 +260,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
|
||||||
// Here, we just do this shortcut smaller fix, since state tests do not
|
// Here, we just do this shortcut smaller fix, since state tests do not
|
||||||
// utilize those codepaths
|
// utilize those codepaths
|
||||||
if len(msg.BlobHashes)*params.BlobTxBlobGasPerBlob > params.MaxBlobGasPerBlock {
|
if len(msg.BlobHashes)*params.BlobTxBlobGasPerBlob > params.MaxBlobGasPerBlock {
|
||||||
return st, common.Hash{}, errors.New("blob gas exceeds maximum")
|
return st, common.Hash{}, 0, errors.New("blob gas exceeds maximum")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -269,10 +269,10 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
|
||||||
var ttx types.Transaction
|
var ttx types.Transaction
|
||||||
err := ttx.UnmarshalBinary(post.TxBytes)
|
err := ttx.UnmarshalBinary(post.TxBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return st, common.Hash{}, err
|
return st, common.Hash{}, 0, err
|
||||||
}
|
}
|
||||||
if _, err := types.Sender(types.LatestSigner(config), &ttx); err != nil {
|
if _, err := types.Sender(types.LatestSigner(config), &ttx); err != nil {
|
||||||
return st, common.Hash{}, err
|
return st, common.Hash{}, 0, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -322,7 +322,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
|
||||||
receipt := &types.Receipt{GasUsed: vmRet.UsedGas}
|
receipt := &types.Receipt{GasUsed: vmRet.UsedGas}
|
||||||
tracer.OnTxEnd(receipt, nil)
|
tracer.OnTxEnd(receipt, nil)
|
||||||
}
|
}
|
||||||
return st, root, err
|
return st, root, vmRet.UsedGas, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *StateTest) gasLimit(subtest StateSubtest) uint64 {
|
func (t *StateTest) gasLimit(subtest StateSubtest) uint64 {
|
||||||
|
|
|
||||||
|
|
@ -156,10 +156,6 @@ func GetTreeKey(address []byte, treeIndex *uint256.Int, subIndex byte) []byte {
|
||||||
func GetTreeKeyWithEvaluatedAddress(evaluated *verkle.Point, treeIndex *uint256.Int, subIndex byte) []byte {
|
func GetTreeKeyWithEvaluatedAddress(evaluated *verkle.Point, treeIndex *uint256.Int, subIndex byte) []byte {
|
||||||
var poly [5]fr.Element
|
var poly [5]fr.Element
|
||||||
|
|
||||||
poly[0].SetZero()
|
|
||||||
poly[1].SetZero()
|
|
||||||
poly[2].SetZero()
|
|
||||||
|
|
||||||
// little-endian, 32-byte aligned treeIndex
|
// little-endian, 32-byte aligned treeIndex
|
||||||
var index [32]byte
|
var index [32]byte
|
||||||
for i := 0; i < len(treeIndex); i++ {
|
for i := 0; i < len(treeIndex); i++ {
|
||||||
|
|
@ -297,8 +293,6 @@ func evaluateAddressPoint(address []byte) *verkle.Point {
|
||||||
}
|
}
|
||||||
var poly [3]fr.Element
|
var poly [3]fr.Element
|
||||||
|
|
||||||
poly[0].SetZero()
|
|
||||||
|
|
||||||
// 32-byte address, interpreted as two little endian
|
// 32-byte address, interpreted as two little endian
|
||||||
// 16-byte numbers.
|
// 16-byte numbers.
|
||||||
verkle.FromLEBytes(&poly[1], address[:16])
|
verkle.FromLEBytes(&poly[1], address[:16])
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NodeReader wraps the Node method of a backing trie reader.
|
// NodeReader wraps the Node method of a backing trie reader.
|
||||||
|
|
@ -37,3 +38,31 @@ type NodeDatabase interface {
|
||||||
// An error will be returned if the specified state is not available.
|
// An error will be returned if the specified state is not available.
|
||||||
NodeReader(stateRoot common.Hash) (NodeReader, error)
|
NodeReader(stateRoot common.Hash) (NodeReader, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StateReader wraps the Account and Storage method of a backing state reader.
|
||||||
|
type StateReader interface {
|
||||||
|
// Account directly retrieves the account associated with a particular hash in
|
||||||
|
// the slim data format. An error will be returned if the read operation exits
|
||||||
|
// abnormally. Specifically, if the layer is already stale.
|
||||||
|
//
|
||||||
|
// Note:
|
||||||
|
// - the returned account object is safe to modify
|
||||||
|
// - no error will be returned if the requested account is not found in database
|
||||||
|
Account(hash common.Hash) (*types.SlimAccount, error)
|
||||||
|
|
||||||
|
// Storage directly retrieves the storage data associated with a particular hash,
|
||||||
|
// within a particular account. An error will be returned if the read operation
|
||||||
|
// exits abnormally.
|
||||||
|
//
|
||||||
|
// Note:
|
||||||
|
// - the returned storage data is not a copy, please don't modify it
|
||||||
|
// - no error will be returned if the requested slot is not found in database
|
||||||
|
Storage(accountHash, storageHash common.Hash) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StateDatabase wraps the methods of a backing state store.
|
||||||
|
type StateDatabase interface {
|
||||||
|
// StateReader returns a state reader associated with the specific state.
|
||||||
|
// An error will be returned if the specified state is not available.
|
||||||
|
StateReader(stateRoot common.Hash) (StateReader, error)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue