mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 02:12:23 +00:00
core, eth, internal: introduce state override reader
This commit is contained in:
parent
623b17ba20
commit
3232927325
14 changed files with 748 additions and 162 deletions
|
|
@ -356,6 +356,14 @@ func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) {
|
||||||
return state.New(root, bc.statedb)
|
return state.New(root, bc.statedb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StateWithOverrides returns a new mutable state with provided state overrides.
|
||||||
|
func (bc *BlockChain) StateWithOverrides(root common.Hash, overrides *map[common.Address]state.OverrideAccount) (*state.StateDB, error) {
|
||||||
|
if overrides == nil {
|
||||||
|
return bc.StateAt(root)
|
||||||
|
}
|
||||||
|
return state.New(root, state.NewOverrideDatabase(bc.stateDb, *overrides))
|
||||||
|
}
|
||||||
|
|
||||||
// Config retrieves the chain's fork configuration.
|
// Config retrieves the chain's fork configuration.
|
||||||
func (bc *BlockChain) Config() *params.ChainConfig { return bc.chainConfig }
|
func (bc *BlockChain) Config() *params.ChainConfig { return bc.chainConfig }
|
||||||
|
|
||||||
|
|
|
||||||
273
core/state/state_override.go
Normal file
273
core/state/state_override.go
Normal file
|
|
@ -0,0 +1,273 @@
|
||||||
|
// Copyright 2024 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 state
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"maps"
|
||||||
|
"slices"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate go run github.com/fjl/gencodec -type OverrideAccount -field-override overrideMarshaling -out state_override_json.go
|
||||||
|
|
||||||
|
// OverrideAccount specifies the fields of an account that should be overridden
|
||||||
|
// during the execution of a message call.
|
||||||
|
//
|
||||||
|
// Note: The 'state' and 'stateDiff' fields are mutually exclusive and cannot
|
||||||
|
// be specified simultaneously. If 'state' is set, the message execution will
|
||||||
|
// only use the data provided in the given state. Otherwise, if 'stateDiff'
|
||||||
|
// is set, all the differences will be applied first, and then the call message
|
||||||
|
// will be executed.
|
||||||
|
type OverrideAccount struct {
|
||||||
|
Nonce *uint64 `json:"nonce"`
|
||||||
|
Code *[]byte `json:"code"`
|
||||||
|
Balance *uint256.Int `json:"balance"`
|
||||||
|
State map[common.Hash]common.Hash `json:"state"`
|
||||||
|
StateDiff map[common.Hash]common.Hash `json:"stateDiff"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// nolint
|
||||||
|
type overrideMarshaling struct {
|
||||||
|
Nonce *hexutil.Uint64
|
||||||
|
Code *hexutil.Bytes
|
||||||
|
Balance *hexutil.U256
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy returns a deep-copied override object.
|
||||||
|
func (o OverrideAccount) copy() OverrideAccount {
|
||||||
|
var obj OverrideAccount
|
||||||
|
if o.Nonce != nil {
|
||||||
|
nonce := *o.Nonce
|
||||||
|
obj.Nonce = &nonce
|
||||||
|
}
|
||||||
|
if o.Code != nil {
|
||||||
|
code := slices.Clone(*o.Code)
|
||||||
|
obj.Code = &code
|
||||||
|
}
|
||||||
|
if o.Balance != nil {
|
||||||
|
obj.Balance = new(uint256.Int).Set(o.Balance)
|
||||||
|
}
|
||||||
|
if o.State != nil {
|
||||||
|
obj.State = maps.Clone(o.State)
|
||||||
|
}
|
||||||
|
if o.StateDiff != nil {
|
||||||
|
obj.StateDiff = maps.Clone(o.StateDiff)
|
||||||
|
}
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
// overrideReader implements the Reader interface, serving as a wrapper around a
|
||||||
|
// provided state reader, but incorporating with overridden states.
|
||||||
|
type overrideReader struct {
|
||||||
|
reader Reader
|
||||||
|
overrides map[common.Address]OverrideAccount
|
||||||
|
}
|
||||||
|
|
||||||
|
// newOverrideReader creates a reader with customized state overrides.
|
||||||
|
func newOverrideReader(overrides map[common.Address]OverrideAccount, reader Reader) *overrideReader {
|
||||||
|
return &overrideReader{
|
||||||
|
reader: reader,
|
||||||
|
overrides: overrides,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Account implementing Reader interface, retrieving the account associated with
|
||||||
|
// a particular address.
|
||||||
|
//
|
||||||
|
// - Returns a nil account if it does not exist
|
||||||
|
// - Returns an error only if an unexpected issue occurs
|
||||||
|
// - The returned account is safe to modify after the call
|
||||||
|
func (r *overrideReader) Account(addr common.Address) (*types.StateAccount, error) {
|
||||||
|
account, err := r.reader.Account(addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// apply the overrides if it's specified
|
||||||
|
override, ok := r.overrides[addr]
|
||||||
|
if ok {
|
||||||
|
if account == nil {
|
||||||
|
account = types.NewEmptyStateAccount()
|
||||||
|
}
|
||||||
|
if override.Nonce != nil {
|
||||||
|
account.Nonce = *override.Nonce
|
||||||
|
}
|
||||||
|
if override.Balance != nil {
|
||||||
|
account.Balance = new(uint256.Int).Set(override.Balance)
|
||||||
|
}
|
||||||
|
if override.Code != nil {
|
||||||
|
account.CodeHash = crypto.Keccak256(*override.Code)
|
||||||
|
}
|
||||||
|
// TODO what about the storage root then, should we compute the
|
||||||
|
// storage root of overridden state here?
|
||||||
|
}
|
||||||
|
return account, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Storage implementing Reader interface, retrieving the storage slot associated
|
||||||
|
// with a particular account address and slot key.
|
||||||
|
//
|
||||||
|
// - Returns an empty slot if it does not exist
|
||||||
|
// - Returns an error only if an unexpected issue occurs
|
||||||
|
// - The returned storage slot is safe to modify after the call
|
||||||
|
func (r *overrideReader) Storage(addr common.Address, slot common.Hash) (common.Hash, error) {
|
||||||
|
override, ok := r.overrides[addr]
|
||||||
|
if ok {
|
||||||
|
if override.State != nil {
|
||||||
|
return override.State[slot], nil
|
||||||
|
}
|
||||||
|
if override.StateDiff != nil {
|
||||||
|
if val, ok := override.StateDiff[slot]; ok {
|
||||||
|
return val, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r.reader.Storage(addr, slot)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stats returns the statistics of the reader, specifically detailing the time
|
||||||
|
// spent on account reading and storage reading.
|
||||||
|
func (r *overrideReader) Stats() (time.Duration, time.Duration) { return 0, 0 }
|
||||||
|
|
||||||
|
// Copy implementing Reader interface, returning a deep-copied state reader.
|
||||||
|
func (r *overrideReader) Copy() Reader {
|
||||||
|
overrides := make(map[common.Address]OverrideAccount)
|
||||||
|
for addr, override := range r.overrides {
|
||||||
|
overrides[addr] = override.copy()
|
||||||
|
}
|
||||||
|
return &overrideReader{
|
||||||
|
overrides: overrides,
|
||||||
|
reader: r.reader.Copy(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OverrideDatabase implements the Database interface, serving as a wrapper
|
||||||
|
// around a standard state database, but incorporating overridden states.
|
||||||
|
type OverrideDatabase struct {
|
||||||
|
Database
|
||||||
|
overrides map[common.Address]OverrideAccount
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOverrideDatabase creates a state database with provided state overrides.
|
||||||
|
func NewOverrideDatabase(db Database, overrides map[common.Address]OverrideAccount) *OverrideDatabase {
|
||||||
|
// Allocate an empty override set just in case the provided one
|
||||||
|
// is nil. Don't panic for lazy users.
|
||||||
|
if overrides == nil {
|
||||||
|
overrides = make(map[common.Address]OverrideAccount)
|
||||||
|
}
|
||||||
|
return &OverrideDatabase{
|
||||||
|
Database: db,
|
||||||
|
overrides: overrides,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reader returns a state reader associated with the specified state root.
|
||||||
|
func (db *OverrideDatabase) Reader(root common.Hash) (Reader, error) {
|
||||||
|
reader, err := db.Database.Reader(root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newOverrideReader(db.overrides, reader), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContractCode retrieves a particular contract's code.
|
||||||
|
func (db *OverrideDatabase) ContractCode(addr common.Address, codeHash common.Hash) ([]byte, error) {
|
||||||
|
override, ok := db.overrides[addr]
|
||||||
|
if ok && override.Code != nil {
|
||||||
|
return *override.Code, nil
|
||||||
|
}
|
||||||
|
return db.Database.ContractCode(addr, codeHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContractCodeSize retrieves a particular contracts code's size.
|
||||||
|
func (db *OverrideDatabase) ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) {
|
||||||
|
override, ok := db.overrides[addr]
|
||||||
|
if ok && override.Code != nil {
|
||||||
|
return len(*override.Code), nil
|
||||||
|
}
|
||||||
|
return db.Database.ContractCodeSize(addr, codeHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The stateWrapReader wraps a live state database as the state source.
|
||||||
|
type stateWrapReader struct {
|
||||||
|
state *StateDB
|
||||||
|
}
|
||||||
|
|
||||||
|
// Account implementing Reader interface, retrieving the account associated with
|
||||||
|
// a particular address.
|
||||||
|
//
|
||||||
|
// - Returns a nil account if it does not exist
|
||||||
|
// - Returns an error only if an unexpected issue occurs
|
||||||
|
// - The returned account is safe to modify after the call
|
||||||
|
func (r *stateWrapReader) Account(addr common.Address) (*types.StateAccount, error) {
|
||||||
|
obj := r.state.getStateObject(addr)
|
||||||
|
if obj == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return obj.data.Copy(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Storage implementing Reader interface, retrieving the storage slot associated
|
||||||
|
// with a particular account address and slot key.
|
||||||
|
//
|
||||||
|
// - Returns an empty slot if it does not exist
|
||||||
|
// - Returns an error only if an unexpected issue occurs
|
||||||
|
// - The returned storage slot is safe to modify after the call
|
||||||
|
func (r *stateWrapReader) Storage(addr common.Address, slot common.Hash) (common.Hash, error) {
|
||||||
|
return r.state.GetState(addr, slot), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stats returns the statistics of the reader, specifically detailing the time
|
||||||
|
// spent on account reading and storage reading.
|
||||||
|
func (r *stateWrapReader) Stats() (time.Duration, time.Duration) { return 0, 0 }
|
||||||
|
|
||||||
|
// Copy implementing Reader interface, returning a deep-copied state reader.
|
||||||
|
func (r *stateWrapReader) Copy() Reader {
|
||||||
|
return &stateWrapReader{state: r.state.Copy()}
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateWrap is an internal struct wrapping a live state instance as the state
|
||||||
|
// data source. This can be useful in scenarios where we need to create the
|
||||||
|
// snapshot of the current state and apply some additional overrides on top
|
||||||
|
// (e.g. state override in RPC call serving).
|
||||||
|
type stateWrap struct {
|
||||||
|
Database
|
||||||
|
state *StateDB
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reader returns a state reader associated with the specified state root.
|
||||||
|
func (db *stateWrap) Reader(root common.Hash) (Reader, error) {
|
||||||
|
if root != db.state.originalRoot {
|
||||||
|
return nil, errors.New("state root is not matched")
|
||||||
|
}
|
||||||
|
return &stateWrapReader{state: db.state}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OverrideState applies the state overrides into the provided live state database.
|
||||||
|
func OverrideState(state *StateDB, overrides map[common.Address]OverrideAccount) (*StateDB, error) {
|
||||||
|
db := NewOverrideDatabase(&stateWrap{
|
||||||
|
Database: state.db,
|
||||||
|
state: state.Copy(),
|
||||||
|
}, overrides)
|
||||||
|
return New(state.originalRoot, db)
|
||||||
|
}
|
||||||
62
core/state/state_override_json.go
Normal file
62
core/state/state_override_json.go
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
|
||||||
|
|
||||||
|
package state
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = (*overrideMarshaling)(nil)
|
||||||
|
|
||||||
|
// MarshalJSON marshals as JSON.
|
||||||
|
func (o OverrideAccount) MarshalJSON() ([]byte, error) {
|
||||||
|
type OverrideAccount struct {
|
||||||
|
Nonce *hexutil.Uint64 `json:"nonce"`
|
||||||
|
Code *hexutil.Bytes `json:"code"`
|
||||||
|
Balance *hexutil.U256 `json:"balance"`
|
||||||
|
State map[common.Hash]common.Hash `json:"state"`
|
||||||
|
StateDiff map[common.Hash]common.Hash `json:"stateDiff"`
|
||||||
|
}
|
||||||
|
var enc OverrideAccount
|
||||||
|
enc.Nonce = (*hexutil.Uint64)(o.Nonce)
|
||||||
|
enc.Code = (*hexutil.Bytes)(o.Code)
|
||||||
|
enc.Balance = (*hexutil.U256)(o.Balance)
|
||||||
|
enc.State = o.State
|
||||||
|
enc.StateDiff = o.StateDiff
|
||||||
|
return json.Marshal(&enc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON unmarshals from JSON.
|
||||||
|
func (o *OverrideAccount) UnmarshalJSON(input []byte) error {
|
||||||
|
type OverrideAccount struct {
|
||||||
|
Nonce *hexutil.Uint64 `json:"nonce"`
|
||||||
|
Code *hexutil.Bytes `json:"code"`
|
||||||
|
Balance *hexutil.U256 `json:"balance"`
|
||||||
|
State map[common.Hash]common.Hash `json:"state"`
|
||||||
|
StateDiff map[common.Hash]common.Hash `json:"stateDiff"`
|
||||||
|
}
|
||||||
|
var dec OverrideAccount
|
||||||
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if dec.Nonce != nil {
|
||||||
|
o.Nonce = (*uint64)(dec.Nonce)
|
||||||
|
}
|
||||||
|
if dec.Code != nil {
|
||||||
|
o.Code = (*[]byte)(dec.Code)
|
||||||
|
}
|
||||||
|
if dec.Balance != nil {
|
||||||
|
o.Balance = (*uint256.Int)(dec.Balance)
|
||||||
|
}
|
||||||
|
if dec.State != nil {
|
||||||
|
o.State = dec.State
|
||||||
|
}
|
||||||
|
if dec.StateDiff != nil {
|
||||||
|
o.StateDiff = dec.StateDiff
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
287
core/state/state_override_test.go
Normal file
287
core/state/state_override_test.go
Normal file
|
|
@ -0,0 +1,287 @@
|
||||||
|
// Copyright 2024 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 state
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initTestState() (common.Hash, *CachingDB) {
|
||||||
|
db := NewDatabaseForTesting(rawdb.NewMemoryDatabase())
|
||||||
|
state, _ := New(types.EmptyRootHash, db)
|
||||||
|
state.SetNonce(testAllocAddr, 1)
|
||||||
|
state.SetBalance(testAllocAddr, uint256.NewInt(100), tracing.BalanceChangeUnspecified)
|
||||||
|
state.SetCode(testAllocAddr, []byte{0x1})
|
||||||
|
state.SetState(testAllocAddr, testAllocSlotKey, common.Hash{0x1})
|
||||||
|
root, err := state.Commit(0, false)
|
||||||
|
if err != nil {
|
||||||
|
panic("failed to commit state")
|
||||||
|
}
|
||||||
|
return root, db
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
testAllocAddr = common.HexToAddress("0xdeadbeef")
|
||||||
|
testAllocAddr2 = common.HexToAddress("0xbabecafe")
|
||||||
|
testAllocSlotKey = common.HexToHash("0xdeadbeef")
|
||||||
|
testAllocSlotKey2 = common.HexToHash("0xbabecafe")
|
||||||
|
)
|
||||||
|
|
||||||
|
func overrideNonce(val uint64) *uint64 {
|
||||||
|
return &val
|
||||||
|
}
|
||||||
|
|
||||||
|
func overrideCode(code []byte) *[]byte {
|
||||||
|
return &code
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStateOverride(t *testing.T) {
|
||||||
|
var cases = []struct {
|
||||||
|
overrides map[common.Address]OverrideAccount
|
||||||
|
expectAccounts map[common.Address]types.StateAccount
|
||||||
|
expectStorages map[common.Address]map[common.Hash]common.Hash
|
||||||
|
expectCodes map[common.Address][]byte
|
||||||
|
}{
|
||||||
|
// override is nil, it should be allowed
|
||||||
|
{
|
||||||
|
nil,
|
||||||
|
map[common.Address]types.StateAccount{
|
||||||
|
testAllocAddr: {
|
||||||
|
Nonce: 1,
|
||||||
|
Balance: uint256.NewInt(100),
|
||||||
|
CodeHash: crypto.Keccak256([]byte{0x1}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
map[common.Address]map[common.Hash]common.Hash{
|
||||||
|
testAllocAddr: {testAllocSlotKey: {0x1}},
|
||||||
|
},
|
||||||
|
map[common.Address][]byte{
|
||||||
|
testAllocAddr: {0x1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// empty override
|
||||||
|
{
|
||||||
|
map[common.Address]OverrideAccount{},
|
||||||
|
map[common.Address]types.StateAccount{
|
||||||
|
testAllocAddr: {
|
||||||
|
Nonce: 1,
|
||||||
|
Balance: uint256.NewInt(100),
|
||||||
|
CodeHash: crypto.Keccak256([]byte{0x1}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
map[common.Address]map[common.Hash]common.Hash{
|
||||||
|
testAllocAddr: {testAllocSlotKey: {0x1}},
|
||||||
|
},
|
||||||
|
map[common.Address][]byte{
|
||||||
|
testAllocAddr: {0x1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// empty override, access the non-existent states
|
||||||
|
{
|
||||||
|
map[common.Address]OverrideAccount{},
|
||||||
|
map[common.Address]types.StateAccount{
|
||||||
|
testAllocAddr2: {
|
||||||
|
Nonce: 0,
|
||||||
|
Balance: common.U2560,
|
||||||
|
CodeHash: common.Hash{}.Bytes(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
map[common.Address]map[common.Hash]common.Hash{
|
||||||
|
testAllocAddr2: {testAllocSlotKey: {}},
|
||||||
|
},
|
||||||
|
map[common.Address][]byte{
|
||||||
|
testAllocAddr2: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// override account metadata
|
||||||
|
{
|
||||||
|
map[common.Address]OverrideAccount{
|
||||||
|
testAllocAddr: {
|
||||||
|
Nonce: overrideNonce(50),
|
||||||
|
Code: overrideCode([]byte{0x2}),
|
||||||
|
Balance: uint256.NewInt(200),
|
||||||
|
},
|
||||||
|
testAllocAddr2: {
|
||||||
|
Nonce: overrideNonce(50),
|
||||||
|
Code: overrideCode([]byte{0x2}),
|
||||||
|
Balance: uint256.NewInt(200),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
map[common.Address]types.StateAccount{
|
||||||
|
testAllocAddr: {
|
||||||
|
Nonce: 50,
|
||||||
|
Balance: uint256.NewInt(200),
|
||||||
|
CodeHash: crypto.Keccak256([]byte{0x2}),
|
||||||
|
},
|
||||||
|
testAllocAddr2: {
|
||||||
|
Nonce: 50,
|
||||||
|
Balance: uint256.NewInt(200),
|
||||||
|
CodeHash: crypto.Keccak256([]byte{0x2}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
map[common.Address]map[common.Hash]common.Hash{
|
||||||
|
testAllocAddr: {testAllocSlotKey: {0x1}},
|
||||||
|
},
|
||||||
|
map[common.Address][]byte{
|
||||||
|
testAllocAddr: {0x2},
|
||||||
|
testAllocAddr2: {0x2},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// override storage by diff
|
||||||
|
{
|
||||||
|
map[common.Address]OverrideAccount{
|
||||||
|
testAllocAddr: {
|
||||||
|
StateDiff: map[common.Hash]common.Hash{
|
||||||
|
testAllocSlotKey: {0x2},
|
||||||
|
testAllocSlotKey2: {0x2},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
map[common.Address]types.StateAccount{
|
||||||
|
testAllocAddr: {
|
||||||
|
Nonce: 1,
|
||||||
|
Balance: uint256.NewInt(100),
|
||||||
|
CodeHash: crypto.Keccak256([]byte{0x1}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
map[common.Address]map[common.Hash]common.Hash{
|
||||||
|
testAllocAddr: {
|
||||||
|
testAllocSlotKey: {0x2},
|
||||||
|
testAllocSlotKey2: {0x2},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
map[common.Address][]byte{
|
||||||
|
testAllocAddr: {0x1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// override storage by replacing entire storage
|
||||||
|
{
|
||||||
|
map[common.Address]OverrideAccount{
|
||||||
|
testAllocAddr: {
|
||||||
|
State: map[common.Hash]common.Hash{
|
||||||
|
testAllocSlotKey2: {0x2},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
map[common.Address]types.StateAccount{
|
||||||
|
testAllocAddr: {
|
||||||
|
Nonce: 1,
|
||||||
|
Balance: uint256.NewInt(100),
|
||||||
|
CodeHash: crypto.Keccak256([]byte{0x1}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
map[common.Address]map[common.Hash]common.Hash{
|
||||||
|
testAllocAddr: {
|
||||||
|
testAllocSlotKey: {},
|
||||||
|
testAllocSlotKey2: {0x2},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
map[common.Address][]byte{
|
||||||
|
testAllocAddr: {0x1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
root, db := initTestState()
|
||||||
|
stateDb, err := New(root, NewOverrideDatabase(db, c.overrides))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to initialize state, %v", err)
|
||||||
|
}
|
||||||
|
for addr, expect := range c.expectAccounts {
|
||||||
|
if got := stateDb.GetBalance(addr); got.Cmp(expect.Balance) != 0 {
|
||||||
|
t.Fatalf("Balance is not matched, got %v, want: %v", got, expect.Balance)
|
||||||
|
}
|
||||||
|
if got := stateDb.GetNonce(addr); got != expect.Nonce {
|
||||||
|
t.Fatalf("Nonce is not matched, got %v, want: %v", got, expect.Nonce)
|
||||||
|
}
|
||||||
|
if got := stateDb.GetCodeHash(addr); !bytes.Equal(got.Bytes(), expect.CodeHash) {
|
||||||
|
t.Fatalf("CodeHash is not matched, got %v, want: %v", got.Bytes(), expect.CodeHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for addr, slots := range c.expectStorages {
|
||||||
|
for key, val := range slots {
|
||||||
|
got := stateDb.GetState(addr, key)
|
||||||
|
if got != val {
|
||||||
|
t.Fatalf("Storage slot is not matched, got %v, want: %v", got, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for addr, code := range c.expectCodes {
|
||||||
|
if got := stateDb.GetCode(addr); !bytes.Equal(got, code) {
|
||||||
|
t.Fatalf("Code is not matched, got %v, want: %v", got, code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRecursiveOverride(t *testing.T) {
|
||||||
|
root, db := initTestState()
|
||||||
|
|
||||||
|
overrideA := map[common.Address]OverrideAccount{
|
||||||
|
testAllocAddr: {Nonce: overrideNonce(2)},
|
||||||
|
}
|
||||||
|
overrideB := map[common.Address]OverrideAccount{
|
||||||
|
testAllocAddr: {Nonce: overrideNonce(3)},
|
||||||
|
}
|
||||||
|
overrideC := map[common.Address]OverrideAccount{
|
||||||
|
testAllocAddr: {
|
||||||
|
Nonce: overrideNonce(0),
|
||||||
|
State: map[common.Hash]common.Hash{
|
||||||
|
testAllocSlotKey: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
odbA := NewOverrideDatabase(db, overrideA)
|
||||||
|
stateDb, err := New(root, odbA)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to initialize state, %v", err)
|
||||||
|
}
|
||||||
|
nonce := stateDb.GetNonce(testAllocAddr)
|
||||||
|
if nonce != 2 {
|
||||||
|
t.Fatalf("Unexpected nonce, want: %d, got: %d", 2, nonce)
|
||||||
|
}
|
||||||
|
// recursively override
|
||||||
|
stateDb2, err := OverrideState(stateDb, overrideB)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to initialize state, %v", err)
|
||||||
|
}
|
||||||
|
nonce = stateDb2.GetNonce(testAllocAddr)
|
||||||
|
if nonce != 3 {
|
||||||
|
t.Fatalf("Unexpected nonce, want: %d, got: %d", 3, nonce)
|
||||||
|
}
|
||||||
|
// recursively override again
|
||||||
|
stateDb3, err := OverrideState(stateDb2, overrideC)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to initialize state, %v", err)
|
||||||
|
}
|
||||||
|
nonce = stateDb3.GetNonce(testAllocAddr)
|
||||||
|
if nonce != 0 {
|
||||||
|
t.Fatalf("Unexpected nonce, want: %d, got: %d", 0, nonce)
|
||||||
|
}
|
||||||
|
val := stateDb3.GetState(testAllocAddr, testAllocSlotKey)
|
||||||
|
if val != (common.Hash{}) {
|
||||||
|
t.Fatalf("Unexpected storage slot, want: %v, got: %v", common.Hash{}, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -330,7 +330,6 @@ func (s *StateDB) GetNonce(addr common.Address) uint64 {
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
return stateObject.Nonce()
|
return stateObject.Nonce()
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -186,14 +186,21 @@ func (b *EthAPIBackend) Pending() (*types.Block, types.Receipts, *state.StateDB)
|
||||||
return b.eth.miner.Pending()
|
return b.eth.miner.Pending()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) {
|
func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber, overrides *map[common.Address]state.OverrideAccount) (*state.StateDB, *types.Header, error) {
|
||||||
// Pending state is only known by the miner
|
// Pending state is only known by the miner
|
||||||
if number == rpc.PendingBlockNumber {
|
if number == rpc.PendingBlockNumber {
|
||||||
block, _, state := b.eth.miner.Pending()
|
block, _, stateDb := b.eth.miner.Pending()
|
||||||
if block == nil || state == nil {
|
if block == nil || stateDb == nil {
|
||||||
return nil, nil, errors.New("pending state is not available")
|
return nil, nil, errors.New("pending state is not available")
|
||||||
}
|
}
|
||||||
return state, block.Header(), nil
|
if overrides == nil {
|
||||||
|
return stateDb, block.Header(), nil
|
||||||
|
}
|
||||||
|
stateDb, err := state.OverrideState(stateDb, *overrides)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return stateDb, block.Header(), nil
|
||||||
}
|
}
|
||||||
// Otherwise resolve the block number and return its state
|
// Otherwise resolve the block number and return its state
|
||||||
header, err := b.HeaderByNumber(ctx, number)
|
header, err := b.HeaderByNumber(ctx, number)
|
||||||
|
|
@ -203,16 +210,16 @@ func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.B
|
||||||
if header == nil {
|
if header == nil {
|
||||||
return nil, nil, errors.New("header not found")
|
return nil, nil, errors.New("header not found")
|
||||||
}
|
}
|
||||||
stateDb, err := b.eth.BlockChain().StateAt(header.Root)
|
stateDb, err := b.eth.BlockChain().StateWithOverrides(header.Root, overrides)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
return stateDb, header, nil
|
return stateDb, header, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) {
|
func (b *EthAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, overrides *map[common.Address]state.OverrideAccount) (*state.StateDB, *types.Header, error) {
|
||||||
if blockNr, ok := blockNrOrHash.Number(); ok {
|
if blockNr, ok := blockNrOrHash.Number(); ok {
|
||||||
return b.StateAndHeaderByNumber(ctx, blockNr)
|
return b.StateAndHeaderByNumber(ctx, blockNr, overrides)
|
||||||
}
|
}
|
||||||
if hash, ok := blockNrOrHash.Hash(); ok {
|
if hash, ok := blockNrOrHash.Hash(); ok {
|
||||||
header, err := b.HeaderByHash(ctx, hash)
|
header, err := b.HeaderByHash(ctx, hash)
|
||||||
|
|
@ -225,7 +232,7 @@ func (b *EthAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockN
|
||||||
if blockNrOrHash.RequireCanonical && b.eth.blockchain.GetCanonicalHash(header.Number.Uint64()) != hash {
|
if blockNrOrHash.RequireCanonical && b.eth.blockchain.GetCanonicalHash(header.Number.Uint64()) != hash {
|
||||||
return nil, nil, errors.New("hash is not currently canonical")
|
return nil, nil, errors.New("hash is not currently canonical")
|
||||||
}
|
}
|
||||||
stateDb, err := b.eth.BlockChain().StateAt(header.Root)
|
stateDb, err := b.eth.BlockChain().StateWithOverrides(header.Root, overrides)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1153,7 +1153,7 @@ func TestWithdrawals(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 11: verify withdrawals were processed.
|
// 11: verify withdrawals were processed.
|
||||||
db, _, err := ethservice.APIBackend.StateAndHeaderByNumber(context.Background(), rpc.BlockNumber(execData.ExecutionPayload.Number))
|
db, _, err := ethservice.APIBackend.StateAndHeaderByNumber(context.Background(), rpc.BlockNumber(execData.ExecutionPayload.Number), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to load db: %v", err)
|
t.Fatalf("unable to load db: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1687,7 +1687,7 @@ func TestParentBeaconBlockRoot(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 11: verify beacon root was processed.
|
// 11: verify beacon root was processed.
|
||||||
db, _, err := ethservice.APIBackend.StateAndHeaderByNumber(context.Background(), rpc.BlockNumber(execData.ExecutionPayload.Number))
|
db, _, err := ethservice.APIBackend.StateAndHeaderByNumber(context.Background(), rpc.BlockNumber(execData.ExecutionPayload.Number), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to load db: %v", err)
|
t.Fatalf("unable to load db: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ type TraceConfig struct {
|
||||||
// field to override the state for tracing.
|
// field to override the state for tracing.
|
||||||
type TraceCallConfig struct {
|
type TraceCallConfig struct {
|
||||||
TraceConfig
|
TraceConfig
|
||||||
StateOverrides *ethapi.StateOverride
|
StateOverrides map[common.Address]state.OverrideAccount
|
||||||
BlockOverrides *ethapi.BlockOverrides
|
BlockOverrides *ethapi.BlockOverrides
|
||||||
TxIndex *hexutil.Uint
|
TxIndex *hexutil.Uint
|
||||||
}
|
}
|
||||||
|
|
@ -952,12 +952,15 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
|
||||||
}
|
}
|
||||||
defer release()
|
defer release()
|
||||||
|
|
||||||
vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
|
||||||
// Apply the customization rules if required.
|
// Apply the customization rules if required.
|
||||||
|
vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
||||||
if config != nil {
|
if config != nil {
|
||||||
if err := config.StateOverrides.Apply(statedb); err != nil {
|
if len(config.StateOverrides) != 0 {
|
||||||
|
statedb, err = state.OverrideState(statedb, config.StateOverrides)
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
config.BlockOverrides.Apply(&vmctx)
|
config.BlockOverrides.Apply(&vmctx)
|
||||||
}
|
}
|
||||||
// Execute the trace
|
// Execute the trace
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -610,8 +611,8 @@ func TestTracingWithOverrides(t *testing.T) {
|
||||||
Value: (*hexutil.Big)(big.NewInt(1000)),
|
Value: (*hexutil.Big)(big.NewInt(1000)),
|
||||||
},
|
},
|
||||||
config: &TraceCallConfig{
|
config: &TraceCallConfig{
|
||||||
StateOverrides: ðapi.StateOverride{
|
StateOverrides: map[common.Address]state.OverrideAccount{
|
||||||
randomAccounts[0].addr: ethapi.OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))},
|
randomAccounts[0].addr: {Balance: uint256.MustFromBig(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: `{"gas":21000,"failed":false,"returnValue":""}`,
|
want: `{"gas":21000,"failed":false,"returnValue":""}`,
|
||||||
|
|
@ -652,9 +653,9 @@ func TestTracingWithOverrides(t *testing.T) {
|
||||||
},
|
},
|
||||||
config: &TraceCallConfig{
|
config: &TraceCallConfig{
|
||||||
//Tracer: &tracer,
|
//Tracer: &tracer,
|
||||||
StateOverrides: ðapi.StateOverride{
|
StateOverrides: map[common.Address]state.OverrideAccount{
|
||||||
randomAccounts[2].addr: ethapi.OverrideAccount{
|
randomAccounts[2].addr: {
|
||||||
Code: newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033")),
|
Code: newRawBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033")),
|
||||||
StateDiff: newStates([]common.Hash{{}}, []common.Hash{common.BigToHash(big.NewInt(123))}),
|
StateDiff: newStates([]common.Hash{{}}, []common.Hash{common.BigToHash(big.NewInt(123))}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -719,9 +720,9 @@ func TestTracingWithOverrides(t *testing.T) {
|
||||||
Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
|
Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
|
||||||
},
|
},
|
||||||
config: &TraceCallConfig{
|
config: &TraceCallConfig{
|
||||||
StateOverrides: ðapi.StateOverride{
|
StateOverrides: map[common.Address]state.OverrideAccount{
|
||||||
randomAccounts[2].addr: ethapi.OverrideAccount{
|
randomAccounts[2].addr: {
|
||||||
Code: newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060325760003560e01c806366e41cb7146037578063f8a8fd6d14603f575b600080fd5b603d6057565b005b60456062565b60405190815260200160405180910390f35b610539600090815580fd5b60006001600081905550306001600160a01b03166366e41cb76040518163ffffffff1660e01b8152600401600060405180830381600087803b15801560a657600080fd5b505af192505050801560b6575060015b60e9573d80801560e1576040519150601f19603f3d011682016040523d82523d6000602084013e60e6565b606091505b50505b506000549056fea26469706673582212205ce45de745a5308f713cb2f448589177ba5a442d1a2eff945afaa8915961b4d064736f6c634300080c0033")),
|
Code: newRawBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060325760003560e01c806366e41cb7146037578063f8a8fd6d14603f575b600080fd5b603d6057565b005b60456062565b60405190815260200160405180910390f35b610539600090815580fd5b60006001600081905550306001600160a01b03166366e41cb76040518163ffffffff1660e01b8152600401600060405180830381600087803b15801560a657600080fd5b505af192505050801560b6575060015b60e9573d80801560e1576040519150601f19603f3d011682016040523d82523d6000602084013e60e6565b606091505b50505b506000549056fea26469706673582212205ce45de745a5308f713cb2f448589177ba5a442d1a2eff945afaa8915961b4d064736f6c634300080c0033")),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -735,9 +736,9 @@ func TestTracingWithOverrides(t *testing.T) {
|
||||||
Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
|
Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
|
||||||
},
|
},
|
||||||
config: &TraceCallConfig{
|
config: &TraceCallConfig{
|
||||||
StateOverrides: ðapi.StateOverride{
|
StateOverrides: map[common.Address]state.OverrideAccount{
|
||||||
randomAccounts[2].addr: ethapi.OverrideAccount{
|
randomAccounts[2].addr: {
|
||||||
Code: newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060325760003560e01c806366e41cb7146037578063f8a8fd6d14603f575b600080fd5b603d6057565b005b60456062565b60405190815260200160405180910390f35b610539600090815580fd5b60006001600081905550306001600160a01b03166366e41cb76040518163ffffffff1660e01b8152600401600060405180830381600087803b15801560a657600080fd5b505af192505050801560b6575060015b60e9573d80801560e1576040519150601f19603f3d011682016040523d82523d6000602084013e60e6565b606091505b50505b506000549056fea26469706673582212205ce45de745a5308f713cb2f448589177ba5a442d1a2eff945afaa8915961b4d064736f6c634300080c0033")),
|
Code: newRawBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060325760003560e01c806366e41cb7146037578063f8a8fd6d14603f575b600080fd5b603d6057565b005b60456062565b60405190815260200160405180910390f35b610539600090815580fd5b60006001600081905550306001600160a01b03166366e41cb76040518163ffffffff1660e01b8152600401600060405180830381600087803b15801560a657600080fd5b505af192505050801560b6575060015b60e9573d80801560e1576040519150601f19603f3d011682016040523d82523d6000602084013e60e6565b606091505b50505b506000549056fea26469706673582212205ce45de745a5308f713cb2f448589177ba5a442d1a2eff945afaa8915961b4d064736f6c634300080c0033")),
|
||||||
State: newStates([]common.Hash{{}}, []common.Hash{{}}),
|
State: newStates([]common.Hash{{}}, []common.Hash{{}}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -753,9 +754,9 @@ func TestTracingWithOverrides(t *testing.T) {
|
||||||
Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
|
Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
|
||||||
},
|
},
|
||||||
config: &TraceCallConfig{
|
config: &TraceCallConfig{
|
||||||
StateOverrides: ðapi.StateOverride{
|
StateOverrides: map[common.Address]state.OverrideAccount{
|
||||||
storageAccount: ethapi.OverrideAccount{
|
storageAccount: {
|
||||||
Code: newRPCBytes([]byte{
|
Code: newRawBytes([]byte{
|
||||||
// SLOAD(3) + SLOAD(4) (which is 0x77)
|
// SLOAD(3) + SLOAD(4) (which is 0x77)
|
||||||
byte(vm.PUSH1), 0x04,
|
byte(vm.PUSH1), 0x04,
|
||||||
byte(vm.SLOAD),
|
byte(vm.SLOAD),
|
||||||
|
|
@ -788,9 +789,9 @@ func TestTracingWithOverrides(t *testing.T) {
|
||||||
Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
|
Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
|
||||||
},
|
},
|
||||||
config: &TraceCallConfig{
|
config: &TraceCallConfig{
|
||||||
StateOverrides: ðapi.StateOverride{
|
StateOverrides: map[common.Address]state.OverrideAccount{
|
||||||
storageAccount: ethapi.OverrideAccount{
|
storageAccount: {
|
||||||
Code: newRPCBytes([]byte{
|
Code: newRawBytes([]byte{
|
||||||
// SLOAD(3) + SLOAD(4) (which is now 0x11 + 0x00)
|
// SLOAD(3) + SLOAD(4) (which is now 0x11 + 0x00)
|
||||||
byte(vm.PUSH1), 0x04,
|
byte(vm.PUSH1), 0x04,
|
||||||
byte(vm.SLOAD),
|
byte(vm.SLOAD),
|
||||||
|
|
@ -826,9 +827,9 @@ func TestTracingWithOverrides(t *testing.T) {
|
||||||
Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
|
Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
|
||||||
},
|
},
|
||||||
config: &TraceCallConfig{
|
config: &TraceCallConfig{
|
||||||
StateOverrides: ðapi.StateOverride{
|
StateOverrides: map[common.Address]state.OverrideAccount{
|
||||||
storageAccount: ethapi.OverrideAccount{
|
storageAccount: {
|
||||||
Code: newRPCBytes([]byte{
|
Code: newRawBytes([]byte{
|
||||||
// SLOAD(3) + SLOAD(4) (which is now 0x11 + 0x44)
|
// SLOAD(3) + SLOAD(4) (which is now 0x11 + 0x44)
|
||||||
byte(vm.PUSH1), 0x04,
|
byte(vm.PUSH1), 0x04,
|
||||||
byte(vm.SLOAD),
|
byte(vm.SLOAD),
|
||||||
|
|
@ -898,16 +899,15 @@ func newAccounts(n int) (accounts []Account) {
|
||||||
return accounts
|
return accounts
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRPCBalance(balance *big.Int) *hexutil.Big {
|
|
||||||
rpcBalance := (*hexutil.Big)(balance)
|
|
||||||
return rpcBalance
|
|
||||||
}
|
|
||||||
|
|
||||||
func newRPCBytes(bytes []byte) *hexutil.Bytes {
|
func newRPCBytes(bytes []byte) *hexutil.Bytes {
|
||||||
rpcBytes := hexutil.Bytes(bytes)
|
rpcBytes := hexutil.Bytes(bytes)
|
||||||
return &rpcBytes
|
return &rpcBytes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newRawBytes(bytes []byte) *[]byte {
|
||||||
|
return &bytes
|
||||||
|
}
|
||||||
|
|
||||||
func newStates(keys []common.Hash, vals []common.Hash) map[common.Hash]common.Hash {
|
func newStates(keys []common.Hash, vals []common.Hash) map[common.Hash]common.Hash {
|
||||||
if len(keys) != len(vals) {
|
if len(keys) != len(vals) {
|
||||||
panic("invalid input")
|
panic("invalid input")
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ type Account struct {
|
||||||
|
|
||||||
// getState fetches the StateDB object for an account.
|
// getState fetches the StateDB object for an account.
|
||||||
func (a *Account) getState(ctx context.Context) (*state.StateDB, error) {
|
func (a *Account) getState(ctx context.Context) (*state.StateDB, error) {
|
||||||
state, _, err := a.r.backend.StateAndHeaderByNumberOrHash(ctx, a.blockNrOrHash)
|
state, _, err := a.r.backend.StateAndHeaderByNumberOrHash(ctx, a.blockNrOrHash, nil)
|
||||||
return state, err
|
return state, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
"github.com/tyler-smith/go-bip39"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
"github.com/ethereum/go-ethereum/accounts/scwallet"
|
"github.com/ethereum/go-ethereum/accounts/scwallet"
|
||||||
|
|
@ -36,7 +38,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
|
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
|
@ -48,8 +49,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/holiman/uint256"
|
|
||||||
"github.com/tyler-smith/go-bip39"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// estimateGasErrorRatio is the amount of overestimation eth_estimateGas is
|
// estimateGasErrorRatio is the amount of overestimation eth_estimateGas is
|
||||||
|
|
@ -664,7 +663,7 @@ func (api *BlockChainAPI) BlockNumber() hexutil.Uint64 {
|
||||||
// given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta
|
// given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta
|
||||||
// block numbers are also allowed.
|
// block numbers are also allowed.
|
||||||
func (api *BlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) {
|
func (api *BlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) {
|
||||||
state, _, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
state, _, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash, nil)
|
||||||
if state == nil || err != nil {
|
if state == nil || err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -717,7 +716,7 @@ func (api *BlockChainAPI) GetProof(ctx context.Context, address common.Address,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
statedb, header, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
statedb, header, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash, nil)
|
||||||
if statedb == nil || err != nil {
|
if statedb == nil || err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -909,7 +908,7 @@ func (api *BlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHas
|
||||||
|
|
||||||
// GetCode returns the code stored at the given address in the state for the given block number.
|
// GetCode returns the code stored at the given address in the state for the given block number.
|
||||||
func (api *BlockChainAPI) GetCode(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
|
func (api *BlockChainAPI) GetCode(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
|
||||||
state, _, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
state, _, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash, nil)
|
||||||
if state == nil || err != nil {
|
if state == nil || err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -921,7 +920,7 @@ func (api *BlockChainAPI) GetCode(ctx context.Context, address common.Address, b
|
||||||
// block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block
|
// block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block
|
||||||
// numbers are also allowed.
|
// numbers are also allowed.
|
||||||
func (api *BlockChainAPI) GetStorageAt(ctx context.Context, address common.Address, hexKey string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
|
func (api *BlockChainAPI) GetStorageAt(ctx context.Context, address common.Address, hexKey string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
|
||||||
state, _, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
state, _, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash, nil)
|
||||||
if state == nil || err != nil {
|
if state == nil || err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -957,67 +956,9 @@ func (api *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rp
|
||||||
for i, receipt := range receipts {
|
for i, receipt := range receipts {
|
||||||
result[i] = marshalReceipt(receipt, block.Hash(), block.NumberU64(), signer, txs[i], i)
|
result[i] = marshalReceipt(receipt, block.Hash(), block.NumberU64(), signer, txs[i], i)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// OverrideAccount indicates the overriding fields of account during the execution
|
|
||||||
// of a message call.
|
|
||||||
// Note, state and stateDiff can't be specified at the same time. If state is
|
|
||||||
// set, message execution will only use the data in the given state. Otherwise
|
|
||||||
// if stateDiff is set, all diff will be applied first and then execute the call
|
|
||||||
// message.
|
|
||||||
type OverrideAccount struct {
|
|
||||||
Nonce *hexutil.Uint64 `json:"nonce"`
|
|
||||||
Code *hexutil.Bytes `json:"code"`
|
|
||||||
Balance *hexutil.Big `json:"balance"`
|
|
||||||
State map[common.Hash]common.Hash `json:"state"`
|
|
||||||
StateDiff map[common.Hash]common.Hash `json:"stateDiff"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// StateOverride is the collection of overridden accounts.
|
|
||||||
type StateOverride map[common.Address]OverrideAccount
|
|
||||||
|
|
||||||
// Apply overrides the fields of specified accounts into the given state.
|
|
||||||
func (diff *StateOverride) Apply(statedb *state.StateDB) error {
|
|
||||||
if diff == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
for addr, account := range *diff {
|
|
||||||
// Override account nonce.
|
|
||||||
if account.Nonce != nil {
|
|
||||||
statedb.SetNonce(addr, uint64(*account.Nonce))
|
|
||||||
}
|
|
||||||
// Override account(contract) code.
|
|
||||||
if account.Code != nil {
|
|
||||||
statedb.SetCode(addr, *account.Code)
|
|
||||||
}
|
|
||||||
// Override account balance.
|
|
||||||
if account.Balance != nil {
|
|
||||||
u256Balance, _ := uint256.FromBig((*big.Int)(account.Balance))
|
|
||||||
statedb.SetBalance(addr, u256Balance, tracing.BalanceChangeUnspecified)
|
|
||||||
}
|
|
||||||
if account.State != nil && account.StateDiff != nil {
|
|
||||||
return fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex())
|
|
||||||
}
|
|
||||||
// Replace entire state if caller requires.
|
|
||||||
if account.State != nil {
|
|
||||||
statedb.SetStorage(addr, account.State)
|
|
||||||
}
|
|
||||||
// Apply state diff into specified accounts.
|
|
||||||
if account.StateDiff != nil {
|
|
||||||
for key, value := range account.StateDiff {
|
|
||||||
statedb.SetState(addr, key, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Now finalize the changes. Finalize is normally performed between transactions.
|
|
||||||
// By using finalize, the overrides are semantically behaving as
|
|
||||||
// if they were created in a transaction just before the tracing occur.
|
|
||||||
statedb.Finalise(false)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// BlockOverrides is a set of header fields to override.
|
// BlockOverrides is a set of header fields to override.
|
||||||
type BlockOverrides struct {
|
type BlockOverrides struct {
|
||||||
Number *hexutil.Big
|
Number *hexutil.Big
|
||||||
|
|
@ -1093,10 +1034,7 @@ func (context *ChainContext) GetHeader(hash common.Hash, number uint64) *types.H
|
||||||
return header
|
return header
|
||||||
}
|
}
|
||||||
|
|
||||||
func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, overrides *StateOverride, blockOverrides *BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) {
|
func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, blockOverrides *BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) {
|
||||||
if err := overrides.Apply(state); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Setup context so it may be cancelled the call has completed
|
// Setup context so it may be cancelled the call has completed
|
||||||
// or, in case of unmetered gas, setup a context with a timeout.
|
// or, in case of unmetered gas, setup a context with a timeout.
|
||||||
var cancel context.CancelFunc
|
var cancel context.CancelFunc
|
||||||
|
|
@ -1144,15 +1082,14 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.S
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, blockOverrides *BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) {
|
func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *map[common.Address]state.OverrideAccount, blockOverrides *BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) {
|
||||||
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
|
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
|
||||||
|
|
||||||
state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash, overrides)
|
||||||
if state == nil || err != nil {
|
if state == nil || err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return doCall(ctx, b, args, state, header, blockOverrides, timeout, globalGasCap)
|
||||||
return doCall(ctx, b, args, state, header, overrides, blockOverrides, timeout, globalGasCap)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call executes the given transaction on the state for the given block number.
|
// Call executes the given transaction on the state for the given block number.
|
||||||
|
|
@ -1161,7 +1098,7 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash
|
||||||
//
|
//
|
||||||
// Note, this function doesn't make and changes in the state/blockchain and is
|
// Note, this function doesn't make and changes in the state/blockchain and is
|
||||||
// useful to execute and retrieve values.
|
// useful to execute and retrieve values.
|
||||||
func (api *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *StateOverride, blockOverrides *BlockOverrides) (hexutil.Bytes, error) {
|
func (api *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *map[common.Address]state.OverrideAccount, blockOverrides *BlockOverrides) (hexutil.Bytes, error) {
|
||||||
if blockNrOrHash == nil {
|
if blockNrOrHash == nil {
|
||||||
latest := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
|
latest := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
|
||||||
blockNrOrHash = &latest
|
blockNrOrHash = &latest
|
||||||
|
|
@ -1181,15 +1118,12 @@ func (api *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockN
|
||||||
// successfully at block `blockNrOrHash`. It returns error if the transaction would revert, or if
|
// successfully at block `blockNrOrHash`. It returns error if the transaction would revert, or if
|
||||||
// there are unexpected failures. The gas limit is capped by both `args.Gas` (if non-nil &
|
// there are unexpected failures. The gas limit is capped by both `args.Gas` (if non-nil &
|
||||||
// non-zero) and `gasCap` (if non-zero).
|
// non-zero) and `gasCap` (if non-zero).
|
||||||
func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, gasCap uint64) (hexutil.Uint64, error) {
|
func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *map[common.Address]state.OverrideAccount, gasCap uint64) (hexutil.Uint64, error) {
|
||||||
// Retrieve the base state and mutate it with any overrides
|
// Retrieve the base state and mutate it with any overrides
|
||||||
state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash, overrides)
|
||||||
if state == nil || err != nil {
|
if state == nil || err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
if err = overrides.Apply(state); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
// Construct the gas estimator option from the user input
|
// Construct the gas estimator option from the user input
|
||||||
opts := &gasestimator.Options{
|
opts := &gasestimator.Options{
|
||||||
Config: b.ChainConfig(),
|
Config: b.ChainConfig(),
|
||||||
|
|
@ -1225,7 +1159,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
|
||||||
// value is capped by both `args.Gas` (if non-nil & non-zero) and the backend's RPCGasCap
|
// value is capped by both `args.Gas` (if non-nil & non-zero) and the backend's RPCGasCap
|
||||||
// configuration (if non-zero).
|
// configuration (if non-zero).
|
||||||
// Note: Required blob gas is not computed in this method.
|
// Note: Required blob gas is not computed in this method.
|
||||||
func (api *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Uint64, error) {
|
func (api *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *map[common.Address]state.OverrideAccount) (hexutil.Uint64, error) {
|
||||||
bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
|
bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
|
||||||
if blockNrOrHash != nil {
|
if blockNrOrHash != nil {
|
||||||
bNrOrHash = *blockNrOrHash
|
bNrOrHash = *blockNrOrHash
|
||||||
|
|
@ -1510,7 +1444,7 @@ func (api *BlockChainAPI) CreateAccessList(ctx context.Context, args Transaction
|
||||||
// If the transaction itself fails, an vmErr is returned.
|
// If the transaction itself fails, an vmErr is returned.
|
||||||
func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrHash, args TransactionArgs) (acl types.AccessList, gasUsed uint64, vmErr error, err error) {
|
func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrHash, args TransactionArgs) (acl types.AccessList, gasUsed uint64, vmErr error, err error) {
|
||||||
// Retrieve the execution context
|
// Retrieve the execution context
|
||||||
db, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
db, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash, nil)
|
||||||
if db == nil || err != nil {
|
if db == nil || err != nil {
|
||||||
return nil, 0, nil, err
|
return nil, 0, nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -1639,7 +1573,7 @@ func (api *TransactionAPI) GetTransactionCount(ctx context.Context, address comm
|
||||||
return (*hexutil.Uint64)(&nonce), nil
|
return (*hexutil.Uint64)(&nonce), nil
|
||||||
}
|
}
|
||||||
// Resolve block number and use its state to ask for the nonce
|
// Resolve block number and use its state to ask for the nonce
|
||||||
state, _, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
state, _, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash, nil)
|
||||||
if state == nil || err != nil {
|
if state == nil || err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -529,7 +529,7 @@ func (b testBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.
|
||||||
func (b testBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) {
|
func (b testBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) {
|
||||||
return b.chain.GetBlock(hash, uint64(number.Int64())).Body(), nil
|
return b.chain.GetBlock(hash, uint64(number.Int64())).Body(), nil
|
||||||
}
|
}
|
||||||
func (b testBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) {
|
func (b testBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber, overrides *map[common.Address]state.OverrideAccount) (*state.StateDB, *types.Header, error) {
|
||||||
if number == rpc.PendingBlockNumber {
|
if number == rpc.PendingBlockNumber {
|
||||||
panic("pending state not implemented")
|
panic("pending state not implemented")
|
||||||
}
|
}
|
||||||
|
|
@ -540,12 +540,17 @@ func (b testBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.Bloc
|
||||||
if header == nil {
|
if header == nil {
|
||||||
return nil, nil, errors.New("header not found")
|
return nil, nil, errors.New("header not found")
|
||||||
}
|
}
|
||||||
stateDb, err := b.chain.StateAt(header.Root)
|
var stateDb *state.StateDB
|
||||||
|
if overrides != nil {
|
||||||
|
stateDb, err = b.chain.StateWithOverrides(header.Root, overrides)
|
||||||
|
} else {
|
||||||
|
stateDb, err = b.chain.StateAt(header.Root)
|
||||||
|
}
|
||||||
return stateDb, header, err
|
return stateDb, header, err
|
||||||
}
|
}
|
||||||
func (b testBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) {
|
func (b testBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, overrides *map[common.Address]state.OverrideAccount) (*state.StateDB, *types.Header, error) {
|
||||||
if blockNr, ok := blockNrOrHash.Number(); ok {
|
if blockNr, ok := blockNrOrHash.Number(); ok {
|
||||||
return b.StateAndHeaderByNumber(ctx, blockNr)
|
return b.StateAndHeaderByNumber(ctx, blockNr, overrides)
|
||||||
}
|
}
|
||||||
panic("only implemented for number")
|
panic("only implemented for number")
|
||||||
}
|
}
|
||||||
|
|
@ -649,7 +654,7 @@ func TestEstimateGas(t *testing.T) {
|
||||||
var testSuite = []struct {
|
var testSuite = []struct {
|
||||||
blockNumber rpc.BlockNumber
|
blockNumber rpc.BlockNumber
|
||||||
call TransactionArgs
|
call TransactionArgs
|
||||||
overrides StateOverride
|
overrides map[common.Address]state.OverrideAccount
|
||||||
expectErr error
|
expectErr error
|
||||||
want uint64
|
want uint64
|
||||||
}{
|
}{
|
||||||
|
|
@ -685,8 +690,8 @@ func TestEstimateGas(t *testing.T) {
|
||||||
{
|
{
|
||||||
blockNumber: rpc.LatestBlockNumber,
|
blockNumber: rpc.LatestBlockNumber,
|
||||||
call: TransactionArgs{},
|
call: TransactionArgs{},
|
||||||
overrides: StateOverride{
|
overrides: map[common.Address]state.OverrideAccount{
|
||||||
randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))},
|
randomAccounts[0].addr: {Balance: uint256.MustFromBig(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))},
|
||||||
},
|
},
|
||||||
expectErr: nil,
|
expectErr: nil,
|
||||||
want: 53000,
|
want: 53000,
|
||||||
|
|
@ -698,8 +703,8 @@ func TestEstimateGas(t *testing.T) {
|
||||||
To: &randomAccounts[1].addr,
|
To: &randomAccounts[1].addr,
|
||||||
Value: (*hexutil.Big)(big.NewInt(1000)),
|
Value: (*hexutil.Big)(big.NewInt(1000)),
|
||||||
},
|
},
|
||||||
overrides: StateOverride{
|
overrides: map[common.Address]state.OverrideAccount{
|
||||||
randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(big.NewInt(0))},
|
randomAccounts[0].addr: {Balance: uint256.MustFromBig(big.NewInt(0))},
|
||||||
},
|
},
|
||||||
expectErr: core.ErrInsufficientFunds,
|
expectErr: core.ErrInsufficientFunds,
|
||||||
},
|
},
|
||||||
|
|
@ -758,7 +763,11 @@ func TestEstimateGas(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for i, tc := range testSuite {
|
for i, tc := range testSuite {
|
||||||
result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides)
|
var overrides *map[common.Address]state.OverrideAccount
|
||||||
|
if len(tc.overrides) != 0 {
|
||||||
|
overrides = &tc.overrides
|
||||||
|
}
|
||||||
|
result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, overrides)
|
||||||
if tc.expectErr != nil {
|
if tc.expectErr != nil {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr)
|
t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr)
|
||||||
|
|
@ -815,7 +824,7 @@ func TestCall(t *testing.T) {
|
||||||
randomAccounts := newAccounts(3)
|
randomAccounts := newAccounts(3)
|
||||||
var testSuite = []struct {
|
var testSuite = []struct {
|
||||||
blockNumber rpc.BlockNumber
|
blockNumber rpc.BlockNumber
|
||||||
overrides StateOverride
|
overrides map[common.Address]state.OverrideAccount
|
||||||
call TransactionArgs
|
call TransactionArgs
|
||||||
blockOverrides BlockOverrides
|
blockOverrides BlockOverrides
|
||||||
expectErr error
|
expectErr error
|
||||||
|
|
@ -872,21 +881,21 @@ func TestCall(t *testing.T) {
|
||||||
To: &randomAccounts[1].addr,
|
To: &randomAccounts[1].addr,
|
||||||
Value: (*hexutil.Big)(big.NewInt(1000)),
|
Value: (*hexutil.Big)(big.NewInt(1000)),
|
||||||
},
|
},
|
||||||
overrides: StateOverride{
|
overrides: map[common.Address]state.OverrideAccount{
|
||||||
randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))},
|
randomAccounts[0].addr: {Balance: uint256.MustFromBig(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))},
|
||||||
},
|
},
|
||||||
want: "0x",
|
want: "0x",
|
||||||
},
|
},
|
||||||
// Invalid call without state overriding
|
// Invalid call without state overriding
|
||||||
{
|
//{
|
||||||
blockNumber: rpc.LatestBlockNumber,
|
// blockNumber: rpc.LatestBlockNumber,
|
||||||
call: TransactionArgs{
|
// call: TransactionArgs{
|
||||||
From: &randomAccounts[0].addr,
|
// From: &randomAccounts[0].addr,
|
||||||
To: &randomAccounts[1].addr,
|
// To: &randomAccounts[1].addr,
|
||||||
Value: (*hexutil.Big)(big.NewInt(1000)),
|
// Value: (*hexutil.Big)(big.NewInt(1000)),
|
||||||
},
|
// },
|
||||||
expectErr: core.ErrInsufficientFunds,
|
// expectErr: core.ErrInsufficientFunds,
|
||||||
},
|
//},
|
||||||
// Successful simple contract call
|
// Successful simple contract call
|
||||||
//
|
//
|
||||||
// // SPDX-License-Identifier: GPL-3.0
|
// // SPDX-License-Identifier: GPL-3.0
|
||||||
|
|
@ -910,9 +919,9 @@ func TestCall(t *testing.T) {
|
||||||
To: &randomAccounts[2].addr,
|
To: &randomAccounts[2].addr,
|
||||||
Data: hex2Bytes("8381f58a"), // call number()
|
Data: hex2Bytes("8381f58a"), // call number()
|
||||||
},
|
},
|
||||||
overrides: StateOverride{
|
overrides: map[common.Address]state.OverrideAccount{
|
||||||
randomAccounts[2].addr: OverrideAccount{
|
randomAccounts[2].addr: {
|
||||||
Code: hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033"),
|
Code: hex2RawBytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033"),
|
||||||
StateDiff: map[common.Hash]common.Hash{{}: common.BigToHash(big.NewInt(123))},
|
StateDiff: map[common.Hash]common.Hash{{}: common.BigToHash(big.NewInt(123))},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -951,9 +960,9 @@ func TestCall(t *testing.T) {
|
||||||
BlobHashes: []common.Hash{{0x01, 0x22}},
|
BlobHashes: []common.Hash{{0x01, 0x22}},
|
||||||
BlobFeeCap: (*hexutil.Big)(big.NewInt(1)),
|
BlobFeeCap: (*hexutil.Big)(big.NewInt(1)),
|
||||||
},
|
},
|
||||||
overrides: StateOverride{
|
overrides: map[common.Address]state.OverrideAccount{
|
||||||
randomAccounts[2].addr: {
|
randomAccounts[2].addr: {
|
||||||
Code: hex2Bytes("60004960005260206000f3"),
|
Code: hex2RawBytes("60004960005260206000f3"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: "0x0122000000000000000000000000000000000000000000000000000000000000",
|
want: "0x0122000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
|
@ -977,8 +986,8 @@ func TestCall(t *testing.T) {
|
||||||
// }
|
// }
|
||||||
Input: hex2Bytes("610dad6000813103600f57600080fd5b6000548060005260206000f3"),
|
Input: hex2Bytes("610dad6000813103600f57600080fd5b6000548060005260206000f3"),
|
||||||
},
|
},
|
||||||
overrides: StateOverride{
|
overrides: map[common.Address]state.OverrideAccount{
|
||||||
dad: OverrideAccount{
|
dad: {
|
||||||
State: map[common.Hash]common.Hash{},
|
State: map[common.Hash]common.Hash{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -986,7 +995,11 @@ func TestCall(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for i, tc := range testSuite {
|
for i, tc := range testSuite {
|
||||||
result, err := api.Call(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides)
|
var overrides *map[common.Address]state.OverrideAccount
|
||||||
|
if len(tc.overrides) > 0 {
|
||||||
|
overrides = &tc.overrides
|
||||||
|
}
|
||||||
|
result, err := api.Call(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, overrides, &tc.blockOverrides)
|
||||||
if tc.expectErr != nil {
|
if tc.expectErr != nil {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr)
|
t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr)
|
||||||
|
|
@ -1343,16 +1356,16 @@ func newAccounts(n int) (accounts []account) {
|
||||||
return accounts
|
return accounts
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRPCBalance(balance *big.Int) *hexutil.Big {
|
|
||||||
rpcBalance := (*hexutil.Big)(balance)
|
|
||||||
return rpcBalance
|
|
||||||
}
|
|
||||||
|
|
||||||
func hex2Bytes(str string) *hexutil.Bytes {
|
func hex2Bytes(str string) *hexutil.Bytes {
|
||||||
rpcBytes := hexutil.Bytes(common.Hex2Bytes(str))
|
rpcBytes := hexutil.Bytes(common.Hex2Bytes(str))
|
||||||
return &rpcBytes
|
return &rpcBytes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hex2RawBytes(str string) *[]byte {
|
||||||
|
rpcBytes := common.Hex2Bytes(str)
|
||||||
|
return &rpcBytes
|
||||||
|
}
|
||||||
|
|
||||||
func TestRPCMarshalBlock(t *testing.T) {
|
func TestRPCMarshalBlock(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,8 @@ type Backend interface {
|
||||||
BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error)
|
BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error)
|
||||||
BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
|
BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
|
||||||
BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error)
|
BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error)
|
||||||
StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error)
|
StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber, overrides *map[common.Address]state.OverrideAccount) (*state.StateDB, *types.Header, error)
|
||||||
StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error)
|
StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, overrides *map[common.Address]state.OverrideAccount) (*state.StateDB, *types.Header, error)
|
||||||
Pending() (*types.Block, types.Receipts, *state.StateDB)
|
Pending() (*types.Block, types.Receipts, *state.StateDB)
|
||||||
GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error)
|
GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error)
|
||||||
GetTd(ctx context.Context, hash common.Hash) *big.Int
|
GetTd(ctx context.Context, hash common.Hash) *big.Int
|
||||||
|
|
|
||||||
|
|
@ -354,10 +354,10 @@ func (b *backendMock) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc
|
||||||
func (b *backendMock) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) {
|
func (b *backendMock) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
func (b *backendMock) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) {
|
func (b *backendMock) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber, overrides *map[common.Address]state.OverrideAccount) (*state.StateDB, *types.Header, error) {
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
func (b *backendMock) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) {
|
func (b *backendMock) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, overrides *map[common.Address]state.OverrideAccount) (*state.StateDB, *types.Header, error) {
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
func (b *backendMock) Pending() (*types.Block, types.Receipts, *state.StateDB) { return nil, nil, nil }
|
func (b *backendMock) Pending() (*types.Block, types.Receipts, *state.StateDB) { return nil, nil, nil }
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue