Merge 3def46a6e0
into 53f66c1b03
This commit is contained in:
commit
af87cdc8cd
|
@ -37,6 +37,7 @@ profile.cov
|
|||
|
||||
# IdeaIDE
|
||||
.idea
|
||||
*.iml
|
||||
|
||||
# VS Code
|
||||
.vscode
|
||||
|
|
|
@ -28,6 +28,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi/override"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
@ -38,10 +39,11 @@ import (
|
|||
// these together, it would be excessively hard to test. Splitting the parts out
|
||||
// allows testing without needing a proper live chain.
|
||||
type Options struct {
|
||||
Config *params.ChainConfig // Chain configuration for hard fork selection
|
||||
Chain core.ChainContext // Chain context to access past block hashes
|
||||
Header *types.Header // Header defining the block context to execute in
|
||||
State *state.StateDB // Pre-state on top of which to estimate the gas
|
||||
Config *params.ChainConfig // Chain configuration for hard fork selection
|
||||
Chain core.ChainContext // Chain context to access past block hashes
|
||||
Header *types.Header // Header defining the block context to execute in
|
||||
State *state.StateDB // Pre-state on top of which to estimate the gas
|
||||
BlockOverrides *override.BlockOverrides // Block overrides to apply during the estimation
|
||||
|
||||
ErrorRatio float64 // Allowed overestimation ratio for faster estimation termination
|
||||
}
|
||||
|
@ -222,6 +224,9 @@ func run(ctx context.Context, call *core.Message, opts *Options) (*core.Executio
|
|||
|
||||
dirtyState = opts.State.Copy()
|
||||
)
|
||||
if opts.BlockOverrides != nil {
|
||||
opts.BlockOverrides.Apply(&evmContext)
|
||||
}
|
||||
// Lower the basefee to 0 to avoid breaking EVM
|
||||
// invariants (basefee < feecap).
|
||||
if msgContext.GasPrice.Sign() == 0 {
|
||||
|
|
|
@ -39,6 +39,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi/override"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
|
@ -163,8 +164,8 @@ type TraceConfig struct {
|
|||
// field to override the state for tracing.
|
||||
type TraceCallConfig struct {
|
||||
TraceConfig
|
||||
StateOverrides *ethapi.StateOverride
|
||||
BlockOverrides *ethapi.BlockOverrides
|
||||
StateOverrides *override.StateOverride
|
||||
BlockOverrides *override.BlockOverrides
|
||||
TxIndex *hexutil.Uint
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi/override"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
@ -367,7 +368,7 @@ func TestTraceCall(t *testing.T) {
|
|||
Input: &hexutil.Bytes{0x43}, // blocknumber
|
||||
},
|
||||
config: &TraceCallConfig{
|
||||
BlockOverrides: ðapi.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))},
|
||||
BlockOverrides: &override.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))},
|
||||
},
|
||||
expectErr: nil,
|
||||
expect: ` {"gas":53018,"failed":false,"returnValue":"","structLogs":[
|
||||
|
@ -611,8 +612,8 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||
Value: (*hexutil.Big)(big.NewInt(1000)),
|
||||
},
|
||||
config: &TraceCallConfig{
|
||||
StateOverrides: ðapi.StateOverride{
|
||||
randomAccounts[0].addr: ethapi.OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))},
|
||||
StateOverrides: &override.StateOverride{
|
||||
randomAccounts[0].addr: override.OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))},
|
||||
},
|
||||
},
|
||||
want: `{"gas":21000,"failed":false,"returnValue":""}`,
|
||||
|
@ -653,8 +654,8 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||
},
|
||||
config: &TraceCallConfig{
|
||||
//Tracer: &tracer,
|
||||
StateOverrides: ðapi.StateOverride{
|
||||
randomAccounts[2].addr: ethapi.OverrideAccount{
|
||||
StateOverrides: &override.StateOverride{
|
||||
randomAccounts[2].addr: override.OverrideAccount{
|
||||
Code: newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033")),
|
||||
StateDiff: newStates([]common.Hash{{}}, []common.Hash{common.BigToHash(big.NewInt(123))}),
|
||||
},
|
||||
|
@ -670,7 +671,7 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||
Input: newRPCBytes(common.Hex2Bytes("4360005260206000f3")),
|
||||
},
|
||||
config: &TraceCallConfig{
|
||||
BlockOverrides: ðapi.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))},
|
||||
BlockOverrides: &override.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))},
|
||||
},
|
||||
want: `{"gas":59537,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000001337"}`,
|
||||
},
|
||||
|
@ -690,7 +691,7 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||
}, // blocknumber
|
||||
},
|
||||
config: &TraceCallConfig{
|
||||
BlockOverrides: ðapi.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))},
|
||||
BlockOverrides: &override.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))},
|
||||
},
|
||||
want: `{"gas":72666,"failed":false,"returnValue":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}`,
|
||||
},
|
||||
|
@ -720,8 +721,8 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||
Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
|
||||
},
|
||||
config: &TraceCallConfig{
|
||||
StateOverrides: ðapi.StateOverride{
|
||||
randomAccounts[2].addr: ethapi.OverrideAccount{
|
||||
StateOverrides: &override.StateOverride{
|
||||
randomAccounts[2].addr: override.OverrideAccount{
|
||||
Code: newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060325760003560e01c806366e41cb7146037578063f8a8fd6d14603f575b600080fd5b603d6057565b005b60456062565b60405190815260200160405180910390f35b610539600090815580fd5b60006001600081905550306001600160a01b03166366e41cb76040518163ffffffff1660e01b8152600401600060405180830381600087803b15801560a657600080fd5b505af192505050801560b6575060015b60e9573d80801560e1576040519150601f19603f3d011682016040523d82523d6000602084013e60e6565b606091505b50505b506000549056fea26469706673582212205ce45de745a5308f713cb2f448589177ba5a442d1a2eff945afaa8915961b4d064736f6c634300080c0033")),
|
||||
},
|
||||
},
|
||||
|
@ -736,8 +737,8 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||
Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
|
||||
},
|
||||
config: &TraceCallConfig{
|
||||
StateOverrides: ðapi.StateOverride{
|
||||
randomAccounts[2].addr: ethapi.OverrideAccount{
|
||||
StateOverrides: &override.StateOverride{
|
||||
randomAccounts[2].addr: override.OverrideAccount{
|
||||
Code: newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060325760003560e01c806366e41cb7146037578063f8a8fd6d14603f575b600080fd5b603d6057565b005b60456062565b60405190815260200160405180910390f35b610539600090815580fd5b60006001600081905550306001600160a01b03166366e41cb76040518163ffffffff1660e01b8152600401600060405180830381600087803b15801560a657600080fd5b505af192505050801560b6575060015b60e9573d80801560e1576040519150601f19603f3d011682016040523d82523d6000602084013e60e6565b606091505b50505b506000549056fea26469706673582212205ce45de745a5308f713cb2f448589177ba5a442d1a2eff945afaa8915961b4d064736f6c634300080c0033")),
|
||||
State: newStates([]common.Hash{{}}, []common.Hash{{}}),
|
||||
},
|
||||
|
@ -754,8 +755,8 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||
Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
|
||||
},
|
||||
config: &TraceCallConfig{
|
||||
StateOverrides: ðapi.StateOverride{
|
||||
storageAccount: ethapi.OverrideAccount{
|
||||
StateOverrides: &override.StateOverride{
|
||||
storageAccount: override.OverrideAccount{
|
||||
Code: newRPCBytes([]byte{
|
||||
// SLOAD(3) + SLOAD(4) (which is 0x77)
|
||||
byte(vm.PUSH1), 0x04,
|
||||
|
@ -789,8 +790,8 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||
Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
|
||||
},
|
||||
config: &TraceCallConfig{
|
||||
StateOverrides: ðapi.StateOverride{
|
||||
storageAccount: ethapi.OverrideAccount{
|
||||
StateOverrides: &override.StateOverride{
|
||||
storageAccount: override.OverrideAccount{
|
||||
Code: newRPCBytes([]byte{
|
||||
// SLOAD(3) + SLOAD(4) (which is now 0x11 + 0x00)
|
||||
byte(vm.PUSH1), 0x04,
|
||||
|
@ -827,8 +828,8 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||
Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
|
||||
},
|
||||
config: &TraceCallConfig{
|
||||
StateOverrides: ðapi.StateOverride{
|
||||
storageAccount: ethapi.OverrideAccount{
|
||||
StateOverrides: &override.StateOverride{
|
||||
storageAccount: override.OverrideAccount{
|
||||
Code: newRPCBytes([]byte{
|
||||
// SLOAD(3) + SLOAD(4) (which is now 0x11 + 0x44)
|
||||
byte(vm.PUSH1), 0x04,
|
||||
|
|
|
@ -1208,7 +1208,7 @@ func (b *Block) Call(ctx context.Context, args struct {
|
|||
func (b *Block) EstimateGas(ctx context.Context, args struct {
|
||||
Data ethapi.TransactionArgs
|
||||
}) (hexutil.Uint64, error) {
|
||||
return ethapi.DoEstimateGas(ctx, b.r.backend, args.Data, *b.numberOrHash, nil, b.r.backend.RPCGasCap())
|
||||
return ethapi.DoEstimateGas(ctx, b.r.backend, args.Data, *b.numberOrHash, nil, nil, b.r.backend.RPCGasCap())
|
||||
}
|
||||
|
||||
type Pending struct {
|
||||
|
@ -1272,7 +1272,7 @@ func (p *Pending) EstimateGas(ctx context.Context, args struct {
|
|||
Data ethapi.TransactionArgs
|
||||
}) (hexutil.Uint64, error) {
|
||||
latestBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
|
||||
return ethapi.DoEstimateGas(ctx, p.r.backend, args.Data, latestBlockNr, nil, p.r.backend.RPCGasCap())
|
||||
return ethapi.DoEstimateGas(ctx, p.r.backend, args.Data, latestBlockNr, nil, nil, p.r.backend.RPCGasCap())
|
||||
}
|
||||
|
||||
// Resolver is the top-level object in the GraphQL hierarchy.
|
||||
|
|
|
@ -35,19 +35,18 @@ import (
|
|||
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"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/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/eth/gasestimator"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi/override"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// estimateGasErrorRatio is the amount of overestimation eth_estimateGas is
|
||||
|
@ -621,171 +620,6 @@ func (api *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rp
|
|||
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"`
|
||||
MovePrecompileTo *common.Address `json:"movePrecompileToAddress"`
|
||||
}
|
||||
|
||||
// StateOverride is the collection of overridden accounts.
|
||||
type StateOverride map[common.Address]OverrideAccount
|
||||
|
||||
func (diff *StateOverride) has(address common.Address) bool {
|
||||
_, ok := (*diff)[address]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Apply overrides the fields of specified accounts into the given state.
|
||||
func (diff *StateOverride) Apply(statedb *state.StateDB, precompiles vm.PrecompiledContracts) error {
|
||||
if diff == nil {
|
||||
return nil
|
||||
}
|
||||
// Tracks destinations of precompiles that were moved.
|
||||
dirtyAddrs := make(map[common.Address]struct{})
|
||||
for addr, account := range *diff {
|
||||
// If a precompile was moved to this address already, it can't be overridden.
|
||||
if _, ok := dirtyAddrs[addr]; ok {
|
||||
return fmt.Errorf("account %s has already been overridden by a precompile", addr.Hex())
|
||||
}
|
||||
p, isPrecompile := precompiles[addr]
|
||||
// The MoveTo feature makes it possible to move a precompile
|
||||
// code to another address. If the target address is another precompile
|
||||
// the code for the latter is lost for this session.
|
||||
// Note the destination account is not cleared upon move.
|
||||
if account.MovePrecompileTo != nil {
|
||||
if !isPrecompile {
|
||||
return fmt.Errorf("account %s is not a precompile", addr.Hex())
|
||||
}
|
||||
// Refuse to move a precompile to an address that has been
|
||||
// or will be overridden.
|
||||
if diff.has(*account.MovePrecompileTo) {
|
||||
return fmt.Errorf("account %s is already overridden", account.MovePrecompileTo.Hex())
|
||||
}
|
||||
precompiles[*account.MovePrecompileTo] = p
|
||||
dirtyAddrs[*account.MovePrecompileTo] = struct{}{}
|
||||
}
|
||||
if isPrecompile {
|
||||
delete(precompiles, addr)
|
||||
}
|
||||
// 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.
|
||||
type BlockOverrides struct {
|
||||
Number *hexutil.Big
|
||||
Difficulty *hexutil.Big // No-op if we're simulating post-merge calls.
|
||||
Time *hexutil.Uint64
|
||||
GasLimit *hexutil.Uint64
|
||||
FeeRecipient *common.Address
|
||||
PrevRandao *common.Hash
|
||||
BaseFeePerGas *hexutil.Big
|
||||
BlobBaseFee *hexutil.Big
|
||||
}
|
||||
|
||||
// Apply overrides the given header fields into the given block context.
|
||||
func (o *BlockOverrides) Apply(blockCtx *vm.BlockContext) {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
if o.Number != nil {
|
||||
blockCtx.BlockNumber = o.Number.ToInt()
|
||||
}
|
||||
if o.Difficulty != nil {
|
||||
blockCtx.Difficulty = o.Difficulty.ToInt()
|
||||
}
|
||||
if o.Time != nil {
|
||||
blockCtx.Time = uint64(*o.Time)
|
||||
}
|
||||
if o.GasLimit != nil {
|
||||
blockCtx.GasLimit = uint64(*o.GasLimit)
|
||||
}
|
||||
if o.FeeRecipient != nil {
|
||||
blockCtx.Coinbase = *o.FeeRecipient
|
||||
}
|
||||
if o.PrevRandao != nil {
|
||||
blockCtx.Random = o.PrevRandao
|
||||
}
|
||||
if o.BaseFeePerGas != nil {
|
||||
blockCtx.BaseFee = o.BaseFeePerGas.ToInt()
|
||||
}
|
||||
if o.BlobBaseFee != nil {
|
||||
blockCtx.BlobBaseFee = o.BlobBaseFee.ToInt()
|
||||
}
|
||||
}
|
||||
|
||||
// MakeHeader returns a new header object with the overridden
|
||||
// fields.
|
||||
// Note: MakeHeader ignores BlobBaseFee if set. That's because
|
||||
// header has no such field.
|
||||
func (o *BlockOverrides) MakeHeader(header *types.Header) *types.Header {
|
||||
if o == nil {
|
||||
return header
|
||||
}
|
||||
h := types.CopyHeader(header)
|
||||
if o.Number != nil {
|
||||
h.Number = o.Number.ToInt()
|
||||
}
|
||||
if o.Difficulty != nil {
|
||||
h.Difficulty = o.Difficulty.ToInt()
|
||||
}
|
||||
if o.Time != nil {
|
||||
h.Time = uint64(*o.Time)
|
||||
}
|
||||
if o.GasLimit != nil {
|
||||
h.GasLimit = uint64(*o.GasLimit)
|
||||
}
|
||||
if o.FeeRecipient != nil {
|
||||
h.Coinbase = *o.FeeRecipient
|
||||
}
|
||||
if o.PrevRandao != nil {
|
||||
h.MixDigest = *o.PrevRandao
|
||||
}
|
||||
if o.BaseFeePerGas != nil {
|
||||
h.BaseFee = o.BaseFeePerGas.ToInt()
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
// ChainContextBackend provides methods required to implement ChainContext.
|
||||
type ChainContextBackend interface {
|
||||
Engine() consensus.Engine
|
||||
|
@ -818,7 +652,7 @@ func (context *ChainContext) GetHeader(hash common.Hash, number uint64) *types.H
|
|||
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, overrides *override.StateOverride, blockOverrides *override.BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) {
|
||||
blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil)
|
||||
if blockOverrides != nil {
|
||||
blockOverrides.Apply(&blockCtx)
|
||||
|
@ -898,7 +732,7 @@ func applyMessageWithEVM(ctx context.Context, evm *vm.EVM, msg *core.Message, ti
|
|||
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 *override.StateOverride, blockOverrides *override.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())
|
||||
|
||||
state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
||||
|
@ -914,7 +748,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
|
||||
// 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 *override.StateOverride, blockOverrides *override.BlockOverrides) (hexutil.Bytes, error) {
|
||||
if blockNrOrHash == nil {
|
||||
latest := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
|
||||
blockNrOrHash = &latest
|
||||
|
@ -973,7 +807,7 @@ func (api *BlockChainAPI) SimulateV1(ctx context.Context, opts simOpts, blockNrO
|
|||
// 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 &
|
||||
// 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 *override.StateOverride, blockOverrides *override.BlockOverrides, gasCap uint64) (hexutil.Uint64, error) {
|
||||
// Retrieve the base state and mutate it with any overrides
|
||||
state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
||||
if state == nil || err != nil {
|
||||
|
@ -984,11 +818,12 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
|
|||
}
|
||||
// Construct the gas estimator option from the user input
|
||||
opts := &gasestimator.Options{
|
||||
Config: b.ChainConfig(),
|
||||
Chain: NewChainContext(ctx, b),
|
||||
Header: header,
|
||||
State: state,
|
||||
ErrorRatio: estimateGasErrorRatio,
|
||||
Config: b.ChainConfig(),
|
||||
Chain: NewChainContext(ctx, b),
|
||||
Header: header,
|
||||
BlockOverrides: blockOverrides,
|
||||
State: state,
|
||||
ErrorRatio: estimateGasErrorRatio,
|
||||
}
|
||||
// Set any required transaction default, but make sure the gas cap itself is not messed with
|
||||
// if it was not specified in the original argument list.
|
||||
|
@ -1017,12 +852,12 @@ 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
|
||||
// configuration (if non-zero).
|
||||
// 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 *override.StateOverride, blockOverrides *override.BlockOverrides) (hexutil.Uint64, error) {
|
||||
bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
|
||||
if blockNrOrHash != nil {
|
||||
bNrOrHash = *blockNrOrHash
|
||||
}
|
||||
return DoEstimateGas(ctx, api.b, args, bNrOrHash, overrides, api.b.RPCGasCap())
|
||||
return DoEstimateGas(ctx, api.b, args, bNrOrHash, overrides, blockOverrides, api.b.RPCGasCap())
|
||||
}
|
||||
|
||||
// RPCMarshalHeader converts the given header to the RPC output .
|
||||
|
|
|
@ -24,7 +24,6 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -34,6 +33,9 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi/override"
|
||||
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||
|
@ -55,7 +57,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/internal/blocktest"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/triedb"
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -640,6 +641,17 @@ func TestEstimateGas(t *testing.T) {
|
|||
signer = types.HomesteadSigner{}
|
||||
randomAccounts = newAccounts(2)
|
||||
)
|
||||
packRevert := func(revertMessage string) []byte {
|
||||
var revertSelector = crypto.Keccak256([]byte("Error(string)"))[:4]
|
||||
stringType, _ := abi.NewType("string", "", nil)
|
||||
args := abi.Arguments{
|
||||
{Type: stringType},
|
||||
}
|
||||
encodedMessage, _ := args.Pack(revertMessage)
|
||||
|
||||
return append(revertSelector, encodedMessage...)
|
||||
}
|
||||
|
||||
api := NewBlockChainAPI(newTestBackend(t, genBlocks, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) {
|
||||
// Transfer from account[0] to account[1]
|
||||
// value: 1000 wei
|
||||
|
@ -648,14 +660,16 @@ func TestEstimateGas(t *testing.T) {
|
|||
b.AddTx(tx)
|
||||
b.SetPoS()
|
||||
}))
|
||||
|
||||
var testSuite = []struct {
|
||||
blockNumber rpc.BlockNumber
|
||||
call TransactionArgs
|
||||
overrides StateOverride
|
||||
expectErr error
|
||||
want uint64
|
||||
blockNumber rpc.BlockNumber
|
||||
call TransactionArgs
|
||||
overrides override.StateOverride
|
||||
blockOverrides override.BlockOverrides
|
||||
expectErr error
|
||||
want uint64
|
||||
}{
|
||||
// simple transfer on latest block
|
||||
//simple transfer on latest block
|
||||
{
|
||||
blockNumber: rpc.LatestBlockNumber,
|
||||
call: TransactionArgs{
|
||||
|
@ -687,8 +701,8 @@ func TestEstimateGas(t *testing.T) {
|
|||
{
|
||||
blockNumber: rpc.LatestBlockNumber,
|
||||
call: TransactionArgs{},
|
||||
overrides: StateOverride{
|
||||
randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))},
|
||||
overrides: override.StateOverride{
|
||||
randomAccounts[0].addr: override.OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))},
|
||||
},
|
||||
expectErr: nil,
|
||||
want: 53000,
|
||||
|
@ -700,8 +714,8 @@ func TestEstimateGas(t *testing.T) {
|
|||
To: &randomAccounts[1].addr,
|
||||
Value: (*hexutil.Big)(big.NewInt(1000)),
|
||||
},
|
||||
overrides: StateOverride{
|
||||
randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(big.NewInt(0))},
|
||||
overrides: override.StateOverride{
|
||||
randomAccounts[0].addr: override.OverrideAccount{Balance: newRPCBalance(big.NewInt(0))},
|
||||
},
|
||||
expectErr: core.ErrInsufficientFunds,
|
||||
},
|
||||
|
@ -758,16 +772,65 @@ func TestEstimateGas(t *testing.T) {
|
|||
},
|
||||
want: 21000,
|
||||
},
|
||||
// // SPDX-License-Identifier: GPL-3.0
|
||||
//pragma solidity >=0.8.2 <0.9.0;
|
||||
//
|
||||
//contract BlockOverridesTest {
|
||||
// function call() public view returns (uint256) {
|
||||
// return block.number;
|
||||
// }
|
||||
//
|
||||
// function estimate() public view {
|
||||
// revert(string.concat("block ", uint2str(block.number)));
|
||||
// }
|
||||
//
|
||||
// function uint2str(uint256 _i) internal pure returns (string memory str) {
|
||||
// if (_i == 0) {
|
||||
// return "0";
|
||||
// }
|
||||
// uint256 j = _i;
|
||||
// uint256 length;
|
||||
// while (j != 0) {
|
||||
// length++;
|
||||
// j /= 10;
|
||||
// }
|
||||
// bytes memory bstr = new bytes(length);
|
||||
// uint256 k = length;
|
||||
// j = _i;
|
||||
// while (j != 0) {
|
||||
// bstr[--k] = bytes1(uint8(48 + (j % 10)));
|
||||
// j /= 10;
|
||||
// }
|
||||
// str = string(bstr);
|
||||
// }
|
||||
//}
|
||||
{
|
||||
blockNumber: rpc.LatestBlockNumber,
|
||||
call: TransactionArgs{
|
||||
From: &accounts[0].addr,
|
||||
To: &accounts[1].addr,
|
||||
Data: hex2Bytes("0x3592d016"), //estimate
|
||||
},
|
||||
overrides: override.StateOverride{
|
||||
accounts[1].addr: override.OverrideAccount{
|
||||
Code: hex2Bytes("608060405234801561000f575f5ffd5b5060043610610034575f3560e01c806328b5e32b146100385780633592d0161461004b575b5f5ffd5b4360405190815260200160405180910390f35b610053610055565b005b61005e4361009d565b60405160200161006e91906101a5565b60408051601f198184030181529082905262461bcd60e51b8252610094916004016101cd565b60405180910390fd5b6060815f036100c35750506040805180820190915260018152600360fc1b602082015290565b815f5b81156100ec57806100d681610216565b91506100e59050600a83610242565b91506100c6565b5f8167ffffffffffffffff81111561010657610106610255565b6040519080825280601f01601f191660200182016040528015610130576020820181803683370190505b508593509050815b831561019c57610149600a85610269565b61015490603061027c565b60f81b8261016183610295565b92508281518110610174576101746102aa565b60200101906001600160f81b03191690815f1a905350610195600a85610242565b9350610138565b50949350505050565b650313637b1b5960d51b81525f82518060208501600685015e5f920160060191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b634e487b7160e01b5f52601160045260245ffd5b5f6001820161022757610227610202565b5060010190565b634e487b7160e01b5f52601260045260245ffd5b5f826102505761025061022e565b500490565b634e487b7160e01b5f52604160045260245ffd5b5f826102775761027761022e565b500690565b8082018082111561028f5761028f610202565b92915050565b5f816102a3576102a3610202565b505f190190565b634e487b7160e01b5f52603260045260245ffdfea2646970667358221220a253cad1e2e3523b8c053c1d0cd1e39d7f3bafcedd73440a244872701f05dab264736f6c634300081c0033"),
|
||||
},
|
||||
},
|
||||
blockOverrides: override.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(11))},
|
||||
expectErr: newRevertError(packRevert("block 11")),
|
||||
},
|
||||
}
|
||||
for i, tc := range testSuite {
|
||||
result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides)
|
||||
result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides)
|
||||
if tc.expectErr != nil {
|
||||
if err == nil {
|
||||
t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr)
|
||||
continue
|
||||
}
|
||||
if !errors.Is(err, tc.expectErr) {
|
||||
t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err)
|
||||
if !reflect.DeepEqual(err, tc.expectErr) {
|
||||
t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err)
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
@ -818,9 +881,9 @@ func TestCall(t *testing.T) {
|
|||
var testSuite = []struct {
|
||||
name string
|
||||
blockNumber rpc.BlockNumber
|
||||
overrides StateOverride
|
||||
overrides override.StateOverride
|
||||
call TransactionArgs
|
||||
blockOverrides BlockOverrides
|
||||
blockOverrides override.BlockOverrides
|
||||
expectErr error
|
||||
want string
|
||||
}{
|
||||
|
@ -880,8 +943,8 @@ func TestCall(t *testing.T) {
|
|||
To: &randomAccounts[1].addr,
|
||||
Value: (*hexutil.Big)(big.NewInt(1000)),
|
||||
},
|
||||
overrides: StateOverride{
|
||||
randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))},
|
||||
overrides: override.StateOverride{
|
||||
randomAccounts[0].addr: override.OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))},
|
||||
},
|
||||
want: "0x",
|
||||
},
|
||||
|
@ -920,27 +983,60 @@ func TestCall(t *testing.T) {
|
|||
To: &randomAccounts[2].addr,
|
||||
Data: hex2Bytes("8381f58a"), // call number()
|
||||
},
|
||||
overrides: StateOverride{
|
||||
randomAccounts[2].addr: OverrideAccount{
|
||||
overrides: override.StateOverride{
|
||||
randomAccounts[2].addr: override.OverrideAccount{
|
||||
Code: hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033"),
|
||||
StateDiff: map[common.Hash]common.Hash{{}: common.BigToHash(big.NewInt(123))},
|
||||
},
|
||||
},
|
||||
want: "0x000000000000000000000000000000000000000000000000000000000000007b",
|
||||
},
|
||||
// Block overrides should work
|
||||
// // SPDX-License-Identifier: GPL-3.0
|
||||
//pragma solidity >=0.8.2 <0.9.0;
|
||||
//
|
||||
//contract BlockOverridesTest {
|
||||
// function call() public view returns (uint256) {
|
||||
// return block.number;
|
||||
// }
|
||||
//
|
||||
// function estimate() public view {
|
||||
// revert(string.concat("block ", uint2str(block.number)));
|
||||
// }
|
||||
//
|
||||
// function uint2str(uint256 _i) internal pure returns (string memory str) {
|
||||
// if (_i == 0) {
|
||||
// return "0";
|
||||
// }
|
||||
// uint256 j = _i;
|
||||
// uint256 length;
|
||||
// while (j != 0) {
|
||||
// length++;
|
||||
// j /= 10;
|
||||
// }
|
||||
// bytes memory bstr = new bytes(length);
|
||||
// uint256 k = length;
|
||||
// j = _i;
|
||||
// while (j != 0) {
|
||||
// bstr[--k] = bytes1(uint8(48 + (j % 10)));
|
||||
// j /= 10;
|
||||
// }
|
||||
// str = string(bstr);
|
||||
// }
|
||||
//}
|
||||
{
|
||||
name: "block-override",
|
||||
name: "block-override-with-state-override",
|
||||
blockNumber: rpc.LatestBlockNumber,
|
||||
call: TransactionArgs{
|
||||
From: &accounts[1].addr,
|
||||
Input: &hexutil.Bytes{
|
||||
0x43, // NUMBER
|
||||
0x60, 0x00, 0x52, // MSTORE offset 0
|
||||
0x60, 0x20, 0x60, 0x00, 0xf3,
|
||||
To: &accounts[2].addr,
|
||||
Data: hex2Bytes("0x28b5e32b"), //call
|
||||
},
|
||||
overrides: override.StateOverride{
|
||||
accounts[2].addr: override.OverrideAccount{
|
||||
Code: hex2Bytes("608060405234801561000f575f5ffd5b5060043610610034575f3560e01c806328b5e32b146100385780633592d0161461004b575b5f5ffd5b4360405190815260200160405180910390f35b610053610055565b005b61005e4361009d565b60405160200161006e91906101a5565b60408051601f198184030181529082905262461bcd60e51b8252610094916004016101cd565b60405180910390fd5b6060815f036100c35750506040805180820190915260018152600360fc1b602082015290565b815f5b81156100ec57806100d681610216565b91506100e59050600a83610242565b91506100c6565b5f8167ffffffffffffffff81111561010657610106610255565b6040519080825280601f01601f191660200182016040528015610130576020820181803683370190505b508593509050815b831561019c57610149600a85610269565b61015490603061027c565b60f81b8261016183610295565b92508281518110610174576101746102aa565b60200101906001600160f81b03191690815f1a905350610195600a85610242565b9350610138565b50949350505050565b650313637b1b5960d51b81525f82518060208501600685015e5f920160060191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b634e487b7160e01b5f52601160045260245ffd5b5f6001820161022757610227610202565b5060010190565b634e487b7160e01b5f52601260045260245ffd5b5f826102505761025061022e565b500490565b634e487b7160e01b5f52604160045260245ffd5b5f826102775761027761022e565b500690565b8082018082111561028f5761028f610202565b92915050565b5f816102a3576102a3610202565b505f190190565b634e487b7160e01b5f52603260045260245ffdfea2646970667358221220a253cad1e2e3523b8c053c1d0cd1e39d7f3bafcedd73440a244872701f05dab264736f6c634300081c0033"),
|
||||
},
|
||||
},
|
||||
blockOverrides: BlockOverrides{Number: (*hexutil.Big)(big.NewInt(11))},
|
||||
blockOverrides: override.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(11))},
|
||||
want: "0x000000000000000000000000000000000000000000000000000000000000000b",
|
||||
},
|
||||
// Clear storage trie
|
||||
|
@ -963,8 +1059,8 @@ func TestCall(t *testing.T) {
|
|||
// }
|
||||
Input: hex2Bytes("610dad6000813103600f57600080fd5b6000548060005260206000f3"),
|
||||
},
|
||||
overrides: StateOverride{
|
||||
dad: OverrideAccount{
|
||||
overrides: override.StateOverride{
|
||||
dad: override.OverrideAccount{
|
||||
State: map[common.Hash]common.Hash{},
|
||||
},
|
||||
},
|
||||
|
@ -991,7 +1087,7 @@ func TestCall(t *testing.T) {
|
|||
BlobHashes: []common.Hash{{0x01, 0x22}},
|
||||
BlobFeeCap: (*hexutil.Big)(big.NewInt(1)),
|
||||
},
|
||||
overrides: StateOverride{
|
||||
overrides: override.StateOverride{
|
||||
randomAccounts[2].addr: {
|
||||
Code: hex2Bytes("60004960005260206000f3"),
|
||||
},
|
||||
|
@ -1017,8 +1113,8 @@ func TestCall(t *testing.T) {
|
|||
// }
|
||||
Input: hex2Bytes("610dad6000813103600f57600080fd5b6000548060005260206000f3"),
|
||||
},
|
||||
overrides: StateOverride{
|
||||
dad: OverrideAccount{
|
||||
overrides: override.StateOverride{
|
||||
dad: override.OverrideAccount{
|
||||
State: map[common.Hash]common.Hash{},
|
||||
},
|
||||
},
|
||||
|
@ -1172,8 +1268,8 @@ func TestSimulateV1(t *testing.T) {
|
|||
name: "simple",
|
||||
tag: latest,
|
||||
blocks: []simBlock{{
|
||||
StateOverrides: &StateOverride{
|
||||
randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(big.NewInt(1000))},
|
||||
StateOverrides: &override.StateOverride{
|
||||
randomAccounts[0].addr: override.OverrideAccount{Balance: newRPCBalance(big.NewInt(1000))},
|
||||
},
|
||||
Calls: []TransactionArgs{{
|
||||
From: &randomAccounts[0].addr,
|
||||
|
@ -1215,8 +1311,8 @@ func TestSimulateV1(t *testing.T) {
|
|||
name: "simple-multi-block",
|
||||
tag: latest,
|
||||
blocks: []simBlock{{
|
||||
StateOverrides: &StateOverride{
|
||||
randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(big.NewInt(2000))},
|
||||
StateOverrides: &override.StateOverride{
|
||||
randomAccounts[0].addr: override.OverrideAccount{Balance: newRPCBalance(big.NewInt(2000))},
|
||||
},
|
||||
Calls: []TransactionArgs{
|
||||
{
|
||||
|
@ -1230,8 +1326,8 @@ func TestSimulateV1(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}, {
|
||||
StateOverrides: &StateOverride{
|
||||
randomAccounts[3].addr: OverrideAccount{Balance: newRPCBalance(big.NewInt(0))},
|
||||
StateOverrides: &override.StateOverride{
|
||||
randomAccounts[3].addr: override.OverrideAccount{Balance: newRPCBalance(big.NewInt(0))},
|
||||
},
|
||||
Calls: []TransactionArgs{
|
||||
{
|
||||
|
@ -1289,8 +1385,8 @@ func TestSimulateV1(t *testing.T) {
|
|||
name: "evm-error",
|
||||
tag: latest,
|
||||
blocks: []simBlock{{
|
||||
StateOverrides: &StateOverride{
|
||||
randomAccounts[2].addr: OverrideAccount{Code: hex2Bytes("f3")},
|
||||
StateOverrides: &override.StateOverride{
|
||||
randomAccounts[2].addr: override.OverrideAccount{Code: hex2Bytes("f3")},
|
||||
},
|
||||
Calls: []TransactionArgs{{
|
||||
From: &randomAccounts[0].addr,
|
||||
|
@ -1316,7 +1412,7 @@ func TestSimulateV1(t *testing.T) {
|
|||
name: "block-overrides",
|
||||
tag: latest,
|
||||
blocks: []simBlock{{
|
||||
BlockOverrides: &BlockOverrides{
|
||||
BlockOverrides: &override.BlockOverrides{
|
||||
Number: (*hexutil.Big)(big.NewInt(11)),
|
||||
FeeRecipient: &cac,
|
||||
},
|
||||
|
@ -1331,7 +1427,7 @@ func TestSimulateV1(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}, {
|
||||
BlockOverrides: &BlockOverrides{
|
||||
BlockOverrides: &override.BlockOverrides{
|
||||
Number: (*hexutil.Big)(big.NewInt(12)),
|
||||
},
|
||||
Calls: []TransactionArgs{{
|
||||
|
@ -1374,7 +1470,7 @@ func TestSimulateV1(t *testing.T) {
|
|||
name: "block-number-order",
|
||||
tag: latest,
|
||||
blocks: []simBlock{{
|
||||
BlockOverrides: &BlockOverrides{
|
||||
BlockOverrides: &override.BlockOverrides{
|
||||
Number: (*hexutil.Big)(big.NewInt(12)),
|
||||
},
|
||||
Calls: []TransactionArgs{{
|
||||
|
@ -1386,7 +1482,7 @@ func TestSimulateV1(t *testing.T) {
|
|||
},
|
||||
}},
|
||||
}, {
|
||||
BlockOverrides: &BlockOverrides{
|
||||
BlockOverrides: &override.BlockOverrides{
|
||||
Number: (*hexutil.Big)(big.NewInt(11)),
|
||||
},
|
||||
Calls: []TransactionArgs{{
|
||||
|
@ -1406,8 +1502,8 @@ func TestSimulateV1(t *testing.T) {
|
|||
name: "storage-contract",
|
||||
tag: latest,
|
||||
blocks: []simBlock{{
|
||||
StateOverrides: &StateOverride{
|
||||
randomAccounts[2].addr: OverrideAccount{
|
||||
StateOverrides: &override.StateOverride{
|
||||
randomAccounts[2].addr: override.OverrideAccount{
|
||||
Code: hex2Bytes("608060405234801561001057600080fd5b50600436106100365760003560e01c80632e64cec11461003b5780636057361d14610059575b600080fd5b610043610075565b60405161005091906100d9565b60405180910390f35b610073600480360381019061006e919061009d565b61007e565b005b60008054905090565b8060008190555050565b60008135905061009781610103565b92915050565b6000602082840312156100b3576100b26100fe565b5b60006100c184828501610088565b91505092915050565b6100d3816100f4565b82525050565b60006020820190506100ee60008301846100ca565b92915050565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea2646970667358221220404e37f487a89a932dca5e77faaf6ca2de3b991f93d230604b1b8daaef64766264736f6c63430008070033"),
|
||||
},
|
||||
},
|
||||
|
@ -1448,8 +1544,8 @@ func TestSimulateV1(t *testing.T) {
|
|||
name: "logs",
|
||||
tag: latest,
|
||||
blocks: []simBlock{{
|
||||
StateOverrides: &StateOverride{
|
||||
randomAccounts[2].addr: OverrideAccount{
|
||||
StateOverrides: &override.StateOverride{
|
||||
randomAccounts[2].addr: override.OverrideAccount{
|
||||
// Yul code:
|
||||
// object "Test" {
|
||||
// code {
|
||||
|
@ -1490,8 +1586,8 @@ func TestSimulateV1(t *testing.T) {
|
|||
name: "ecrecover-override",
|
||||
tag: latest,
|
||||
blocks: []simBlock{{
|
||||
StateOverrides: &StateOverride{
|
||||
randomAccounts[2].addr: OverrideAccount{
|
||||
StateOverrides: &override.StateOverride{
|
||||
randomAccounts[2].addr: override.OverrideAccount{
|
||||
// Yul code that returns ecrecover(0, 0, 0, 0).
|
||||
// object "Test" {
|
||||
// code {
|
||||
|
@ -1518,7 +1614,7 @@ func TestSimulateV1(t *testing.T) {
|
|||
// }
|
||||
Code: hex2Bytes("6040516000815260006020820152600060408201526000606082015260208160808360015afa60008103603157600080fd5b601482f3"),
|
||||
},
|
||||
common.BytesToAddress([]byte{0x01}): OverrideAccount{
|
||||
common.BytesToAddress([]byte{0x01}): override.OverrideAccount{
|
||||
// Yul code that returns the address of the caller.
|
||||
// object "Test" {
|
||||
// code {
|
||||
|
@ -1555,8 +1651,8 @@ func TestSimulateV1(t *testing.T) {
|
|||
name: "precompile-move",
|
||||
tag: latest,
|
||||
blocks: []simBlock{{
|
||||
StateOverrides: &StateOverride{
|
||||
sha256Address: OverrideAccount{
|
||||
StateOverrides: &override.StateOverride{
|
||||
sha256Address: override.OverrideAccount{
|
||||
// Yul code that returns the calldata.
|
||||
// object "Test" {
|
||||
// code {
|
||||
|
@ -1610,8 +1706,8 @@ func TestSimulateV1(t *testing.T) {
|
|||
name: "transfer-logs",
|
||||
tag: latest,
|
||||
blocks: []simBlock{{
|
||||
StateOverrides: &StateOverride{
|
||||
randomAccounts[0].addr: OverrideAccount{
|
||||
StateOverrides: &override.StateOverride{
|
||||
randomAccounts[0].addr: override.OverrideAccount{
|
||||
Balance: newRPCBalance(big.NewInt(100)),
|
||||
// Yul code that transfers 100 wei to address passed in calldata:
|
||||
// object "Test" {
|
||||
|
@ -1753,8 +1849,8 @@ func TestSimulateV1(t *testing.T) {
|
|||
name: "validation-checks-from-contract",
|
||||
tag: latest,
|
||||
blocks: []simBlock{{
|
||||
StateOverrides: &StateOverride{
|
||||
randomAccounts[2].addr: OverrideAccount{
|
||||
StateOverrides: &override.StateOverride{
|
||||
randomAccounts[2].addr: override.OverrideAccount{
|
||||
Balance: newRPCBalance(big.NewInt(2098640803896784)),
|
||||
Code: hex2Bytes("00"),
|
||||
Nonce: newUint64(1),
|
||||
|
@ -1788,11 +1884,11 @@ func TestSimulateV1(t *testing.T) {
|
|||
name: "validation-checks-success",
|
||||
tag: latest,
|
||||
blocks: []simBlock{{
|
||||
BlockOverrides: &BlockOverrides{
|
||||
BlockOverrides: &override.BlockOverrides{
|
||||
BaseFeePerGas: (*hexutil.Big)(big.NewInt(1)),
|
||||
},
|
||||
StateOverrides: &StateOverride{
|
||||
randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(big.NewInt(10000000))},
|
||||
StateOverrides: &override.StateOverride{
|
||||
randomAccounts[0].addr: override.OverrideAccount{Balance: newRPCBalance(big.NewInt(10000000))},
|
||||
},
|
||||
Calls: []TransactionArgs{{
|
||||
From: &randomAccounts[0].addr,
|
||||
|
@ -1821,7 +1917,7 @@ func TestSimulateV1(t *testing.T) {
|
|||
name: "clear-storage",
|
||||
tag: latest,
|
||||
blocks: []simBlock{{
|
||||
StateOverrides: &StateOverride{
|
||||
StateOverrides: &override.StateOverride{
|
||||
randomAccounts[2].addr: {
|
||||
Code: newBytes(genesis.Alloc[bab].Code),
|
||||
StateDiff: map[common.Hash]common.Hash{
|
||||
|
@ -1843,7 +1939,7 @@ func TestSimulateV1(t *testing.T) {
|
|||
To: &bab,
|
||||
}},
|
||||
}, {
|
||||
StateOverrides: &StateOverride{
|
||||
StateOverrides: &override.StateOverride{
|
||||
randomAccounts[2].addr: {
|
||||
State: map[common.Hash]common.Hash{
|
||||
common.BigToHash(big.NewInt(1)): common.BigToHash(big.NewInt(5)),
|
||||
|
@ -1890,10 +1986,10 @@ func TestSimulateV1(t *testing.T) {
|
|||
name: "blockhash-opcode",
|
||||
tag: latest,
|
||||
blocks: []simBlock{{
|
||||
BlockOverrides: &BlockOverrides{
|
||||
BlockOverrides: &override.BlockOverrides{
|
||||
Number: (*hexutil.Big)(big.NewInt(12)),
|
||||
},
|
||||
StateOverrides: &StateOverride{
|
||||
StateOverrides: &override.StateOverride{
|
||||
randomAccounts[2].addr: {
|
||||
Code: hex2Bytes("600035804060008103601057600080fd5b5050"),
|
||||
},
|
||||
|
@ -1915,7 +2011,7 @@ func TestSimulateV1(t *testing.T) {
|
|||
Input: uint256ToBytes(uint256.NewInt(10)),
|
||||
}},
|
||||
}, {
|
||||
BlockOverrides: &BlockOverrides{
|
||||
BlockOverrides: &override.BlockOverrides{
|
||||
Number: (*hexutil.Big)(big.NewInt(16)),
|
||||
},
|
||||
Calls: []TransactionArgs{{
|
||||
|
@ -2005,7 +2101,7 @@ func TestSimulateV1(t *testing.T) {
|
|||
name: "basefee-non-validation",
|
||||
tag: latest,
|
||||
blocks: []simBlock{{
|
||||
StateOverrides: &StateOverride{
|
||||
StateOverrides: &override.StateOverride{
|
||||
randomAccounts[2].addr: {
|
||||
// Yul code:
|
||||
// object "Test" {
|
||||
|
@ -2040,7 +2136,7 @@ func TestSimulateV1(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}, {
|
||||
BlockOverrides: &BlockOverrides{
|
||||
BlockOverrides: &override.BlockOverrides{
|
||||
BaseFeePerGas: (*hexutil.Big)(big.NewInt(1)),
|
||||
},
|
||||
Calls: []TransactionArgs{{
|
||||
|
@ -2113,7 +2209,7 @@ func TestSimulateV1(t *testing.T) {
|
|||
name: "basefee-validation-mode",
|
||||
tag: latest,
|
||||
blocks: []simBlock{{
|
||||
StateOverrides: &StateOverride{
|
||||
StateOverrides: &override.StateOverride{
|
||||
randomAccounts[2].addr: {
|
||||
// Yul code:
|
||||
// object "Test" {
|
||||
|
@ -3286,97 +3382,6 @@ func TestRPCGetBlockReceipts(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
type precompileContract struct{}
|
||||
|
||||
func (p *precompileContract) RequiredGas(input []byte) uint64 { return 0 }
|
||||
|
||||
func (p *precompileContract) Run(input []byte) ([]byte, error) { return nil, nil }
|
||||
|
||||
func TestStateOverrideMovePrecompile(t *testing.T) {
|
||||
db := state.NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil), nil)
|
||||
statedb, err := state.New(common.Hash{}, db)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create statedb: %v", err)
|
||||
}
|
||||
precompiles := map[common.Address]vm.PrecompiledContract{
|
||||
common.BytesToAddress([]byte{0x1}): &precompileContract{},
|
||||
common.BytesToAddress([]byte{0x2}): &precompileContract{},
|
||||
}
|
||||
bytes2Addr := func(b []byte) *common.Address {
|
||||
a := common.BytesToAddress(b)
|
||||
return &a
|
||||
}
|
||||
var testSuite = []struct {
|
||||
overrides StateOverride
|
||||
expectedPrecompiles map[common.Address]struct{}
|
||||
fail bool
|
||||
}{
|
||||
{
|
||||
overrides: StateOverride{
|
||||
common.BytesToAddress([]byte{0x1}): {
|
||||
Code: hex2Bytes("0xff"),
|
||||
MovePrecompileTo: bytes2Addr([]byte{0x2}),
|
||||
},
|
||||
common.BytesToAddress([]byte{0x2}): {
|
||||
Code: hex2Bytes("0x00"),
|
||||
},
|
||||
},
|
||||
// 0x2 has already been touched by the moveTo.
|
||||
fail: true,
|
||||
}, {
|
||||
overrides: StateOverride{
|
||||
common.BytesToAddress([]byte{0x1}): {
|
||||
Code: hex2Bytes("0xff"),
|
||||
MovePrecompileTo: bytes2Addr([]byte{0xff}),
|
||||
},
|
||||
common.BytesToAddress([]byte{0x3}): {
|
||||
Code: hex2Bytes("0x00"),
|
||||
MovePrecompileTo: bytes2Addr([]byte{0xfe}),
|
||||
},
|
||||
},
|
||||
// 0x3 is not a precompile.
|
||||
fail: true,
|
||||
}, {
|
||||
overrides: StateOverride{
|
||||
common.BytesToAddress([]byte{0x1}): {
|
||||
Code: hex2Bytes("0xff"),
|
||||
MovePrecompileTo: bytes2Addr([]byte{0xff}),
|
||||
},
|
||||
common.BytesToAddress([]byte{0x2}): {
|
||||
Code: hex2Bytes("0x00"),
|
||||
MovePrecompileTo: bytes2Addr([]byte{0xfe}),
|
||||
},
|
||||
},
|
||||
expectedPrecompiles: map[common.Address]struct{}{common.BytesToAddress([]byte{0xfe}): {}, common.BytesToAddress([]byte{0xff}): {}},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range testSuite {
|
||||
cpy := maps.Clone(precompiles)
|
||||
// Apply overrides
|
||||
err := tt.overrides.Apply(statedb, cpy)
|
||||
if tt.fail {
|
||||
if err == nil {
|
||||
t.Errorf("test %d: want error, have nothing", i)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("test %d: want no error, have %v", i, err)
|
||||
continue
|
||||
}
|
||||
// Precompile keys
|
||||
if len(cpy) != len(tt.expectedPrecompiles) {
|
||||
t.Errorf("test %d: precompile mismatch, want %d, have %d", i, len(tt.expectedPrecompiles), len(cpy))
|
||||
}
|
||||
for k := range tt.expectedPrecompiles {
|
||||
if _, ok := cpy[k]; !ok {
|
||||
t.Errorf("test %d: precompile not found: %s", i, k.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testRPCResponseWithFile(t *testing.T, testid int, result interface{}, rpc string, file string) {
|
||||
data, err := json.MarshalIndent(result, "", " ")
|
||||
if err != nil {
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
// 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 override
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"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/vm"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// 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"`
|
||||
MovePrecompileTo *common.Address `json:"movePrecompileToAddress"`
|
||||
}
|
||||
|
||||
// StateOverride is the collection of overridden accounts.
|
||||
type StateOverride map[common.Address]OverrideAccount
|
||||
|
||||
func (diff *StateOverride) has(address common.Address) bool {
|
||||
_, ok := (*diff)[address]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Apply overrides the fields of specified accounts into the given state.
|
||||
func (diff *StateOverride) Apply(statedb *state.StateDB, precompiles vm.PrecompiledContracts) error {
|
||||
if diff == nil {
|
||||
return nil
|
||||
}
|
||||
// Tracks destinations of precompiles that were moved.
|
||||
dirtyAddrs := make(map[common.Address]struct{})
|
||||
for addr, account := range *diff {
|
||||
// If a precompile was moved to this address already, it can't be overridden.
|
||||
if _, ok := dirtyAddrs[addr]; ok {
|
||||
return fmt.Errorf("account %s has already been overridden by a precompile", addr.Hex())
|
||||
}
|
||||
p, isPrecompile := precompiles[addr]
|
||||
// The MoveTo feature makes it possible to move a precompile
|
||||
// code to another address. If the target address is another precompile
|
||||
// the code for the latter is lost for this session.
|
||||
// Note the destination account is not cleared upon move.
|
||||
if account.MovePrecompileTo != nil {
|
||||
if !isPrecompile {
|
||||
return fmt.Errorf("account %s is not a precompile", addr.Hex())
|
||||
}
|
||||
// Refuse to move a precompile to an address that has been
|
||||
// or will be overridden.
|
||||
if diff.has(*account.MovePrecompileTo) {
|
||||
return fmt.Errorf("account %s is already overridden", account.MovePrecompileTo.Hex())
|
||||
}
|
||||
precompiles[*account.MovePrecompileTo] = p
|
||||
dirtyAddrs[*account.MovePrecompileTo] = struct{}{}
|
||||
}
|
||||
if isPrecompile {
|
||||
delete(precompiles, addr)
|
||||
}
|
||||
// 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.
|
||||
type BlockOverrides struct {
|
||||
Number *hexutil.Big
|
||||
Difficulty *hexutil.Big // No-op if we're simulating post-merge calls.
|
||||
Time *hexutil.Uint64
|
||||
GasLimit *hexutil.Uint64
|
||||
FeeRecipient *common.Address
|
||||
PrevRandao *common.Hash
|
||||
BaseFeePerGas *hexutil.Big
|
||||
BlobBaseFee *hexutil.Big
|
||||
}
|
||||
|
||||
// Apply overrides the given header fields into the given block context.
|
||||
func (o *BlockOverrides) Apply(blockCtx *vm.BlockContext) {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
if o.Number != nil {
|
||||
blockCtx.BlockNumber = o.Number.ToInt()
|
||||
}
|
||||
if o.Difficulty != nil {
|
||||
blockCtx.Difficulty = o.Difficulty.ToInt()
|
||||
}
|
||||
if o.Time != nil {
|
||||
blockCtx.Time = uint64(*o.Time)
|
||||
}
|
||||
if o.GasLimit != nil {
|
||||
blockCtx.GasLimit = uint64(*o.GasLimit)
|
||||
}
|
||||
if o.FeeRecipient != nil {
|
||||
blockCtx.Coinbase = *o.FeeRecipient
|
||||
}
|
||||
if o.PrevRandao != nil {
|
||||
blockCtx.Random = o.PrevRandao
|
||||
}
|
||||
if o.BaseFeePerGas != nil {
|
||||
blockCtx.BaseFee = o.BaseFeePerGas.ToInt()
|
||||
}
|
||||
if o.BlobBaseFee != nil {
|
||||
blockCtx.BlobBaseFee = o.BlobBaseFee.ToInt()
|
||||
}
|
||||
}
|
||||
|
||||
// MakeHeader returns a new header object with the overridden
|
||||
// fields.
|
||||
// Note: MakeHeader ignores BlobBaseFee if set. That's because
|
||||
// header has no such field.
|
||||
func (o *BlockOverrides) MakeHeader(header *types.Header) *types.Header {
|
||||
if o == nil {
|
||||
return header
|
||||
}
|
||||
h := types.CopyHeader(header)
|
||||
if o.Number != nil {
|
||||
h.Number = o.Number.ToInt()
|
||||
}
|
||||
if o.Difficulty != nil {
|
||||
h.Difficulty = o.Difficulty.ToInt()
|
||||
}
|
||||
if o.Time != nil {
|
||||
h.Time = uint64(*o.Time)
|
||||
}
|
||||
if o.GasLimit != nil {
|
||||
h.GasLimit = uint64(*o.GasLimit)
|
||||
}
|
||||
if o.FeeRecipient != nil {
|
||||
h.Coinbase = *o.FeeRecipient
|
||||
}
|
||||
if o.PrevRandao != nil {
|
||||
h.MixDigest = *o.PrevRandao
|
||||
}
|
||||
if o.BaseFeePerGas != nil {
|
||||
h.BaseFee = o.BaseFeePerGas.ToInt()
|
||||
}
|
||||
return h
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
// 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 override
|
||||
|
||||
import (
|
||||
"maps"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/triedb"
|
||||
)
|
||||
|
||||
type precompileContract struct{}
|
||||
|
||||
func (p *precompileContract) RequiredGas(input []byte) uint64 { return 0 }
|
||||
|
||||
func (p *precompileContract) Run(input []byte) ([]byte, error) { return nil, nil }
|
||||
|
||||
func TestStateOverrideMovePrecompile(t *testing.T) {
|
||||
db := state.NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil), nil)
|
||||
statedb, err := state.New(common.Hash{}, db)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create statedb: %v", err)
|
||||
}
|
||||
precompiles := map[common.Address]vm.PrecompiledContract{
|
||||
common.BytesToAddress([]byte{0x1}): &precompileContract{},
|
||||
common.BytesToAddress([]byte{0x2}): &precompileContract{},
|
||||
}
|
||||
bytes2Addr := func(b []byte) *common.Address {
|
||||
a := common.BytesToAddress(b)
|
||||
return &a
|
||||
}
|
||||
var testSuite = []struct {
|
||||
overrides StateOverride
|
||||
expectedPrecompiles map[common.Address]struct{}
|
||||
fail bool
|
||||
}{
|
||||
{
|
||||
overrides: StateOverride{
|
||||
common.BytesToAddress([]byte{0x1}): {
|
||||
Code: hex2Bytes("0xff"),
|
||||
MovePrecompileTo: bytes2Addr([]byte{0x2}),
|
||||
},
|
||||
common.BytesToAddress([]byte{0x2}): {
|
||||
Code: hex2Bytes("0x00"),
|
||||
},
|
||||
},
|
||||
// 0x2 has already been touched by the moveTo.
|
||||
fail: true,
|
||||
}, {
|
||||
overrides: StateOverride{
|
||||
common.BytesToAddress([]byte{0x1}): {
|
||||
Code: hex2Bytes("0xff"),
|
||||
MovePrecompileTo: bytes2Addr([]byte{0xff}),
|
||||
},
|
||||
common.BytesToAddress([]byte{0x3}): {
|
||||
Code: hex2Bytes("0x00"),
|
||||
MovePrecompileTo: bytes2Addr([]byte{0xfe}),
|
||||
},
|
||||
},
|
||||
// 0x3 is not a precompile.
|
||||
fail: true,
|
||||
}, {
|
||||
overrides: StateOverride{
|
||||
common.BytesToAddress([]byte{0x1}): {
|
||||
Code: hex2Bytes("0xff"),
|
||||
MovePrecompileTo: bytes2Addr([]byte{0xff}),
|
||||
},
|
||||
common.BytesToAddress([]byte{0x2}): {
|
||||
Code: hex2Bytes("0x00"),
|
||||
MovePrecompileTo: bytes2Addr([]byte{0xfe}),
|
||||
},
|
||||
},
|
||||
expectedPrecompiles: map[common.Address]struct{}{common.BytesToAddress([]byte{0xfe}): {}, common.BytesToAddress([]byte{0xff}): {}},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range testSuite {
|
||||
cpy := maps.Clone(precompiles)
|
||||
// Apply overrides
|
||||
err := tt.overrides.Apply(statedb, cpy)
|
||||
if tt.fail {
|
||||
if err == nil {
|
||||
t.Errorf("test %d: want error, have nothing", i)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("test %d: want no error, have %v", i, err)
|
||||
continue
|
||||
}
|
||||
// Precompile keys
|
||||
if len(cpy) != len(tt.expectedPrecompiles) {
|
||||
t.Errorf("test %d: precompile mismatch, want %d, have %d", i, len(tt.expectedPrecompiles), len(cpy))
|
||||
}
|
||||
for k := range tt.expectedPrecompiles {
|
||||
if _, ok := cpy[k]; !ok {
|
||||
t.Errorf("test %d: precompile not found: %s", i, k.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func hex2Bytes(str string) *hexutil.Bytes {
|
||||
rpcBytes := hexutil.Bytes(common.FromHex(str))
|
||||
return &rpcBytes
|
||||
}
|
|
@ -33,6 +33,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi/override"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
|
@ -49,8 +50,8 @@ const (
|
|||
|
||||
// simBlock is a batch of calls to be simulated sequentially.
|
||||
type simBlock struct {
|
||||
BlockOverrides *BlockOverrides
|
||||
StateOverrides *StateOverride
|
||||
BlockOverrides *override.BlockOverrides
|
||||
StateOverrides *override.StateOverride
|
||||
Calls []TransactionArgs
|
||||
}
|
||||
|
||||
|
@ -304,7 +305,7 @@ func (sim *simulator) sanitizeChain(blocks []simBlock) ([]simBlock, error) {
|
|||
)
|
||||
for _, block := range blocks {
|
||||
if block.BlockOverrides == nil {
|
||||
block.BlockOverrides = new(BlockOverrides)
|
||||
block.BlockOverrides = new(override.BlockOverrides)
|
||||
}
|
||||
if block.BlockOverrides.Number == nil {
|
||||
n := new(big.Int).Add(prevNumber, big.NewInt(1))
|
||||
|
@ -324,7 +325,7 @@ func (sim *simulator) sanitizeChain(blocks []simBlock) ([]simBlock, error) {
|
|||
for i := uint64(0); i < gap.Uint64(); i++ {
|
||||
n := new(big.Int).Add(prevNumber, big.NewInt(int64(i+1)))
|
||||
t := prevTimestamp + timestampIncrement
|
||||
b := simBlock{BlockOverrides: &BlockOverrides{Number: (*hexutil.Big)(n), Time: (*hexutil.Uint64)(&t)}}
|
||||
b := simBlock{BlockOverrides: &override.BlockOverrides{Number: (*hexutil.Big)(n), Time: (*hexutil.Uint64)(&t)}}
|
||||
prevTimestamp = t
|
||||
res = append(res, b)
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi/override"
|
||||
)
|
||||
|
||||
func TestSimulateSanitizeBlockOrder(t *testing.T) {
|
||||
|
@ -45,37 +46,37 @@ func TestSimulateSanitizeBlockOrder(t *testing.T) {
|
|||
{
|
||||
baseNumber: 10,
|
||||
baseTimestamp: 50,
|
||||
blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(13), Time: newUint64(70)}}, {}},
|
||||
blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(70)}}, {}},
|
||||
expected: []result{{number: 11, timestamp: 51}, {number: 12, timestamp: 52}, {number: 13, timestamp: 70}, {number: 14, timestamp: 71}},
|
||||
},
|
||||
{
|
||||
baseNumber: 10,
|
||||
baseTimestamp: 50,
|
||||
blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(11)}}, {BlockOverrides: &BlockOverrides{Number: newInt(14)}}, {}},
|
||||
blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(11)}}, {BlockOverrides: &override.BlockOverrides{Number: newInt(14)}}, {}},
|
||||
expected: []result{{number: 11, timestamp: 51}, {number: 12, timestamp: 52}, {number: 13, timestamp: 53}, {number: 14, timestamp: 54}, {number: 15, timestamp: 55}},
|
||||
},
|
||||
{
|
||||
baseNumber: 10,
|
||||
baseTimestamp: 50,
|
||||
blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(13)}}, {BlockOverrides: &BlockOverrides{Number: newInt(12)}}},
|
||||
blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(13)}}, {BlockOverrides: &override.BlockOverrides{Number: newInt(12)}}},
|
||||
err: "block numbers must be in order: 12 <= 13",
|
||||
},
|
||||
{
|
||||
baseNumber: 10,
|
||||
baseTimestamp: 50,
|
||||
blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(13), Time: newUint64(52)}}},
|
||||
blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(52)}}},
|
||||
err: "block timestamps must be in order: 52 <= 52",
|
||||
},
|
||||
{
|
||||
baseNumber: 10,
|
||||
baseTimestamp: 50,
|
||||
blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(11), Time: newUint64(60)}}, {BlockOverrides: &BlockOverrides{Number: newInt(12), Time: newUint64(55)}}},
|
||||
blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(11), Time: newUint64(60)}}, {BlockOverrides: &override.BlockOverrides{Number: newInt(12), Time: newUint64(55)}}},
|
||||
err: "block timestamps must be in order: 55 <= 60",
|
||||
},
|
||||
{
|
||||
baseNumber: 10,
|
||||
baseTimestamp: 50,
|
||||
blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(11), Time: newUint64(60)}}, {BlockOverrides: &BlockOverrides{Number: newInt(13), Time: newUint64(61)}}},
|
||||
blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(11), Time: newUint64(60)}}, {BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(61)}}},
|
||||
err: "block timestamps must be in order: 61 <= 61",
|
||||
},
|
||||
} {
|
||||
|
|
|
@ -160,7 +160,7 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend, skipGas
|
|||
BlobHashes: args.BlobHashes,
|
||||
}
|
||||
latestBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
|
||||
estimated, err := DoEstimateGas(ctx, b, callArgs, latestBlockNr, nil, b.RPCGasCap())
|
||||
estimated, err := DoEstimateGas(ctx, b, callArgs, latestBlockNr, nil, nil, b.RPCGasCap())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -503,8 +503,8 @@ web3._extend({
|
|||
new web3._extend.Method({
|
||||
name: 'estimateGas',
|
||||
call: 'eth_estimateGas',
|
||||
params: 3,
|
||||
inputFormatter: [web3._extend.formatters.inputCallFormatter, web3._extend.formatters.inputBlockNumberFormatter, null],
|
||||
params: 4,
|
||||
inputFormatter: [web3._extend.formatters.inputCallFormatter, web3._extend.formatters.inputBlockNumberFormatter, null, null],
|
||||
outputFormatter: web3._extend.utils.toDecimal
|
||||
}),
|
||||
new web3._extend.Method({
|
||||
|
|
Loading…
Reference in New Issue