diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go
index 3d5259b894df..af3ffb6e27b2 100644
--- a/accounts/abi/bind/backends/simulated.go
+++ b/accounts/abi/bind/backends/simulated.go
@@ -65,7 +65,7 @@ type SimulatedBackend struct {
mu sync.Mutex
pendingBlock *types.Block // Currently pending block that will be imported on request
- pendingState *state.StateDB // Currently pending state that will be the active on request
+ pendingState state.StateDBI // Currently pending state that will be the active on request
pendingReceipts types.Receipts // Currently receipts for the pending block
events *filters.EventSystem // for filtering log events live
@@ -179,7 +179,7 @@ func (b *SimulatedBackend) Fork(ctx context.Context, parent common.Hash) error {
}
// stateByBlockNumber retrieves a state by a given blocknumber.
-func (b *SimulatedBackend) stateByBlockNumber(ctx context.Context, blockNumber *big.Int) (*state.StateDB, error) {
+func (b *SimulatedBackend) stateByBlockNumber(ctx context.Context, blockNumber *big.Int) (state.StateDBI, error) {
if blockNumber == nil || blockNumber.Cmp(b.blockchain.CurrentBlock().Number) == 0 {
return b.blockchain.State()
}
@@ -605,7 +605,7 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs
// callContract implements common code between normal and pending contract calls.
// state is modified during execution, make sure to copy it if necessary.
-func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, header *types.Header, stateDB *state.StateDB) (*core.ExecutionResult, error) {
+func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, header *types.Header, stateDB state.StateDBI) (*core.ExecutionResult, error) {
// Gas prices post 1559 need to be initialized
if call.GasPrice != nil && (call.GasFeeCap != nil || call.GasTipCap != nil) {
return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go
index df3f52a403e7..20ffbd3ab48d 100644
--- a/accounts/abi/bind/base.go
+++ b/accounts/abi/bind/base.go
@@ -334,12 +334,13 @@ func (c *BoundContract) createLegacyTx(opts *TransactOpts, contract *common.Addr
func (c *BoundContract) estimateGasLimit(opts *TransactOpts, contract *common.Address, input []byte, gasPrice, gasTipCap, gasFeeCap, value *big.Int) (uint64, error) {
if contract != nil {
// Gas estimation cannot succeed without code for method invocations.
- if code, err := c.transactor.PendingCodeAt(ensureContext(opts.Context), c.address); err != nil {
+ if _, err := c.transactor.PendingCodeAt(ensureContext(opts.Context), c.address); err != nil {
return 0, err
- } else if len(code) == 0 {
- return 0, ErrNoCode
}
+
+ // if the contract code has length 0, we assume it is a precompile contract.
}
+
msg := ethereum.CallMsg{
From: opts.From,
To: contract,
@@ -349,6 +350,7 @@ func (c *BoundContract) estimateGasLimit(opts *TransactOpts, contract *common.Ad
Value: value,
Data: input,
}
+
return c.transactor.EstimateGas(ensureContext(opts.Context), msg)
}
@@ -400,6 +402,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
if opts.NoSend {
return signedTx, nil
}
+
if err := c.transactor.SendTransaction(ensureContext(opts.Context), signedTx); err != nil {
return nil, err
}
diff --git a/cmd/clef/main.go b/cmd/clef/main.go
index 2788ddc33b9e..e71c2e538edc 100644
--- a/cmd/clef/main.go
+++ b/cmd/clef/main.go
@@ -41,7 +41,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/internal/ethapi"
+ "github.com/ethereum/go-ethereum/ethapi"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go
index 5f796c1d6639..aa4528fea5c6 100644
--- a/cmd/evm/internal/t8ntool/execution.go
+++ b/cmd/evm/internal/t8ntool/execution.go
@@ -108,7 +108,7 @@ type rejectedTx struct {
// Apply applies a set of transactions to a pre-state
func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
txs types.Transactions, miningReward int64,
- getTracerFn func(txIndex int, txHash common.Hash) (tracer vm.EVMLogger, err error)) (*state.StateDB, *ExecutionResult, error) {
+ getTracerFn func(txIndex int, txHash common.Hash) (tracer vm.EVMLogger, err error)) (state.StateDBI, *ExecutionResult, error) {
// Capture errors for BLOCKHASH operation, if we haven't been supplied the
// required blockhashes
var hashError error
@@ -292,7 +292,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
return statedb, execRs, nil
}
-func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB {
+func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) state.StateDBI {
sdb := state.NewDatabaseWithConfig(db, &trie.Config{Preimages: true})
statedb, _ := state.New(common.Hash{}, sdb, nil)
for addr, a := range accounts {
diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go
index 3a010da9f2dc..ce84f0cc28de 100644
--- a/cmd/evm/runner.go
+++ b/cmd/evm/runner.go
@@ -120,7 +120,7 @@ func runCmd(ctx *cli.Context) error {
var (
tracer vm.EVMLogger
debugLogger *logger.StructLogger
- statedb *state.StateDB
+ statedb state.StateDBI
chainConfig *params.ChainConfig
sender = common.BytesToAddress([]byte("sender"))
receiver = common.BytesToAddress([]byte("receiver"))
diff --git a/cmd/geth/config.go b/cmd/geth/config.go
index 0b856d1c1b7a..29bd13e9e53a 100644
--- a/cmd/geth/config.go
+++ b/cmd/geth/config.go
@@ -33,7 +33,7 @@ import (
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/ethconfig"
- "github.com/ethereum/go-ethereum/internal/ethapi"
+ "github.com/ethereum/go-ethereum/ethapi"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/internal/version"
"github.com/ethereum/go-ethereum/log"
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index 5ba070249897..d7bdfd995d60 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -32,9 +32,9 @@ import (
"github.com/ethereum/go-ethereum/console/prompt"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/eth/downloader"
+ "github.com/ethereum/go-ethereum/ethapi"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/internal/debug"
- "github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 08de71ee831b..c2d0532739c5 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -53,11 +53,11 @@ import (
"github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/eth/gasprice"
"github.com/ethereum/go-ethereum/eth/tracers"
+ "github.com/ethereum/go-ethereum/ethapi"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethdb/remotedb"
"github.com/ethereum/go-ethereum/ethstats"
"github.com/ethereum/go-ethereum/graphql"
- "github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/les"
lescatalyst "github.com/ethereum/go-ethereum/les/catalyst"
@@ -2032,8 +2032,12 @@ func RegisterGraphQLService(stack *node.Node, backend ethapi.Backend, filterSyst
}
}
+type NetworkingStack interface {
+ RegisterAPIs([]rpc.API)
+}
+
// RegisterFilterAPI adds the eth log filtering RPC API to the node.
-func RegisterFilterAPI(stack *node.Node, backend ethapi.Backend, ethcfg *ethconfig.Config) *filters.FilterSystem {
+func RegisterFilterAPI(stack NetworkingStack, backend ethapi.Backend, ethcfg *ethconfig.Config) *filters.FilterSystem {
isLightClient := ethcfg.SyncMode == downloader.LightSync
filterSystem := filters.NewFilterSystem(backend, filters.Config{
LogCacheSize: ethcfg.FilterLogCacheSize,
diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go
index eb5aa58ca887..0a59c296dd8a 100644
--- a/consensus/beacon/consensus.go
+++ b/consensus/beacon/consensus.go
@@ -327,7 +327,7 @@ func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.H
}
// Finalize implements consensus.Engine, setting the final state on the header
-func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) {
+func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state state.StateDBI, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) {
// Finalize is different with Prepare, it can be used in both block generation
// and verification. So determine the consensus rules by header type.
if !beacon.IsPoSHeader(header) {
@@ -348,7 +348,7 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.
// FinalizeAndAssemble implements consensus.Engine, setting the final state and
// assembling the block.
-func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) {
+func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state state.StateDBI, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) {
// FinalizeAndAssemble is different with Prepare, it can be used in both block
// generation and verification. So determine the consensus rules by header type.
if !beacon.IsPoSHeader(header) {
diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go
index 4706bbac1ca9..e25fa2d869c4 100644
--- a/consensus/clique/clique.go
+++ b/consensus/clique/clique.go
@@ -567,7 +567,7 @@ func (c *Clique) Prepare(chain consensus.ChainHeaderReader, header *types.Header
// Finalize implements consensus.Engine, ensuring no uncles are set, nor block
// rewards given.
-func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) {
+func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state state.StateDBI, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) {
// No block rewards in PoA, so the state remains as is and uncles are dropped
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
header.UncleHash = types.CalcUncleHash(nil)
@@ -575,7 +575,7 @@ func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Heade
// FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set,
// nor block rewards given, and returns the final block.
-func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) {
+func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state state.StateDBI, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) {
if len(withdrawals) > 0 {
return nil, errors.New("clique does not support withdrawals")
}
diff --git a/consensus/consensus.go b/consensus/consensus.go
index 190d5ae12c8a..31cf037aaf36 100644
--- a/consensus/consensus.go
+++ b/consensus/consensus.go
@@ -89,7 +89,7 @@ type Engine interface {
//
// Note: The block header and state database might be updated to reflect any
// consensus rules that happen at finalization (e.g. block rewards).
- Finalize(chain ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction,
+ Finalize(chain ChainHeaderReader, header *types.Header, state state.StateDBI, txs []*types.Transaction,
uncles []*types.Header, withdrawals []*types.Withdrawal)
// FinalizeAndAssemble runs any post-transaction state modifications (e.g. block
@@ -97,7 +97,7 @@ type Engine interface {
//
// Note: The block header and state database might be updated to reflect any
// consensus rules that happen at finalization (e.g. block rewards).
- FinalizeAndAssemble(chain ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction,
+ FinalizeAndAssemble(chain ChainHeaderReader, header *types.Header, state state.StateDBI, txs []*types.Transaction,
uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error)
// Seal generates a new sealing request for the given input block and pushes
diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go
index da29e16597b6..705756a9f617 100644
--- a/consensus/ethash/consensus.go
+++ b/consensus/ethash/consensus.go
@@ -600,7 +600,7 @@ func (ethash *Ethash) Prepare(chain consensus.ChainHeaderReader, header *types.H
// Finalize implements consensus.Engine, accumulating the block and uncle rewards,
// setting the final state on the header
-func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) {
+func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state state.StateDBI, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) {
// Accumulate any block and uncle rewards and commit the final state root
accumulateRewards(chain.Config(), state, header, uncles)
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
@@ -608,7 +608,7 @@ func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.
// FinalizeAndAssemble implements consensus.Engine, accumulating the block and
// uncle rewards, setting the final state and assembling the block.
-func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) {
+func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state state.StateDBI, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, withdrawals []*types.Withdrawal) (*types.Block, error) {
if len(withdrawals) > 0 {
return nil, errors.New("ethash does not support withdrawals")
}
@@ -658,7 +658,7 @@ var (
// AccumulateRewards credits the coinbase of the given block with the mining
// reward. The total reward consists of the static block reward and rewards for
// included uncles. The coinbase of each uncle block is also rewarded.
-func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, uncles []*types.Header) {
+func accumulateRewards(config *params.ChainConfig, state state.StateDBI, header *types.Header, uncles []*types.Header) {
// Select the correct block reward based on chain progression
blockReward := FrontierBlockReward
if config.IsByzantium(header.Number) {
diff --git a/consensus/misc/dao.go b/consensus/misc/dao.go
index 96995616de56..d436303c983e 100644
--- a/consensus/misc/dao.go
+++ b/consensus/misc/dao.go
@@ -72,7 +72,7 @@ func VerifyDAOHeaderExtraData(config *params.ChainConfig, header *types.Header)
// ApplyDAOHardFork modifies the state database according to the DAO hard-fork
// rules, transferring all balances of a set of DAO accounts to a single refund
// contract.
-func ApplyDAOHardFork(statedb *state.StateDB) {
+func ApplyDAOHardFork(statedb state.StateDBI) {
// Retrieve the contract to refund balances into
if !statedb.Exist(params.DAORefundContract) {
statedb.CreateAccount(params.DAORefundContract)
diff --git a/core/block_validator.go b/core/block_validator.go
index db7ea3568723..a79d1db978cf 100644
--- a/core/block_validator.go
+++ b/core/block_validator.go
@@ -94,7 +94,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
// transition, such as amount of used gas, the receipt roots and the state root
// itself. ValidateState returns a database batch if the validation was a success
// otherwise nil and an error is returned.
-func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64) error {
+func (v *BlockValidator) ValidateState(block *types.Block, statedb state.StateDBI, receipts types.Receipts, usedGas uint64) error {
header := block.Header()
if block.GasUsed() != usedGas {
return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas)
diff --git a/core/blockchain.go b/core/blockchain.go
index f22562ccfa94..99a38000ca9a 100644
--- a/core/blockchain.go
+++ b/core/blockchain.go
@@ -1333,7 +1333,7 @@ func (bc *BlockChain) writeKnownBlock(block *types.Block) error {
// writeBlockWithState writes block, metadata and corresponding state data to the
// database.
-func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) error {
+func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, state state.StateDBI) error {
// Calculate the total difficulty of the block
ptd := bc.GetTd(block.ParentHash(), block.NumberU64()-1)
if ptd == nil {
@@ -1416,7 +1416,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
// WriteBlockAndSetHead writes the given block and all associated state to the database,
// and applies the block as the new chain head.
-func (bc *BlockChain) WriteBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
+func (bc *BlockChain) WriteBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state state.StateDBI, emitHeadEvent bool) (status WriteStatus, err error) {
if !bc.chainmu.TryLock() {
return NonStatTy, errChainStopped
}
@@ -1427,7 +1427,7 @@ func (bc *BlockChain) WriteBlockAndSetHead(block *types.Block, receipts []*types
// writeBlockAndSetHead is the internal implementation of WriteBlockAndSetHead.
// This function expects the chain mutex to be held.
-func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
+func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state state.StateDBI, emitHeadEvent bool) (status WriteStatus, err error) {
if err := bc.writeBlockWithState(block, receipts, state); err != nil {
return NonStatTy, err
}
@@ -1656,7 +1656,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool)
return it.index, err
}
// No validation errors for the first block (or chain prefix skipped)
- var activeState *state.StateDB
+ var activeState state.StateDBI
defer func() {
// The chain importer is starting and stopping trie prefetchers. If a bad
// block or other error is hit however, an early return may not properly
@@ -1740,7 +1740,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool)
if followup, err := it.peek(); followup != nil && err == nil {
throwaway, _ := state.New(parent.Root, bc.stateCache, bc.snaps)
- go func(start time.Time, followup *types.Block, throwaway *state.StateDB, interrupt *uint32) {
+ go func(start time.Time, followup *types.Block, throwaway state.StateDBI, interrupt *uint32) {
bc.prefetcher.Prefetch(followup, throwaway, bc.vmConfig, &followupInterrupt)
blockPrefetchExecuteTimer.Update(time.Since(start))
diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go
index 21a9c6676bd5..897bd19eb7a9 100644
--- a/core/blockchain_reader.go
+++ b/core/blockchain_reader.go
@@ -314,12 +314,12 @@ func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) ([]byte, error) {
}
// State returns a new mutable state based on the current HEAD block.
-func (bc *BlockChain) State() (*state.StateDB, error) {
+func (bc *BlockChain) State() (state.StateDBI, error) {
return bc.StateAt(bc.CurrentBlock().Root)
}
// StateAt returns a new mutable state based on a particular point in time.
-func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) {
+func (bc *BlockChain) StateAt(root common.Hash) (state.StateDBI, error) {
return state.New(root, bc.stateCache, bc.snaps)
}
diff --git a/core/chain_makers.go b/core/chain_makers.go
index 61d0098af3f6..4e2b2f59d306 100644
--- a/core/chain_makers.go
+++ b/core/chain_makers.go
@@ -39,7 +39,7 @@ type BlockGen struct {
parent *types.Block
chain []*types.Block
header *types.Header
- statedb *state.StateDB
+ statedb state.StateDBI
gasPool *GasPool
txs []*types.Transaction
@@ -282,7 +282,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
}
blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n)
chainreader := &fakeChainReader{config: config}
- genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) {
+ genblock := func(i int, parent *types.Block, statedb state.StateDBI) (*types.Block, types.Receipts) {
b := &BlockGen{i: i, chain: blocks, parent: parent, statedb: statedb, config: config, engine: engine}
b.header = makeHeader(chainreader, parent, statedb, b.engine)
@@ -358,7 +358,7 @@ func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int,
return db, blocks, receipts
}
-func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.StateDB, engine consensus.Engine) *types.Header {
+func makeHeader(chain consensus.ChainReader, parent *types.Block, state state.StateDBI, engine consensus.Engine) *types.Header {
var time uint64
if parent.Time() == 0 {
time = 10
diff --git a/core/genesis.go b/core/genesis.go
index 269c1486d31d..aa712e520edc 100644
--- a/core/genesis.go
+++ b/core/genesis.go
@@ -128,6 +128,9 @@ func (ga *GenesisAlloc) deriveHash() (common.Hash, error) {
statedb.AddBalance(addr, account.Balance)
statedb.SetCode(addr, account.Code)
statedb.SetNonce(addr, account.Nonce)
+ if err := statedb.Error(); err != nil {
+ return common.Hash{}, err
+ }
for key, value := range account.Storage {
statedb.SetState(addr, key, value)
}
@@ -147,6 +150,9 @@ func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhas
statedb.AddBalance(addr, account.Balance)
statedb.SetCode(addr, account.Code)
statedb.SetNonce(addr, account.Nonce)
+ if err := statedb.Error(); err != nil {
+ return err
+ }
for key, value := range account.Storage {
statedb.SetState(addr, key, value)
}
diff --git a/core/state/access_list.go b/core/state/access_list.go
index 419469134595..0a61223b4b75 100644
--- a/core/state/access_list.go
+++ b/core/state/access_list.go
@@ -20,20 +20,20 @@ import (
"github.com/ethereum/go-ethereum/common"
)
-type accessList struct {
+type AccessList struct {
addresses map[common.Address]int
slots []map[common.Hash]struct{}
}
// ContainsAddress returns true if the address is in the access list.
-func (al *accessList) ContainsAddress(address common.Address) bool {
+func (al *AccessList) ContainsAddress(address common.Address) bool {
_, ok := al.addresses[address]
return ok
}
// Contains checks if a slot within an account is present in the access list, returning
// separate flags for the presence of the account and the slot respectively.
-func (al *accessList) Contains(address common.Address, slot common.Hash) (addressPresent bool, slotPresent bool) {
+func (al *AccessList) Contains(address common.Address, slot common.Hash) (addressPresent bool, slotPresent bool) {
idx, ok := al.addresses[address]
if !ok {
// no such address (and hence zero slots)
@@ -47,16 +47,16 @@ func (al *accessList) Contains(address common.Address, slot common.Hash) (addres
return true, slotPresent
}
-// newAccessList creates a new accessList.
-func newAccessList() *accessList {
- return &accessList{
+// NewAccessList creates a new AccessList.
+func NewAccessList() *AccessList {
+ return &AccessList{
addresses: make(map[common.Address]int),
}
}
-// Copy creates an independent copy of an accessList.
-func (a *accessList) Copy() *accessList {
- cp := newAccessList()
+// Copy creates an independent copy of an AccessList.
+func (a *AccessList) Copy() *AccessList {
+ cp := NewAccessList()
for k, v := range a.addresses {
cp.addresses[k] = v
}
@@ -73,7 +73,7 @@ func (a *accessList) Copy() *accessList {
// AddAddress adds an address to the access list, and returns 'true' if the operation
// caused a change (addr was not previously in the list).
-func (al *accessList) AddAddress(address common.Address) bool {
+func (al *AccessList) AddAddress(address common.Address) bool {
if _, present := al.addresses[address]; present {
return false
}
@@ -86,7 +86,7 @@ func (al *accessList) AddAddress(address common.Address) bool {
// - address added
// - slot added
// For any 'true' value returned, a corresponding journal entry must be made.
-func (al *accessList) AddSlot(address common.Address, slot common.Hash) (addrChange bool, slotChange bool) {
+func (al *AccessList) AddSlot(address common.Address, slot common.Hash) (addrChange bool, slotChange bool) {
idx, addrPresent := al.addresses[address]
if !addrPresent || idx == -1 {
// Address not present, or addr present but no slots there
@@ -110,7 +110,7 @@ func (al *accessList) AddSlot(address common.Address, slot common.Hash) (addrCha
// This operation needs to be performed in the same order as the addition happened.
// This method is meant to be used by the journal, which maintains ordering of
// operations.
-func (al *accessList) DeleteSlot(address common.Address, slot common.Hash) {
+func (al *AccessList) DeleteSlot(address common.Address, slot common.Hash) {
idx, addrOk := al.addresses[address]
// There are two ways this can fail
if !addrOk {
@@ -131,6 +131,6 @@ func (al *accessList) DeleteSlot(address common.Address, slot common.Hash) {
// needs to be performed in the same order as the addition happened.
// This method is meant to be used by the journal, which maintains ordering of
// operations.
-func (al *accessList) DeleteAddress(address common.Address) {
+func (al *AccessList) DeleteAddress(address common.Address) {
delete(al.addresses, address)
}
diff --git a/core/state/interface.go b/core/state/interface.go
new file mode 100644
index 000000000000..0f8b797344d2
--- /dev/null
+++ b/core/state/interface.go
@@ -0,0 +1,108 @@
+// Copyright 2014 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 .
+
+// Package state provides a caching layer atop the Ethereum state trie.
+
+package state
+
+import (
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/params"
+)
+
+// StateDBI is an EVM database for full state querying.
+type StateDBI interface {
+ CreateAccount(common.Address)
+
+ SubBalance(common.Address, *big.Int)
+ AddBalance(common.Address, *big.Int)
+ GetBalance(common.Address) *big.Int
+
+ GetNonce(common.Address) uint64
+ SetNonce(common.Address, uint64)
+
+ GetCodeHash(common.Address) common.Hash
+ GetCode(common.Address) []byte
+ SetCode(common.Address, []byte)
+ GetCodeSize(common.Address) int
+
+ AddRefund(uint64)
+ SubRefund(uint64)
+ GetRefund() uint64
+
+ GetCommittedState(common.Address, common.Hash) common.Hash
+ GetState(common.Address, common.Hash) common.Hash
+ SetState(common.Address, common.Hash, common.Hash)
+
+ GetTransientState(addr common.Address, key common.Hash) common.Hash
+ SetTransientState(addr common.Address, key, value common.Hash)
+
+ Suicide(common.Address) bool
+ HasSuicided(common.Address) bool
+
+ // Exist reports whether the given account exists in state.
+ // Notably this should also return true for suicided accounts.
+ Exist(common.Address) bool
+ // Empty returns whether the given account is empty. Empty
+ // is defined according to EIP161 (balance = nonce = code = 0).
+ Empty(common.Address) bool
+
+ AddressInAccessList(addr common.Address) bool
+ SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool)
+ // AddAddressToAccessList adds the given address to the access list. This operation is safe to perform
+ // even if the feature/fork is not active yet
+ AddAddressToAccessList(addr common.Address)
+ // AddSlotToAccessList adds the given (address,slot) to the access list. This operation is safe to perform
+ // even if the feature/fork is not active yet
+ AddSlotToAccessList(addr common.Address, slot common.Hash)
+ Prepare(rules params.Rules, sender, coinbase common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList)
+
+ RevertToSnapshot(int)
+ Snapshot() int
+
+ AddLog(*types.Log)
+ Logs() []*types.Log
+ GetLogs(hash common.Hash, blockNumber uint64, blockHash common.Hash) []*types.Log
+ TxIndex() int
+ AddPreimage(common.Hash, []byte)
+ Preimages() map[common.Hash][]byte
+
+ ForEachStorage(common.Address, func(common.Hash, common.Hash) bool) error
+
+ GetOrNewStateObject(addr common.Address) *StateObject
+
+ DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey []byte)
+ Dump(opts *DumpConfig) []byte
+ RawDump(opts *DumpConfig) Dump
+ IteratorDump(opts *DumpConfig) IteratorDump
+ Database() Database
+ StorageTrie(addr common.Address) (Trie, error)
+ Error() error
+ GetStorageProof(a common.Address, key common.Hash) ([][]byte, error)
+ GetProof(addr common.Address) ([][]byte, error)
+ SetBalance(addr common.Address, amount *big.Int)
+ SetStorage(addr common.Address, storage map[common.Hash]common.Hash)
+ Finalise(deleteEmptyObjects bool)
+ Commit(deleteEmptyObjects bool) (common.Hash, error)
+ Copy() StateDBI
+ SetTxContext(thash common.Hash, ti int)
+ StopPrefetcher()
+ StartPrefetcher(namespace string)
+ IntermediateRoot(deleteEmptyObjects bool) common.Hash
+}
diff --git a/core/state/journal.go b/core/state/journal.go
index 1722fb4c02e1..5feb6bb05c61 100644
--- a/core/state/journal.go
+++ b/core/state/journal.go
@@ -90,7 +90,7 @@ type (
account *common.Address
}
resetObjectChange struct {
- prev *stateObject
+ prev *StateObject
prevdestruct bool
}
suicideChange struct {
diff --git a/core/state/state_object.go b/core/state/state_object.go
index 5dfd3c1b648a..6c0023b25612 100644
--- a/core/state/state_object.go
+++ b/core/state/state_object.go
@@ -56,13 +56,13 @@ func (s Storage) Copy() Storage {
return cpy
}
-// stateObject represents an Ethereum account which is being modified.
+// StateObject represents an Ethereum account which is being modified.
//
// The usage pattern is as follows:
// First you need to obtain a state object.
// Account values can be accessed and modified through the object.
// Finally, call commitTrie to write the modified storage trie into a database.
-type stateObject struct {
+type StateObject struct {
address common.Address
addrHash common.Hash // hash of ethereum address of the account
data types.StateAccount
@@ -92,12 +92,12 @@ type stateObject struct {
}
// empty returns whether the account is considered empty.
-func (s *stateObject) empty() bool {
+func (s *StateObject) empty() bool {
return s.data.Nonce == 0 && s.data.Balance.Sign() == 0 && bytes.Equal(s.data.CodeHash, types.EmptyCodeHash.Bytes())
}
// newObject creates a state object.
-func newObject(db *StateDB, address common.Address, data types.StateAccount) *stateObject {
+func newObject(db *StateDB, address common.Address, data types.StateAccount) *StateObject {
if data.Balance == nil {
data.Balance = new(big.Int)
}
@@ -107,7 +107,7 @@ func newObject(db *StateDB, address common.Address, data types.StateAccount) *st
if data.Root == (common.Hash{}) {
data.Root = types.EmptyRootHash
}
- return &stateObject{
+ return &StateObject{
db: db,
address: address,
addrHash: crypto.Keccak256Hash(address[:]),
@@ -119,22 +119,22 @@ func newObject(db *StateDB, address common.Address, data types.StateAccount) *st
}
// EncodeRLP implements rlp.Encoder.
-func (s *stateObject) EncodeRLP(w io.Writer) error {
+func (s *StateObject) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, &s.data)
}
// setError remembers the first non-nil error it is called with.
-func (s *stateObject) setError(err error) {
+func (s *StateObject) setError(err error) {
if s.dbErr == nil {
s.dbErr = err
}
}
-func (s *stateObject) markSuicided() {
+func (s *StateObject) markSuicided() {
s.suicided = true
}
-func (s *stateObject) touch() {
+func (s *StateObject) touch() {
s.db.journal.append(touchChange{
account: &s.address,
})
@@ -148,7 +148,7 @@ func (s *stateObject) touch() {
// getTrie returns the associated storage trie. The trie will be opened
// if it's not loaded previously. An error will be returned if trie can't
// be loaded.
-func (s *stateObject) getTrie(db Database) (Trie, error) {
+func (s *StateObject) getTrie(db Database) (Trie, error) {
if s.trie == nil {
// Try fetching from prefetcher first
// We don't prefetch empty tries
@@ -169,7 +169,7 @@ func (s *stateObject) getTrie(db Database) (Trie, error) {
}
// GetState retrieves a value from the account storage trie.
-func (s *stateObject) GetState(db Database, key common.Hash) common.Hash {
+func (s *StateObject) GetState(db Database, key common.Hash) common.Hash {
// If we have a dirty value for this state entry, return it
value, dirty := s.dirtyStorage[key]
if dirty {
@@ -180,7 +180,7 @@ func (s *stateObject) GetState(db Database, key common.Hash) common.Hash {
}
// GetCommittedState retrieves a value from the committed account storage trie.
-func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Hash {
+func (s *StateObject) GetCommittedState(db Database, key common.Hash) common.Hash {
// If we have a pending write or clean cached, return that
if value, pending := s.pendingStorage[key]; pending {
return value
@@ -239,7 +239,7 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has
}
// SetState updates a value in account storage.
-func (s *stateObject) SetState(db Database, key, value common.Hash) {
+func (s *StateObject) SetState(db Database, key, value common.Hash) {
// If the new value is the same as old, don't set
prev := s.GetState(db, key)
if prev == value {
@@ -254,13 +254,13 @@ func (s *stateObject) SetState(db Database, key, value common.Hash) {
s.setState(key, value)
}
-func (s *stateObject) setState(key, value common.Hash) {
+func (s *StateObject) setState(key, value common.Hash) {
s.dirtyStorage[key] = value
}
// finalise moves all dirty storage slots into the pending area to be hashed or
// committed later. It is invoked at the end of every transaction.
-func (s *stateObject) finalise(prefetch bool) {
+func (s *StateObject) finalise(prefetch bool) {
slotsToPrefetch := make([][]byte, 0, len(s.dirtyStorage))
for key, value := range s.dirtyStorage {
s.pendingStorage[key] = value
@@ -279,7 +279,7 @@ func (s *stateObject) finalise(prefetch bool) {
// updateTrie writes cached storage modifications into the object's storage trie.
// It will return nil if the trie has not been loaded and no changes have been
// made. An error will be returned if the trie can't be loaded/updated correctly.
-func (s *stateObject) updateTrie(db Database) (Trie, error) {
+func (s *StateObject) updateTrie(db Database) (Trie, error) {
// Make sure all dirty slots are finalized into the pending storage area
s.finalise(false) // Don't prefetch anymore, pull directly if need be
if len(s.pendingStorage) == 0 {
@@ -348,7 +348,7 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) {
// UpdateRoot sets the trie root to the current root hash of. An error
// will be returned if trie root hash is not computed correctly.
-func (s *stateObject) updateRoot(db Database) {
+func (s *StateObject) updateRoot(db Database) {
tr, err := s.updateTrie(db)
if err != nil {
s.setError(fmt.Errorf("updateRoot (%x) error: %w", s.address, err))
@@ -367,7 +367,7 @@ func (s *stateObject) updateRoot(db Database) {
// commitTrie submits the storage changes into the storage trie and re-computes
// the root. Besides, all trie changes will be collected in a nodeset and returned.
-func (s *stateObject) commitTrie(db Database) (*trie.NodeSet, error) {
+func (s *StateObject) commitTrie(db Database) (*trie.NodeSet, error) {
tr, err := s.updateTrie(db)
if err != nil {
return nil, err
@@ -390,7 +390,7 @@ func (s *stateObject) commitTrie(db Database) (*trie.NodeSet, error) {
// AddBalance adds amount to s's balance.
// It is used to add funds to the destination account of a transfer.
-func (s *stateObject) AddBalance(amount *big.Int) {
+func (s *StateObject) AddBalance(amount *big.Int) {
// EIP161: We must check emptiness for the objects such that the account
// clearing (0,0,0 objects) can take effect.
if amount.Sign() == 0 {
@@ -404,14 +404,14 @@ func (s *stateObject) AddBalance(amount *big.Int) {
// SubBalance removes amount from s's balance.
// It is used to remove funds from the origin account of a transfer.
-func (s *stateObject) SubBalance(amount *big.Int) {
+func (s *StateObject) SubBalance(amount *big.Int) {
if amount.Sign() == 0 {
return
}
s.SetBalance(new(big.Int).Sub(s.Balance(), amount))
}
-func (s *stateObject) SetBalance(amount *big.Int) {
+func (s *StateObject) SetBalance(amount *big.Int) {
s.db.journal.append(balanceChange{
account: &s.address,
prev: new(big.Int).Set(s.data.Balance),
@@ -419,23 +419,23 @@ func (s *stateObject) SetBalance(amount *big.Int) {
s.setBalance(amount)
}
-func (s *stateObject) setBalance(amount *big.Int) {
+func (s *StateObject) setBalance(amount *big.Int) {
s.data.Balance = amount
}
-func (s *stateObject) deepCopy(db *StateDB) *stateObject {
- stateObject := newObject(db, s.address, s.data)
+func (s *StateObject) deepCopy(db *StateDB) *StateObject {
+ StateObject := newObject(db, s.address, s.data)
if s.trie != nil {
- stateObject.trie = db.db.CopyTrie(s.trie)
+ StateObject.trie = db.db.CopyTrie(s.trie)
}
- stateObject.code = s.code
- stateObject.dirtyStorage = s.dirtyStorage.Copy()
- stateObject.originStorage = s.originStorage.Copy()
- stateObject.pendingStorage = s.pendingStorage.Copy()
- stateObject.suicided = s.suicided
- stateObject.dirtyCode = s.dirtyCode
- stateObject.deleted = s.deleted
- return stateObject
+ StateObject.code = s.code
+ StateObject.dirtyStorage = s.dirtyStorage.Copy()
+ StateObject.originStorage = s.originStorage.Copy()
+ StateObject.pendingStorage = s.pendingStorage.Copy()
+ StateObject.suicided = s.suicided
+ StateObject.dirtyCode = s.dirtyCode
+ StateObject.deleted = s.deleted
+ return StateObject
}
//
@@ -443,12 +443,12 @@ func (s *stateObject) deepCopy(db *StateDB) *stateObject {
//
// Address returns the address of the contract/account
-func (s *stateObject) Address() common.Address {
+func (s *StateObject) Address() common.Address {
return s.address
}
// Code returns the contract code associated with this object, if any.
-func (s *stateObject) Code(db Database) []byte {
+func (s *StateObject) Code(db Database) []byte {
if s.code != nil {
return s.code
}
@@ -466,7 +466,7 @@ func (s *stateObject) Code(db Database) []byte {
// CodeSize returns the size of the contract code associated with this object,
// or zero if none. This method is an almost mirror of Code, but uses a cache
// inside the database to avoid loading codes seen recently.
-func (s *stateObject) CodeSize(db Database) int {
+func (s *StateObject) CodeSize(db Database) int {
if s.code != nil {
return len(s.code)
}
@@ -480,7 +480,7 @@ func (s *stateObject) CodeSize(db Database) int {
return size
}
-func (s *stateObject) SetCode(codeHash common.Hash, code []byte) {
+func (s *StateObject) SetCode(codeHash common.Hash, code []byte) {
prevcode := s.Code(s.db.db)
s.db.journal.append(codeChange{
account: &s.address,
@@ -490,13 +490,13 @@ func (s *stateObject) SetCode(codeHash common.Hash, code []byte) {
s.setCode(codeHash, code)
}
-func (s *stateObject) setCode(codeHash common.Hash, code []byte) {
+func (s *StateObject) setCode(codeHash common.Hash, code []byte) {
s.code = code
s.data.CodeHash = codeHash[:]
s.dirtyCode = true
}
-func (s *stateObject) SetNonce(nonce uint64) {
+func (s *StateObject) SetNonce(nonce uint64) {
s.db.journal.append(nonceChange{
account: &s.address,
prev: s.data.Nonce,
@@ -504,25 +504,25 @@ func (s *stateObject) SetNonce(nonce uint64) {
s.setNonce(nonce)
}
-func (s *stateObject) setNonce(nonce uint64) {
+func (s *StateObject) setNonce(nonce uint64) {
s.data.Nonce = nonce
}
-func (s *stateObject) CodeHash() []byte {
+func (s *StateObject) CodeHash() []byte {
return s.data.CodeHash
}
-func (s *stateObject) Balance() *big.Int {
+func (s *StateObject) Balance() *big.Int {
return s.data.Balance
}
-func (s *stateObject) Nonce() uint64 {
+func (s *StateObject) Nonce() uint64 {
return s.data.Nonce
}
-// Value is never called, but must be present to allow stateObject to be used
+// Value is never called, but must be present to allow StateObject to be used
// as a vm.Account interface that also satisfies the vm.ContractRef
// interface. Interfaces are awesome.
-func (s *stateObject) Value() *big.Int {
- panic("Value on stateObject should never be called")
+func (s *StateObject) Value() *big.Int {
+ panic("Value on StateObject should never be called")
}
diff --git a/core/state/state_test.go b/core/state/state_test.go
index b6b46e446fba..3f48fdd13fd5 100644
--- a/core/state/state_test.go
+++ b/core/state/state_test.go
@@ -205,7 +205,7 @@ func TestSnapshot2(t *testing.T) {
}
}
-func compareStateObjects(so0, so1 *stateObject, t *testing.T) {
+func compareStateObjects(so0, so1 *StateObject, t *testing.T) {
if so0.Address() != so1.Address() {
t.Fatalf("Address mismatch: have %v, want %v", so0.address, so1.address)
}
diff --git a/core/state/statedb.go b/core/state/statedb.go
index 3d8fd15bbd25..b92ad1035f02 100644
--- a/core/state/statedb.go
+++ b/core/state/statedb.go
@@ -73,7 +73,7 @@ type StateDB struct {
snapStorage map[common.Hash]map[common.Hash][]byte
// This map holds 'live' objects, which will get modified while processing a state transition.
- stateObjects map[common.Address]*stateObject
+ stateObjects map[common.Address]*StateObject
stateObjectsPending map[common.Address]struct{} // State objects finalized but not yet written to the trie
stateObjectsDirty map[common.Address]struct{} // State objects modified in the current execution
stateObjectsDestruct map[common.Address]struct{} // State objects destructed in the block
@@ -96,7 +96,7 @@ type StateDB struct {
preimages map[common.Hash][]byte
// Per-transaction access list
- accessList *accessList
+ accessList *AccessList
// Transient storage
transientStorage transientStorage
@@ -138,14 +138,14 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
trie: tr,
originalRoot: root,
snaps: snaps,
- stateObjects: make(map[common.Address]*stateObject),
+ stateObjects: make(map[common.Address]*StateObject),
stateObjectsPending: make(map[common.Address]struct{}),
stateObjectsDirty: make(map[common.Address]struct{}),
stateObjectsDestruct: make(map[common.Address]struct{}),
logs: make(map[common.Hash][]*types.Log),
preimages: make(map[common.Hash][]byte),
journal: newJournal(),
- accessList: newAccessList(),
+ accessList: NewAccessList(),
transientStorage: newTransientStorage(),
hasher: crypto.NewKeccakState(),
}
@@ -266,17 +266,17 @@ func (s *StateDB) Empty(addr common.Address) bool {
// GetBalance retrieves the balance from the given address or 0 if object not found
func (s *StateDB) GetBalance(addr common.Address) *big.Int {
- stateObject := s.getStateObject(addr)
- if stateObject != nil {
- return stateObject.Balance()
+ StateObject := s.getStateObject(addr)
+ if StateObject != nil {
+ return StateObject.Balance()
}
return common.Big0
}
func (s *StateDB) GetNonce(addr common.Address) uint64 {
- stateObject := s.getStateObject(addr)
- if stateObject != nil {
- return stateObject.Nonce()
+ StateObject := s.getStateObject(addr)
+ if StateObject != nil {
+ return StateObject.Nonce()
}
return 0
@@ -288,34 +288,34 @@ func (s *StateDB) TxIndex() int {
}
func (s *StateDB) GetCode(addr common.Address) []byte {
- stateObject := s.getStateObject(addr)
- if stateObject != nil {
- return stateObject.Code(s.db)
+ StateObject := s.getStateObject(addr)
+ if StateObject != nil {
+ return StateObject.Code(s.db)
}
return nil
}
func (s *StateDB) GetCodeSize(addr common.Address) int {
- stateObject := s.getStateObject(addr)
- if stateObject != nil {
- return stateObject.CodeSize(s.db)
+ StateObject := s.getStateObject(addr)
+ if StateObject != nil {
+ return StateObject.CodeSize(s.db)
}
return 0
}
func (s *StateDB) GetCodeHash(addr common.Address) common.Hash {
- stateObject := s.getStateObject(addr)
- if stateObject == nil {
+ StateObject := s.getStateObject(addr)
+ if StateObject == nil {
return common.Hash{}
}
- return common.BytesToHash(stateObject.CodeHash())
+ return common.BytesToHash(StateObject.CodeHash())
}
// GetState retrieves a value from the given account's storage trie.
func (s *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash {
- stateObject := s.getStateObject(addr)
- if stateObject != nil {
- return stateObject.GetState(s.db, hash)
+ StateObject := s.getStateObject(addr)
+ if StateObject != nil {
+ return StateObject.GetState(s.db, hash)
}
return common.Hash{}
}
@@ -351,9 +351,9 @@ func (s *StateDB) GetStorageProof(a common.Address, key common.Hash) ([][]byte,
// GetCommittedState retrieves a value from the given account's committed storage trie.
func (s *StateDB) GetCommittedState(addr common.Address, hash common.Hash) common.Hash {
- stateObject := s.getStateObject(addr)
- if stateObject != nil {
- return stateObject.GetCommittedState(s.db, hash)
+ StateObject := s.getStateObject(addr)
+ if StateObject != nil {
+ return StateObject.GetCommittedState(s.db, hash)
}
return common.Hash{}
}
@@ -367,11 +367,11 @@ func (s *StateDB) Database() Database {
// and is nil for non-existent accounts. An error will be returned if storage trie
// is existent but can't be loaded correctly.
func (s *StateDB) StorageTrie(addr common.Address) (Trie, error) {
- stateObject := s.getStateObject(addr)
- if stateObject == nil {
+ StateObject := s.getStateObject(addr)
+ if StateObject == nil {
return nil, nil
}
- cpy := stateObject.deepCopy(s)
+ cpy := StateObject.deepCopy(s)
if _, err := cpy.updateTrie(s.db); err != nil {
return nil, err
}
@@ -379,9 +379,9 @@ func (s *StateDB) StorageTrie(addr common.Address) (Trie, error) {
}
func (s *StateDB) HasSuicided(addr common.Address) bool {
- stateObject := s.getStateObject(addr)
- if stateObject != nil {
- return stateObject.suicided
+ StateObject := s.getStateObject(addr)
+ if StateObject != nil {
+ return StateObject.suicided
}
return false
}
@@ -392,45 +392,45 @@ func (s *StateDB) HasSuicided(addr common.Address) bool {
// AddBalance adds amount to the account associated with addr.
func (s *StateDB) AddBalance(addr common.Address, amount *big.Int) {
- stateObject := s.GetOrNewStateObject(addr)
- if stateObject != nil {
- stateObject.AddBalance(amount)
+ StateObject := s.GetOrNewStateObject(addr)
+ if StateObject != nil {
+ StateObject.AddBalance(amount)
}
}
// SubBalance subtracts amount from the account associated with addr.
func (s *StateDB) SubBalance(addr common.Address, amount *big.Int) {
- stateObject := s.GetOrNewStateObject(addr)
- if stateObject != nil {
- stateObject.SubBalance(amount)
+ StateObject := s.GetOrNewStateObject(addr)
+ if StateObject != nil {
+ StateObject.SubBalance(amount)
}
}
func (s *StateDB) SetBalance(addr common.Address, amount *big.Int) {
- stateObject := s.GetOrNewStateObject(addr)
- if stateObject != nil {
- stateObject.SetBalance(amount)
+ StateObject := s.GetOrNewStateObject(addr)
+ if StateObject != nil {
+ StateObject.SetBalance(amount)
}
}
func (s *StateDB) SetNonce(addr common.Address, nonce uint64) {
- stateObject := s.GetOrNewStateObject(addr)
- if stateObject != nil {
- stateObject.SetNonce(nonce)
+ StateObject := s.GetOrNewStateObject(addr)
+ if StateObject != nil {
+ StateObject.SetNonce(nonce)
}
}
func (s *StateDB) SetCode(addr common.Address, code []byte) {
- stateObject := s.GetOrNewStateObject(addr)
- if stateObject != nil {
- stateObject.SetCode(crypto.Keccak256Hash(code), code)
+ StateObject := s.GetOrNewStateObject(addr)
+ if StateObject != nil {
+ StateObject.SetCode(crypto.Keccak256Hash(code), code)
}
}
func (s *StateDB) SetState(addr common.Address, key, value common.Hash) {
- stateObject := s.GetOrNewStateObject(addr)
- if stateObject != nil {
- stateObject.SetState(s.db, key, value)
+ StateObject := s.GetOrNewStateObject(addr)
+ if StateObject != nil {
+ StateObject.SetState(s.db, key, value)
}
}
@@ -443,9 +443,9 @@ func (s *StateDB) SetStorage(addr common.Address, storage map[common.Hash]common
// will not hit disk, since it is assumed that the disk-data is belonging
// to a previous incarnation of the object.
s.stateObjectsDestruct[addr] = struct{}{}
- stateObject := s.GetOrNewStateObject(addr)
+ StateObject := s.GetOrNewStateObject(addr)
for k, v := range storage {
- stateObject.SetState(s.db, k, v)
+ StateObject.SetState(s.db, k, v)
}
}
@@ -455,17 +455,17 @@ func (s *StateDB) SetStorage(addr common.Address, storage map[common.Hash]common
// The account's state object is still available until the state is committed,
// getStateObject will return a non-nil account after Suicide.
func (s *StateDB) Suicide(addr common.Address) bool {
- stateObject := s.getStateObject(addr)
- if stateObject == nil {
+ StateObject := s.getStateObject(addr)
+ if StateObject == nil {
return false
}
s.journal.append(suicideChange{
account: &addr,
- prev: stateObject.suicided,
- prevbalance: new(big.Int).Set(stateObject.Balance()),
+ prev: StateObject.suicided,
+ prevbalance: new(big.Int).Set(StateObject.Balance()),
})
- stateObject.markSuicided()
- stateObject.data.Balance = new(big.Int)
+ StateObject.markSuicided()
+ StateObject.data.Balance = new(big.Int)
return true
}
@@ -504,7 +504,7 @@ func (s *StateDB) GetTransientState(addr common.Address, key common.Hash) common
//
// updateStateObject writes the given object to the trie.
-func (s *StateDB) updateStateObject(obj *stateObject) {
+func (s *StateDB) updateStateObject(obj *StateObject) {
// Track the amount of time wasted on updating the account from the trie
if metrics.EnabledExpensive {
defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now())
@@ -525,7 +525,7 @@ func (s *StateDB) updateStateObject(obj *stateObject) {
}
// deleteStateObject removes the given object from the state trie.
-func (s *StateDB) deleteStateObject(obj *stateObject) {
+func (s *StateDB) deleteStateObject(obj *StateObject) {
// Track the amount of time wasted on deleting the account from the trie
if metrics.EnabledExpensive {
defer func(start time.Time) { s.AccountUpdates += time.Since(start) }(time.Now())
@@ -540,7 +540,7 @@ func (s *StateDB) deleteStateObject(obj *stateObject) {
// getStateObject retrieves a state object given by the address, returning nil if
// the object is not found or was deleted in this execution context. If you need
// to differentiate between non-existent/just-deleted, use getDeletedStateObject.
-func (s *StateDB) getStateObject(addr common.Address) *stateObject {
+func (s *StateDB) getStateObject(addr common.Address) *StateObject {
if obj := s.getDeletedStateObject(addr); obj != nil && !obj.deleted {
return obj
}
@@ -551,7 +551,7 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject {
// nil for a deleted state object, it returns the actual object with the deleted
// flag set. This is needed by the state journal to revert to the correct s-
// destructed object instead of wiping all knowledge about the state object.
-func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
+func (s *StateDB) getDeletedStateObject(addr common.Address) *StateObject {
// Prefer live objects if any is available
if obj := s.stateObjects[addr]; obj != nil {
return obj
@@ -604,22 +604,22 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
return obj
}
-func (s *StateDB) setStateObject(object *stateObject) {
+func (s *StateDB) setStateObject(object *StateObject) {
s.stateObjects[object.Address()] = object
}
// GetOrNewStateObject retrieves a state object or create a new state object if nil.
-func (s *StateDB) GetOrNewStateObject(addr common.Address) *stateObject {
- stateObject := s.getStateObject(addr)
- if stateObject == nil {
- stateObject, _ = s.createObject(addr)
+func (s *StateDB) GetOrNewStateObject(addr common.Address) *StateObject {
+ StateObject := s.getStateObject(addr)
+ if StateObject == nil {
+ StateObject, _ = s.createObject(addr)
}
- return stateObject
+ return StateObject
}
// createObject creates a new state object. If there is an existing account with
// the given address, it is overwritten and returned as the second return value.
-func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) {
+func (s *StateDB) createObject(addr common.Address) (newobj, prev *StateObject) {
prev = s.getDeletedStateObject(addr) // Note, prev might have been deleted, we need that!
var prevdestruct bool
@@ -694,13 +694,13 @@ func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common
// Copy creates a deep, independent copy of the state.
// Snapshots of the copied state cannot be applied to the copy.
-func (s *StateDB) Copy() *StateDB {
+func (s *StateDB) Copy() StateDBI {
// Copy all the basic fields, initialize the memory ones
state := &StateDB{
db: s.db,
trie: s.db.CopyTrie(s.trie),
originalRoot: s.originalRoot,
- stateObjects: make(map[common.Address]*stateObject, len(s.journal.dirties)),
+ stateObjects: make(map[common.Address]*StateObject, len(s.journal.dirties)),
stateObjectsPending: make(map[common.Address]struct{}, len(s.stateObjectsPending)),
stateObjectsDirty: make(map[common.Address]struct{}, len(s.journal.dirties)),
stateObjectsDestruct: make(map[common.Address]struct{}, len(s.stateObjectsDestruct)),
@@ -1096,7 +1096,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) {
if rules.IsBerlin {
// Clear out any leftover from previous executions
- al := newAccessList()
+ al := NewAccessList()
s.accessList = al
al.AddAddress(sender)
diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go
index 8aa59e3ee592..b25976815a22 100644
--- a/core/state/statedb_test.go
+++ b/core/state/statedb_test.go
@@ -159,10 +159,10 @@ func TestCopy(t *testing.T) {
orig.Finalise(false)
// Copy the state
- copy := orig.Copy()
+ copy := orig.Copy().(*StateDB)
// Copy the copy state
- ccopy := copy.Copy()
+ ccopy := copy.Copy().(*StateDB)
// modify all in memory
for i := byte(0); i < 255; i++ {
@@ -542,7 +542,7 @@ func TestCopyCommitCopy(t *testing.T) {
t.Fatalf("initial committed storage slot mismatch: have %x, want %x", val, common.Hash{})
}
// Copy the non-committed state database and check pre/post commit balance
- copyOne := state.Copy()
+ copyOne := state.Copy().(*StateDB)
if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
t.Fatalf("first copy pre-commit balance mismatch: have %v, want %v", balance, 42)
}
@@ -628,7 +628,7 @@ func TestCopyCopyCommitCopy(t *testing.T) {
t.Fatalf("first copy committed storage slot mismatch: have %x, want %x", val, common.Hash{})
}
// Copy the copy and check the balance once more
- copyTwo := copyOne.Copy()
+ copyTwo := copyOne.Copy().(*StateDB)
if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
t.Fatalf("second copy pre-commit balance mismatch: have %v, want %v", balance, 42)
}
@@ -763,7 +763,7 @@ func TestStateDBAccessList(t *testing.T) {
memDb := rawdb.NewMemoryDatabase()
db := NewDatabase(memDb)
state, _ := New(common.Hash{}, db, nil)
- state.accessList = newAccessList()
+ state.accessList = NewAccessList()
verifyAddrs := func(astrings ...string) {
t.Helper()
@@ -914,7 +914,7 @@ func TestStateDBAccessList(t *testing.T) {
}
// Check the copy
// Make a copy
- state = stateCopy1
+ state = stateCopy1.(*StateDB)
verifyAddrs("aa", "bb")
verifySlots("bb", "01", "02")
if got, exp := len(state.accessList.addresses), 2; got != exp {
diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go
index c258eee4f4cc..59de9d8d24bd 100644
--- a/core/state_prefetcher.go
+++ b/core/state_prefetcher.go
@@ -47,7 +47,7 @@ func newStatePrefetcher(config *params.ChainConfig, bc *BlockChain, engine conse
// Prefetch processes the state changes according to the Ethereum rules by running
// the transaction messages using the statedb, but any changes are discarded. The
// only goal is to pre-cache transaction signatures and state trie nodes.
-func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, cfg vm.Config, interrupt *uint32) {
+func (p *statePrefetcher) Prefetch(block *types.Block, statedb state.StateDBI, cfg vm.Config, interrupt *uint32) {
var (
header = block.Header()
gaspool = new(GasPool).AddGas(block.GasLimit())
@@ -85,7 +85,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
// precacheTransaction attempts to apply a transaction to the given state database
// and uses the input parameters for its environment. The goal is not to execute
// the transaction successfully, rather to warm up touched data slots.
-func precacheTransaction(msg *Message, config *params.ChainConfig, gaspool *GasPool, statedb *state.StateDB, header *types.Header, evm *vm.EVM) error {
+func precacheTransaction(msg *Message, config *params.ChainConfig, gaspool *GasPool, statedb state.StateDBI, header *types.Header, evm *vm.EVM) error {
// Update the evm with the new transaction context.
evm.Reset(NewEVMTxContext(msg), statedb)
// Add addresses to access list if applicable
diff --git a/core/state_processor.go b/core/state_processor.go
index 2fa9c41bcc01..0ccff3f4193f 100644
--- a/core/state_processor.go
+++ b/core/state_processor.go
@@ -56,7 +56,7 @@ func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consen
// Process returns the receipts and logs accumulated during the process and
// returns the amount of gas that was used in the process. If any of the
// transactions failed to execute due to insufficient gas it will return an error.
-func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) {
+func (p *StateProcessor) Process(block *types.Block, statedb state.StateDBI, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) {
var (
receipts types.Receipts
usedGas = new(uint64)
@@ -79,7 +79,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
}
statedb.SetTxContext(tx.Hash(), i)
- receipt, err := applyTransaction(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv)
+ receipt, err := applyTransaction(vmenv, msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas)
if err != nil {
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
}
@@ -97,7 +97,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
return receipts, allLogs, *usedGas, nil
}
-func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) {
+func applyTransaction(
+ evm *vm.EVM, msg *Message, config *params.ChainConfig, gp *GasPool, statedb state.StateDBI,
+ blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64,
+) (*types.Receipt, error) {
// Create a new context to be used in the EVM environment.
txContext := NewEVMTxContext(msg)
evm.Reset(txContext, statedb)
@@ -142,11 +145,62 @@ func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, sta
return receipt, err
}
+func applyTransactionWithResult(
+ evm *vm.EVM, msg *Message, config *params.ChainConfig, gp *GasPool, statedb state.StateDBI,
+ blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64,
+) (*types.Receipt, *ExecutionResult, error) {
+ // Create a new context to be used in the EVM environment.
+ txContext := NewEVMTxContext(msg)
+ evm.Reset(txContext, statedb)
+
+ // Apply the transaction to the current state (included in the env).
+ result, err := ApplyMessage(evm, msg, gp)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ // Update the state with pending changes.
+ var root []byte
+ if config.IsByzantium(blockNumber) {
+ statedb.Finalise(true)
+ } else {
+ root = statedb.IntermediateRoot(config.IsEIP158(blockNumber)).Bytes()
+ }
+ *usedGas += result.UsedGas
+
+ // Create a new receipt for the transaction, storing the intermediate root and gas used
+ // by the tx.
+ receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: *usedGas}
+ if result.Failed() {
+ receipt.Status = types.ReceiptStatusFailed
+ } else {
+ receipt.Status = types.ReceiptStatusSuccessful
+ }
+ receipt.TxHash = tx.Hash()
+ receipt.GasUsed = result.UsedGas
+
+ // If the transaction created a contract, store the creation address in the receipt.
+ if msg.To == nil {
+ receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
+ }
+
+ // Set the receipt logs and create the bloom filter.
+ receipt.Logs = statedb.GetLogs(tx.Hash(), blockNumber.Uint64(), blockHash)
+ receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
+ receipt.BlockHash = blockHash
+ receipt.BlockNumber = blockNumber
+ receipt.TransactionIndex = uint(statedb.TxIndex())
+ return receipt, result, err
+}
+
// ApplyTransaction attempts to apply a transaction to the given state database
// and uses the input parameters for its environment. It returns the receipt
// for the transaction, gas used and an error if the transaction failed,
// indicating the block was invalid.
-func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) {
+func ApplyTransaction(
+ config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool,
+ statedb state.StateDBI, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config,
+) (*types.Receipt, error) {
msg, err := TransactionToMessage(tx, types.MakeSigner(config, header.Number), header.BaseFee)
if err != nil {
return nil, err
@@ -154,5 +208,41 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
// Create a new context to be used in the EVM environment
blockContext := NewEVMBlockContext(header, bc, author)
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg)
- return applyTransaction(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv)
+ return applyTransaction(vmenv, msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas)
+}
+
+func ApplyTransactionWithResult(
+ config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool,
+ statedb state.StateDBI, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config,
+) (*types.Receipt, *ExecutionResult, error) {
+ msg, err := TransactionToMessage(tx, types.MakeSigner(config, header.Number), header.BaseFee)
+ if err != nil {
+ return nil, nil, err
+ }
+ // Create a new context to be used in the EVM environment
+ blockContext := NewEVMBlockContext(header, bc, author)
+ vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg)
+ return applyTransactionWithResult(vmenv, msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas)
+}
+
+func ApplyTransactionWithEVM(
+ vmenv *vm.EVM, config *params.ChainConfig, gp *GasPool, statedb state.StateDBI,
+ header *types.Header, tx *types.Transaction, usedGas *uint64,
+) (*types.Receipt, error) {
+ msg, err := TransactionToMessage(tx, types.MakeSigner(config, header.Number), header.BaseFee)
+ if err != nil {
+ return nil, err
+ }
+ return applyTransaction(vmenv, msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas)
+}
+
+func ApplyTransactionWithEVMWithResult(
+ vmenv *vm.EVM, config *params.ChainConfig, gp *GasPool, statedb state.StateDBI,
+ baseFee *big.Int, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64,
+) (*types.Receipt, *ExecutionResult, error) {
+ msg, err := TransactionToMessage(tx, types.MakeSigner(config, blockNumber), baseFee)
+ if err != nil {
+ return nil, nil, err
+ }
+ return applyTransactionWithResult(vmenv, msg, config, gp, statedb, blockNumber, blockHash, tx, usedGas)
}
diff --git a/core/state_transition.go b/core/state_transition.go
index 1802f1daf70a..394264bf840d 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -244,7 +244,7 @@ func (st *StateTransition) buyGas() error {
st.initialGas = st.msg.GasLimit
st.state.SubBalance(st.msg.From, mgval)
- return nil
+ return st.state.Error()
}
func (st *StateTransition) preCheck() error {
@@ -361,7 +361,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
// Execute the preparatory steps for state transition which includes:
// - prepare accessList(post-berlin)
// - reset transient storage(eip 1153)
- st.state.Prepare(rules, msg.From, st.evm.Context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList)
+ st.state.Prepare(rules, msg.From, st.evm.Context.Coinbase, msg.To, st.evm.PrecompileManager.GetActive(&rules), msg.AccessList)
var (
ret []byte
@@ -372,6 +372,9 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
} else {
// Increment the nonce for the next transaction
st.state.SetNonce(msg.From, st.state.GetNonce(sender.Address())+1)
+ if err := st.state.Error(); err != nil {
+ return nil, err
+ }
ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, msg.Value)
}
@@ -395,6 +398,9 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
fee := new(big.Int).SetUint64(st.gasUsed())
fee.Mul(fee, effectiveTip)
st.state.AddBalance(st.evm.Context.Coinbase, fee)
+ if err := st.state.Error(); err != nil {
+ return nil, err
+ }
}
return &ExecutionResult{
diff --git a/core/txpool/noncer.go b/core/txpool/noncer.go
index ba7fbedad568..a355d1f82c21 100644
--- a/core/txpool/noncer.go
+++ b/core/txpool/noncer.go
@@ -27,13 +27,13 @@ import (
// accounts in the pool, falling back to reading from a real state database if
// an account is unknown.
type noncer struct {
- fallback *state.StateDB
+ fallback state.StateDBI
nonces map[common.Address]uint64
lock sync.Mutex
}
// newNoncer creates a new virtual state database to track the pool nonces.
-func newNoncer(statedb *state.StateDB) *noncer {
+func newNoncer(statedb state.StateDBI) *noncer {
return &noncer{
fallback: statedb.Copy(),
nonces: make(map[common.Address]uint64),
diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go
index 4306d5aee6f5..04d2fed361b0 100644
--- a/core/txpool/txpool.go
+++ b/core/txpool/txpool.go
@@ -156,7 +156,7 @@ const (
type blockChain interface {
CurrentBlock() *types.Header
GetBlock(hash common.Hash, number uint64) *types.Block
- StateAt(root common.Hash) (*state.StateDB, error)
+ StateAt(root common.Hash) (state.StateDBI, error)
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
}
@@ -257,7 +257,7 @@ type TxPool struct {
eip1559 bool // Fork indicator whether we are using EIP-1559 type transactions.
shanghai bool // Fork indicator whether we are in the Shanghai stage.
- currentState *state.StateDB // Current state in the blockchain head
+ currentState state.StateDBI // Current state in the blockchain head
pendingNonces *noncer // Pending state tracking virtual nonces
currentMaxGas uint64 // Current gas limit for transaction caps
diff --git a/core/txpool/txpool_test.go b/core/txpool/txpool_test.go
index c4c62db2d6da..fe95544b0902 100644
--- a/core/txpool/txpool_test.go
+++ b/core/txpool/txpool_test.go
@@ -60,7 +60,7 @@ func init() {
type testBlockChain struct {
gasLimit uint64 // must be first field for 64 bit alignment (atomic access)
- statedb *state.StateDB
+ statedb state.StateDBI
chainHeadFeed *event.Feed
}
@@ -75,7 +75,7 @@ func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block
return types.NewBlock(bc.CurrentBlock(), nil, nil, nil, trie.NewStackTrie(nil))
}
-func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) {
+func (bc *testBlockChain) StateAt(common.Hash) (state.StateDBI, error) {
return bc.statedb, nil
}
@@ -206,7 +206,7 @@ type testChain struct {
// testChain.State() is used multiple times to reset the pending state.
// when simulate is true it will create a state that indicates
// that tx0 and tx1 are included in the chain.
-func (c *testChain) State() (*state.StateDB, error) {
+func (c *testChain) State() (state.StateDBI, error) {
// delay "state change" by one. The tx pool fetches the
// state multiple times and by delaying it a bit we simulate
// a state change between those fetches.
diff --git a/core/types.go b/core/types.go
index 4c5b74a49865..0a8fa9da2f61 100644
--- a/core/types.go
+++ b/core/types.go
@@ -31,7 +31,7 @@ type Validator interface {
// ValidateState validates the given statedb and optionally the receipts and
// gas used.
- ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64) error
+ ValidateState(block *types.Block, state state.StateDBI, receipts types.Receipts, usedGas uint64) error
}
// Prefetcher is an interface for pre-caching transaction signatures and state.
@@ -39,7 +39,7 @@ type Prefetcher interface {
// Prefetch processes the state changes according to the Ethereum rules by running
// the transaction messages using the statedb, but any changes are discarded. The
// only goal is to pre-cache transaction signatures and state trie nodes.
- Prefetch(block *types.Block, statedb *state.StateDB, cfg vm.Config, interrupt *uint32)
+ Prefetch(block *types.Block, statedb state.StateDBI, cfg vm.Config, interrupt *uint32)
}
// Processor is an interface for processing blocks using a given initial state.
@@ -47,5 +47,5 @@ type Processor interface {
// Process processes the state changes according to the Ethereum rules by running
// the transaction messages using the statedb and applying any rewards to both
// the processor (coinbase) and any included uncles.
- Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error)
+ Process(block *types.Block, statedb state.StateDBI, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error)
}
diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go
index 87f0390a6f9c..5d9dcf1d3995 100644
--- a/core/types/transaction_signing.go
+++ b/core/types/transaction_signing.go
@@ -157,9 +157,16 @@ type Signer interface {
// Sender returns the sender address of the transaction.
Sender(tx *Transaction) (common.Address, error)
+ // PubKey returns the public key of the sender.
+ PubKey(tx *Transaction) ([]byte, error)
+
+ // Signature returns the raw signature of the transaction.
+ Signature(tx *Transaction) ([]byte, error)
+
// SignatureValues returns the raw R, S, V values corresponding to the
// given signature.
SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error)
+
ChainID() *big.Int
// Hash returns 'signature hash', i.e. the transaction hash that is signed by the
@@ -195,6 +202,34 @@ func (s londonSigner) Sender(tx *Transaction) (common.Address, error) {
return recoverPlain(s.Hash(tx), R, S, V, true)
}
+func (s londonSigner) PubKey(tx *Transaction) ([]byte, error) {
+ if tx.Type() != DynamicFeeTxType {
+ return s.eip2930Signer.PubKey(tx)
+ }
+ V, R, S := tx.RawSignatureValues()
+ // DynamicFee txs are defined to use 0 and 1 as their recovery
+ // id, add 27 to become equivalent to unprotected Homestead signatures.
+ V = new(big.Int).Add(V, big.NewInt(27))
+ if tx.ChainId().Cmp(s.chainId) != 0 {
+ return nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId)
+ }
+ return recoverPub(s.Hash(tx), R, S, V, true)
+}
+
+func (s londonSigner) Signature(tx *Transaction) ([]byte, error) {
+ if tx.Type() != DynamicFeeTxType {
+ return s.eip2930Signer.PubKey(tx)
+ }
+ V, R, S := tx.RawSignatureValues()
+ // DynamicFee txs are defined to use 0 and 1 as their recovery
+ // id, add 27 to become equivalent to unprotected Homestead signatures.
+ V = new(big.Int).Add(V, big.NewInt(27))
+ if tx.ChainId().Cmp(s.chainId) != 0 {
+ return nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId)
+ }
+ return recoverSig(s.Hash(tx), R, S, V, true)
+}
+
func (s londonSigner) Equal(s2 Signer) bool {
x, ok := s2.(londonSigner)
return ok && x.chainId.Cmp(s.chainId) == 0
@@ -275,6 +310,50 @@ func (s eip2930Signer) Sender(tx *Transaction) (common.Address, error) {
return recoverPlain(s.Hash(tx), R, S, V, true)
}
+func (s eip2930Signer) PubKey(tx *Transaction) ([]byte, error) {
+ V, R, S := tx.RawSignatureValues()
+ switch tx.Type() {
+ case LegacyTxType:
+ if !tx.Protected() {
+ return HomesteadSigner{}.PubKey(tx)
+ }
+ V = new(big.Int).Sub(V, s.chainIdMul)
+ V.Sub(V, big8)
+ case AccessListTxType:
+ // AL txs are defined to use 0 and 1 as their recovery
+ // id, add 27 to become equivalent to unprotected Homestead signatures.
+ V = new(big.Int).Add(V, big.NewInt(27))
+ default:
+ return nil, ErrTxTypeNotSupported
+ }
+ if tx.ChainId().Cmp(s.chainId) != 0 {
+ return nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId)
+ }
+ return recoverPub(s.Hash(tx), R, S, V, true)
+}
+
+func (s eip2930Signer) Signature(tx *Transaction) ([]byte, error) {
+ V, R, S := tx.RawSignatureValues()
+ switch tx.Type() {
+ case LegacyTxType:
+ if !tx.Protected() {
+ return HomesteadSigner{}.PubKey(tx)
+ }
+ V = new(big.Int).Sub(V, s.chainIdMul)
+ V.Sub(V, big8)
+ case AccessListTxType:
+ // AL txs are defined to use 0 and 1 as their recovery
+ // id, add 27 to become equivalent to unprotected Homestead signatures.
+ V = new(big.Int).Add(V, big.NewInt(27))
+ default:
+ return nil, ErrTxTypeNotSupported
+ }
+ if tx.ChainId().Cmp(s.chainId) != 0 {
+ return nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId)
+ }
+ return recoverSig(s.Hash(tx), R, S, V, true)
+}
+
func (s eip2930Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
switch txdata := tx.inner.(type) {
case *LegacyTx:
@@ -372,6 +451,38 @@ func (s EIP155Signer) Sender(tx *Transaction) (common.Address, error) {
return recoverPlain(s.Hash(tx), R, S, V, true)
}
+func (s EIP155Signer) PubKey(tx *Transaction) ([]byte, error) {
+ if tx.Type() != LegacyTxType {
+ return nil, ErrTxTypeNotSupported
+ }
+ if !tx.Protected() {
+ return HomesteadSigner{}.PubKey(tx)
+ }
+ if tx.ChainId().Cmp(s.chainId) != 0 {
+ return nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId)
+ }
+ V, R, S := tx.RawSignatureValues()
+ V = new(big.Int).Sub(V, s.chainIdMul)
+ V.Sub(V, big8)
+ return recoverPub(s.Hash(tx), R, S, V, true)
+}
+
+func (s EIP155Signer) Signature(tx *Transaction) ([]byte, error) {
+ if tx.Type() != LegacyTxType {
+ return nil, ErrTxTypeNotSupported
+ }
+ if !tx.Protected() {
+ return HomesteadSigner{}.Signature(tx)
+ }
+ if tx.ChainId().Cmp(s.chainId) != 0 {
+ return nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId)
+ }
+ V, R, S := tx.RawSignatureValues()
+ V = new(big.Int).Sub(V, s.chainIdMul)
+ V.Sub(V, big8)
+ return recoverSig(s.Hash(tx), R, S, V, true)
+}
+
// SignatureValues returns signature values. This signature
// needs to be in the [R || S || V] format where V is 0 or 1.
func (s EIP155Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
@@ -427,6 +538,14 @@ func (hs HomesteadSigner) Sender(tx *Transaction) (common.Address, error) {
return recoverPlain(hs.Hash(tx), r, s, v, true)
}
+func (hs HomesteadSigner) Signature(tx *Transaction) ([]byte, error) {
+ if tx.Type() != LegacyTxType {
+ return nil, ErrTxTypeNotSupported
+ }
+ v, r, s := tx.RawSignatureValues()
+ return recoverSig(hs.Hash(tx), r, s, v, true)
+}
+
// FrontierSigner implements Signer interface using the
// frontier rules.
type FrontierSigner struct{}
@@ -448,6 +567,22 @@ func (fs FrontierSigner) Sender(tx *Transaction) (common.Address, error) {
return recoverPlain(fs.Hash(tx), r, s, v, false)
}
+func (fs FrontierSigner) PubKey(tx *Transaction) ([]byte, error) {
+ if tx.Type() != LegacyTxType {
+ return nil, ErrTxTypeNotSupported
+ }
+ v, r, s := tx.RawSignatureValues()
+ return recoverPub(fs.Hash(tx), r, s, v, false)
+}
+
+func (fs FrontierSigner) Signature(tx *Transaction) ([]byte, error) {
+ if tx.Type() != LegacyTxType {
+ return nil, ErrTxTypeNotSupported
+ }
+ v, r, s := tx.RawSignatureValues()
+ return recoverSig(fs.Hash(tx), r, s, v, false)
+}
+
// SignatureValues returns signature values. This signature
// needs to be in the [R || S || V] format where V is 0 or 1.
func (fs FrontierSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error) {
@@ -481,13 +616,13 @@ func decodeSignature(sig []byte) (r, s, v *big.Int) {
return r, s, v
}
-func recoverPlain(sighash common.Hash, R, S, Vb *big.Int, homestead bool) (common.Address, error) {
+func recoverSig(sighash common.Hash, R, S, Vb *big.Int, homestead bool) ([]byte, error) {
if Vb.BitLen() > 8 {
- return common.Address{}, ErrInvalidSig
+ return nil, ErrInvalidSig
}
V := byte(Vb.Uint64() - 27)
if !crypto.ValidateSignatureValues(V, R, S, homestead) {
- return common.Address{}, ErrInvalidSig
+ return nil, ErrInvalidSig
}
// encode the signature in uncompressed format
r, s := R.Bytes(), S.Bytes()
@@ -495,13 +630,29 @@ func recoverPlain(sighash common.Hash, R, S, Vb *big.Int, homestead bool) (commo
copy(sig[32-len(r):32], r)
copy(sig[64-len(s):64], s)
sig[64] = V
+ return sig, nil
+}
+
+func recoverPub(sighash common.Hash, R, S, Vb *big.Int, homestead bool) ([]byte, error) {
// recover the public key from the signature
+ sig, err := recoverSig(sighash, R, S, Vb, homestead)
+ if err != nil {
+ return nil, err
+ }
pub, err := crypto.Ecrecover(sighash[:], sig)
if err != nil {
- return common.Address{}, err
+ return nil, err
}
if len(pub) == 0 || pub[0] != 4 {
- return common.Address{}, errors.New("invalid public key")
+ return nil, errors.New("invalid public key")
+ }
+ return pub, nil
+}
+
+func recoverPlain(sighash common.Hash, R, S, Vb *big.Int, homestead bool) (common.Address, error) {
+ pub, err := recoverPub(sighash, R, S, Vb, homestead)
+ if err != nil {
+ return common.Address{}, err
}
var addr common.Address
copy(addr[:], crypto.Keccak256(pub[1:])[12:])
diff --git a/core/types/tx_access_list.go b/core/types/tx_access_list.go
index 692bba4ff2d9..516a9309529d 100644
--- a/core/types/tx_access_list.go
+++ b/core/types/tx_access_list.go
@@ -96,6 +96,7 @@ func (tx *AccessListTx) copy() TxData {
// accessors for innerTx.
func (tx *AccessListTx) txType() byte { return AccessListTxType }
func (tx *AccessListTx) chainID() *big.Int { return tx.ChainID }
+func (tx *AccessListTx) GetChainID() *big.Int { return tx.ChainID }
func (tx *AccessListTx) accessList() AccessList { return tx.AccessList }
func (tx *AccessListTx) data() []byte { return tx.Data }
func (tx *AccessListTx) gas() uint64 { return tx.Gas }
diff --git a/core/types/tx_dynamic_fee.go b/core/types/tx_dynamic_fee.go
index 570810665817..da7bfb5418cc 100644
--- a/core/types/tx_dynamic_fee.go
+++ b/core/types/tx_dynamic_fee.go
@@ -84,6 +84,7 @@ func (tx *DynamicFeeTx) copy() TxData {
// accessors for innerTx.
func (tx *DynamicFeeTx) txType() byte { return DynamicFeeTxType }
func (tx *DynamicFeeTx) chainID() *big.Int { return tx.ChainID }
+func (tx *DynamicFeeTx) GetChainID() *big.Int { return tx.ChainID }
func (tx *DynamicFeeTx) accessList() AccessList { return tx.AccessList }
func (tx *DynamicFeeTx) data() []byte { return tx.Data }
func (tx *DynamicFeeTx) gas() uint64 { return tx.Gas }
diff --git a/core/types/tx_legacy.go b/core/types/tx_legacy.go
index 988de7db09aa..2951c8107596 100644
--- a/core/types/tx_legacy.go
+++ b/core/types/tx_legacy.go
@@ -93,6 +93,7 @@ func (tx *LegacyTx) copy() TxData {
// accessors for innerTx.
func (tx *LegacyTx) txType() byte { return LegacyTxType }
func (tx *LegacyTx) chainID() *big.Int { return deriveChainId(tx.V) }
+func (tx *LegacyTx) GetChainID() *big.Int { return deriveChainId(tx.V) }
func (tx *LegacyTx) accessList() AccessList { return nil }
func (tx *LegacyTx) data() []byte { return tx.Data }
func (tx *LegacyTx) gas() uint64 { return tx.Gas }
diff --git a/core/vm/contracts.go b/core/vm/contracts.go
index aa4a3f13df5e..f0a56d0dc21b 100644
--- a/core/vm/contracts.go
+++ b/core/vm/contracts.go
@@ -17,6 +17,7 @@
package vm
import (
+ "context"
"crypto/sha256"
"encoding/binary"
"errors"
@@ -36,8 +37,12 @@ import (
// requires a deterministic gas count based on the input size of the Run method of the
// contract.
type PrecompiledContract interface {
- RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use
- Run(input []byte) ([]byte, error) // Run runs the precompiled contract
+ // RegistryKey returns the address at which the contract will be registered.
+ RegistryKey() common.Address
+ // RequiredGas calculates the contract static gas use.
+ RequiredGas(input []byte) uint64
+ // Run runs the precompiled contract with the given context.
+ Run(ctx context.Context, evm PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error)
}
// PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum
@@ -127,7 +132,7 @@ func init() {
}
// ActivePrecompiles returns the precompiles enabled with the current configuration.
-func ActivePrecompiles(rules params.Rules) []common.Address {
+func ActivePrecompiles(rules *params.Rules) []common.Address {
switch {
case rules.IsBerlin:
return PrecompiledAddressesBerlin
@@ -140,29 +145,18 @@ func ActivePrecompiles(rules params.Rules) []common.Address {
}
}
-// RunPrecompiledContract runs and evaluates the output of a precompiled contract.
-// It returns
-// - the returned bytes,
-// - the _remaining_ gas,
-// - any error that occurred
-func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) {
- gasCost := p.RequiredGas(input)
- if suppliedGas < gasCost {
- return nil, 0, ErrOutOfGas
- }
- suppliedGas -= gasCost
- output, err := p.Run(input)
- return output, suppliedGas, err
-}
-
// ECRECOVER implemented as a native contract.
type ecrecover struct{}
+func (c *ecrecover) RegistryKey() common.Address {
+ return common.BytesToAddress([]byte{1})
+}
+
func (c *ecrecover) RequiredGas(input []byte) uint64 {
return params.EcrecoverGas
}
-func (c *ecrecover) Run(input []byte) ([]byte, error) {
+func (c *ecrecover) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
const ecRecoverInputLength = 128
input = common.RightPadBytes(input, ecRecoverInputLength)
@@ -196,6 +190,10 @@ func (c *ecrecover) Run(input []byte) ([]byte, error) {
// SHA256 implemented as a native contract.
type sha256hash struct{}
+func (c *sha256hash) RegistryKey() common.Address {
+ return common.BytesToAddress([]byte{2})
+}
+
// RequiredGas returns the gas required to execute the pre-compiled contract.
//
// This method does not require any overflow checking as the input size gas costs
@@ -203,7 +201,7 @@ type sha256hash struct{}
func (c *sha256hash) RequiredGas(input []byte) uint64 {
return uint64(len(input)+31)/32*params.Sha256PerWordGas + params.Sha256BaseGas
}
-func (c *sha256hash) Run(input []byte) ([]byte, error) {
+func (c *sha256hash) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
h := sha256.Sum256(input)
return h[:], nil
}
@@ -211,6 +209,10 @@ func (c *sha256hash) Run(input []byte) ([]byte, error) {
// RIPEMD160 implemented as a native contract.
type ripemd160hash struct{}
+func (c *ripemd160hash) RegistryKey() common.Address {
+ return common.BytesToAddress([]byte{3})
+}
+
// RequiredGas returns the gas required to execute the pre-compiled contract.
//
// This method does not require any overflow checking as the input size gas costs
@@ -218,7 +220,7 @@ type ripemd160hash struct{}
func (c *ripemd160hash) RequiredGas(input []byte) uint64 {
return uint64(len(input)+31)/32*params.Ripemd160PerWordGas + params.Ripemd160BaseGas
}
-func (c *ripemd160hash) Run(input []byte) ([]byte, error) {
+func (c *ripemd160hash) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
ripemd := ripemd160.New()
ripemd.Write(input)
return common.LeftPadBytes(ripemd.Sum(nil), 32), nil
@@ -227,6 +229,10 @@ func (c *ripemd160hash) Run(input []byte) ([]byte, error) {
// data copy implemented as a native contract.
type dataCopy struct{}
+func (c *dataCopy) RegistryKey() common.Address {
+ return common.BytesToAddress([]byte{4})
+}
+
// RequiredGas returns the gas required to execute the pre-compiled contract.
//
// This method does not require any overflow checking as the input size gas costs
@@ -234,8 +240,8 @@ type dataCopy struct{}
func (c *dataCopy) RequiredGas(input []byte) uint64 {
return uint64(len(input)+31)/32*params.IdentityPerWordGas + params.IdentityBaseGas
}
-func (c *dataCopy) Run(in []byte) ([]byte, error) {
- return common.CopyBytes(in), nil
+func (c *dataCopy) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
+ return input, nil
}
// bigModExp implements a native big integer exponential modular operation.
@@ -243,6 +249,10 @@ type bigModExp struct {
eip2565 bool
}
+func (c *bigModExp) RegistryKey() common.Address {
+ return common.BytesToAddress([]byte{5})
+}
+
var (
big0 = big.NewInt(0)
big1 = big.NewInt(1)
@@ -263,10 +273,11 @@ var (
// modexpMultComplexity implements bigModexp multComplexity formula, as defined in EIP-198
//
-// def mult_complexity(x):
-// if x <= 64: return x ** 2
-// elif x <= 1024: return x ** 2 // 4 + 96 * x - 3072
-// else: return x ** 2 // 16 + 480 * x - 199680
+// def mult_complexity(x):
+//
+// if x <= 64: return x ** 2
+// elif x <= 1024: return x ** 2 // 4 + 96 * x - 3072
+// else: return x ** 2 // 16 + 480 * x - 199680
//
// where is x is max(length_of_MODULUS, length_of_BASE)
func modexpMultComplexity(x *big.Int) *big.Int {
@@ -360,7 +371,7 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 {
return gas.Uint64()
}
-func (c *bigModExp) Run(input []byte) ([]byte, error) {
+func (c *bigModExp) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
var (
baseLen = new(big.Int).SetBytes(getData(input, 0, 32)).Uint64()
expLen = new(big.Int).SetBytes(getData(input, 32, 32)).Uint64()
@@ -435,12 +446,16 @@ func runBn256Add(input []byte) ([]byte, error) {
// Istanbul consensus rules.
type bn256AddIstanbul struct{}
+func (c *bn256AddIstanbul) RegistryKey() common.Address {
+ return common.BytesToAddress([]byte{6})
+}
+
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bn256AddIstanbul) RequiredGas(input []byte) uint64 {
return params.Bn256AddGasIstanbul
}
-func (c *bn256AddIstanbul) Run(input []byte) ([]byte, error) {
+func (c *bn256AddIstanbul) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
return runBn256Add(input)
}
@@ -448,12 +463,16 @@ func (c *bn256AddIstanbul) Run(input []byte) ([]byte, error) {
// conforming to Byzantium consensus rules.
type bn256AddByzantium struct{}
+func (c *bn256AddByzantium) RegistryKey() common.Address {
+ return common.BytesToAddress([]byte{6})
+}
+
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bn256AddByzantium) RequiredGas(input []byte) uint64 {
return params.Bn256AddGasByzantium
}
-func (c *bn256AddByzantium) Run(input []byte) ([]byte, error) {
+func (c *bn256AddByzantium) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
return runBn256Add(input)
}
@@ -473,12 +492,16 @@ func runBn256ScalarMul(input []byte) ([]byte, error) {
// multiplication conforming to Istanbul consensus rules.
type bn256ScalarMulIstanbul struct{}
+func (c *bn256ScalarMulIstanbul) RegistryKey() common.Address {
+ return common.BytesToAddress([]byte{7})
+}
+
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bn256ScalarMulIstanbul) RequiredGas(input []byte) uint64 {
return params.Bn256ScalarMulGasIstanbul
}
-func (c *bn256ScalarMulIstanbul) Run(input []byte) ([]byte, error) {
+func (c *bn256ScalarMulIstanbul) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
return runBn256ScalarMul(input)
}
@@ -486,12 +509,16 @@ func (c *bn256ScalarMulIstanbul) Run(input []byte) ([]byte, error) {
// multiplication conforming to Byzantium consensus rules.
type bn256ScalarMulByzantium struct{}
+func (c *bn256ScalarMulByzantium) RegistryKey() common.Address {
+ return common.BytesToAddress([]byte{7})
+}
+
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bn256ScalarMulByzantium) RequiredGas(input []byte) uint64 {
return params.Bn256ScalarMulGasByzantium
}
-func (c *bn256ScalarMulByzantium) Run(input []byte) ([]byte, error) {
+func (c *bn256ScalarMulByzantium) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
return runBn256ScalarMul(input)
}
@@ -541,12 +568,16 @@ func runBn256Pairing(input []byte) ([]byte, error) {
// conforming to Istanbul consensus rules.
type bn256PairingIstanbul struct{}
+func (c *bn256PairingIstanbul) RegistryKey() common.Address {
+ return common.BytesToAddress([]byte{8})
+}
+
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bn256PairingIstanbul) RequiredGas(input []byte) uint64 {
return params.Bn256PairingBaseGasIstanbul + uint64(len(input)/192)*params.Bn256PairingPerPointGasIstanbul
}
-func (c *bn256PairingIstanbul) Run(input []byte) ([]byte, error) {
+func (c *bn256PairingIstanbul) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
return runBn256Pairing(input)
}
@@ -554,17 +585,25 @@ func (c *bn256PairingIstanbul) Run(input []byte) ([]byte, error) {
// conforming to Byzantium consensus rules.
type bn256PairingByzantium struct{}
+func (c *bn256PairingByzantium) RegistryKey() common.Address {
+ return common.BytesToAddress([]byte{8})
+}
+
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bn256PairingByzantium) RequiredGas(input []byte) uint64 {
return params.Bn256PairingBaseGasByzantium + uint64(len(input)/192)*params.Bn256PairingPerPointGasByzantium
}
-func (c *bn256PairingByzantium) Run(input []byte) ([]byte, error) {
+func (c *bn256PairingByzantium) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
return runBn256Pairing(input)
}
type blake2F struct{}
+func (c *blake2F) RegistryKey() common.Address {
+ return common.BytesToAddress([]byte{9})
+}
+
func (c *blake2F) RequiredGas(input []byte) uint64 {
// If the input is malformed, we can't calculate the gas, return 0 and let the
// actual call choke and fault.
@@ -585,7 +624,7 @@ var (
errBlake2FInvalidFinalFlag = errors.New("invalid final flag")
)
-func (c *blake2F) Run(input []byte) ([]byte, error) {
+func (c *blake2F) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
// Make sure the input is valid (correct length and final flag)
if len(input) != blake2FInputLength {
return nil, errBlake2FInvalidInputLength
@@ -634,12 +673,16 @@ var (
// bls12381G1Add implements EIP-2537 G1Add precompile.
type bls12381G1Add struct{}
+func (c *bls12381G1Add) RegistryKey() common.Address {
+ return common.BytesToAddress([]byte{10})
+}
+
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381G1Add) RequiredGas(input []byte) uint64 {
return params.Bls12381G1AddGas
}
-func (c *bls12381G1Add) Run(input []byte) ([]byte, error) {
+func (c *bls12381G1Add) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
// Implements EIP-2537 G1Add precompile.
// > G1 addition call expects `256` bytes as an input that is interpreted as byte concatenation of two G1 points (`128` bytes each).
// > Output is an encoding of addition operation result - single G1 point (`128` bytes).
@@ -672,12 +715,16 @@ func (c *bls12381G1Add) Run(input []byte) ([]byte, error) {
// bls12381G1Mul implements EIP-2537 G1Mul precompile.
type bls12381G1Mul struct{}
+func (c *bls12381G1Mul) RegistryKey() common.Address {
+ return common.BytesToAddress([]byte{11})
+}
+
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381G1Mul) RequiredGas(input []byte) uint64 {
return params.Bls12381G1MulGas
}
-func (c *bls12381G1Mul) Run(input []byte) ([]byte, error) {
+func (c *bls12381G1Mul) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
// Implements EIP-2537 G1Mul precompile.
// > G1 multiplication call expects `160` bytes as an input that is interpreted as byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes).
// > Output is an encoding of multiplication operation result - single G1 point (`128` bytes).
@@ -708,6 +755,10 @@ func (c *bls12381G1Mul) Run(input []byte) ([]byte, error) {
// bls12381G1MultiExp implements EIP-2537 G1MultiExp precompile.
type bls12381G1MultiExp struct{}
+func (c *bls12381G1MultiExp) RegistryKey() common.Address {
+ return common.BytesToAddress([]byte{12})
+}
+
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381G1MultiExp) RequiredGas(input []byte) uint64 {
// Calculate G1 point, scalar value pair length
@@ -727,7 +778,7 @@ func (c *bls12381G1MultiExp) RequiredGas(input []byte) uint64 {
return (uint64(k) * params.Bls12381G1MulGas * discount) / 1000
}
-func (c *bls12381G1MultiExp) Run(input []byte) ([]byte, error) {
+func (c *bls12381G1MultiExp) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
// Implements EIP-2537 G1MultiExp precompile.
// G1 multiplication call expects `160*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes).
// Output is an encoding of multiexponentiation operation result - single G1 point (`128` bytes).
@@ -765,12 +816,16 @@ func (c *bls12381G1MultiExp) Run(input []byte) ([]byte, error) {
// bls12381G2Add implements EIP-2537 G2Add precompile.
type bls12381G2Add struct{}
+func (c *bls12381G2Add) RegistryKey() common.Address {
+ return common.BytesToAddress([]byte{13})
+}
+
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381G2Add) RequiredGas(input []byte) uint64 {
return params.Bls12381G2AddGas
}
-func (c *bls12381G2Add) Run(input []byte) ([]byte, error) {
+func (c *bls12381G2Add) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
// Implements EIP-2537 G2Add precompile.
// > G2 addition call expects `512` bytes as an input that is interpreted as byte concatenation of two G2 points (`256` bytes each).
// > Output is an encoding of addition operation result - single G2 point (`256` bytes).
@@ -803,12 +858,16 @@ func (c *bls12381G2Add) Run(input []byte) ([]byte, error) {
// bls12381G2Mul implements EIP-2537 G2Mul precompile.
type bls12381G2Mul struct{}
+func (c *bls12381G2Mul) RegistryKey() common.Address {
+ return common.BytesToAddress([]byte{14})
+}
+
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381G2Mul) RequiredGas(input []byte) uint64 {
return params.Bls12381G2MulGas
}
-func (c *bls12381G2Mul) Run(input []byte) ([]byte, error) {
+func (c *bls12381G2Mul) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
// Implements EIP-2537 G2MUL precompile logic.
// > G2 multiplication call expects `288` bytes as an input that is interpreted as byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes).
// > Output is an encoding of multiplication operation result - single G2 point (`256` bytes).
@@ -839,6 +898,10 @@ func (c *bls12381G2Mul) Run(input []byte) ([]byte, error) {
// bls12381G2MultiExp implements EIP-2537 G2MultiExp precompile.
type bls12381G2MultiExp struct{}
+func (c *bls12381G2MultiExp) RegistryKey() common.Address {
+ return common.BytesToAddress([]byte{15})
+}
+
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381G2MultiExp) RequiredGas(input []byte) uint64 {
// Calculate G2 point, scalar value pair length
@@ -858,7 +921,7 @@ func (c *bls12381G2MultiExp) RequiredGas(input []byte) uint64 {
return (uint64(k) * params.Bls12381G2MulGas * discount) / 1000
}
-func (c *bls12381G2MultiExp) Run(input []byte) ([]byte, error) {
+func (c *bls12381G2MultiExp) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
// Implements EIP-2537 G2MultiExp precompile logic
// > G2 multiplication call expects `288*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes).
// > Output is an encoding of multiexponentiation operation result - single G2 point (`256` bytes).
@@ -896,12 +959,16 @@ func (c *bls12381G2MultiExp) Run(input []byte) ([]byte, error) {
// bls12381Pairing implements EIP-2537 Pairing precompile.
type bls12381Pairing struct{}
+func (c *bls12381Pairing) RegistryKey() common.Address {
+ return common.BytesToAddress([]byte{16})
+}
+
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381Pairing) RequiredGas(input []byte) uint64 {
return params.Bls12381PairingBaseGas + uint64(len(input)/384)*params.Bls12381PairingPerPairGas
}
-func (c *bls12381Pairing) Run(input []byte) ([]byte, error) {
+func (c *bls12381Pairing) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
// Implements EIP-2537 Pairing precompile logic.
// > Pairing call expects `384*k` bytes as an inputs that is interpreted as byte concatenation of `k` slices. Each slice has the following structure:
// > - `128` bytes of G1 point encoding
@@ -975,12 +1042,16 @@ func decodeBLS12381FieldElement(in []byte) ([]byte, error) {
// bls12381MapG1 implements EIP-2537 MapG1 precompile.
type bls12381MapG1 struct{}
+func (c *bls12381MapG1) RegistryKey() common.Address {
+ return common.BytesToAddress([]byte{17})
+}
+
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381MapG1) RequiredGas(input []byte) uint64 {
return params.Bls12381MapG1Gas
}
-func (c *bls12381MapG1) Run(input []byte) ([]byte, error) {
+func (c *bls12381MapG1) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
// Implements EIP-2537 Map_To_G1 precompile.
// > Field-to-curve call expects `64` bytes an an input that is interpreted as a an element of the base field.
// > Output of this call is `128` bytes and is G1 point following respective encoding rules.
@@ -1010,12 +1081,16 @@ func (c *bls12381MapG1) Run(input []byte) ([]byte, error) {
// bls12381MapG2 implements EIP-2537 MapG2 precompile.
type bls12381MapG2 struct{}
+func (c *bls12381MapG2) RegistryKey() common.Address {
+ return common.BytesToAddress([]byte{18})
+}
+
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381MapG2) RequiredGas(input []byte) uint64 {
return params.Bls12381MapG2Gas
}
-func (c *bls12381MapG2) Run(input []byte) ([]byte, error) {
+func (c *bls12381MapG2) Run(ctx context.Context, _ PrecompileEVM, input []byte, caller common.Address, value *big.Int, readonly bool) ([]byte, error) {
// Implements EIP-2537 Map_FP2_TO_G2 precompile logic.
// > Field-to-curve call expects `128` bytes an an input that is interpreted as a an element of the quadratic extension field.
// > Output of this call is `256` bytes and is G2 point following respective encoding rules.
diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go
index b22d999e6cd9..bf9756cebb57 100644
--- a/core/vm/contracts_test.go
+++ b/core/vm/contracts_test.go
@@ -18,8 +18,10 @@ package vm
import (
"bytes"
+ "context"
"encoding/json"
"fmt"
+ "math/big"
"os"
"testing"
"time"
@@ -91,6 +93,16 @@ var blake2FMalformedInputTests = []precompiledFailureTest{
},
}
+func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) {
+ gasCost := p.RequiredGas(input)
+ if suppliedGas < gasCost {
+ return nil, 0, ErrOutOfGas
+ }
+ suppliedGas -= gasCost
+ output, err := p.Run(context.Background(), nil, input, common.Address{}, new(big.Int), true)
+ return output, suppliedGas, err
+}
+
func testPrecompiled(addr string, test precompiledTest, t *testing.T) {
p := allPrecompiles[common.HexToAddress(addr)]
in := common.Hex2Bytes(test.Input)
diff --git a/core/vm/eips.go b/core/vm/eips.go
index 29ff27c55268..c4b4f56b8d80 100644
--- a/core/vm/eips.go
+++ b/core/vm/eips.go
@@ -53,6 +53,7 @@ func ValidEip(eipNum int) bool {
_, ok := activators[eipNum]
return ok
}
+
func ActivateableEips() []string {
var nums []string
for k := range activators {
diff --git a/core/vm/evm.go b/core/vm/evm.go
index d78ea0792664..6fd161a7b654 100644
--- a/core/vm/evm.go
+++ b/core/vm/evm.go
@@ -17,6 +17,7 @@
package vm
import (
+ "errors"
"math/big"
"sync/atomic"
@@ -40,22 +41,6 @@ type (
GetHashFunc func(uint64) common.Hash
)
-func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
- var precompiles map[common.Address]PrecompiledContract
- switch {
- case evm.chainRules.IsBerlin:
- precompiles = PrecompiledContractsBerlin
- case evm.chainRules.IsIstanbul:
- precompiles = PrecompiledContractsIstanbul
- case evm.chainRules.IsByzantium:
- precompiles = PrecompiledContractsByzantium
- default:
- precompiles = PrecompiledContractsHomestead
- }
- p, ok := precompiles[addr]
- return p, ok
-}
-
// BlockContext provides the EVM with auxiliary information. Once provided
// it shouldn't be modified.
type BlockContext struct {
@@ -100,6 +85,8 @@ type EVM struct {
TxContext
// StateDB gives access to the underlying state
StateDB StateDB
+ // PrecompileManager finds and runs precompiled contracts
+ PrecompileManager PrecompileManager
// Depth is the current call stack
depth int
@@ -134,6 +121,26 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig
chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time),
}
evm.interpreter = NewEVMInterpreter(evm)
+ evm.PrecompileManager = NewPrecompileManager(&evm.chainRules)
+ return evm
+}
+
+// NewEVMWithPrecompiles returns a new EVM with a precompile manager. The returned EVM is not
+// thread safe and should only ever be used *once*.
+func NewEVMWithPrecompiles(
+ blockCtx BlockContext, txCtx TxContext, statedb StateDB,
+ chainConfig *params.ChainConfig, config Config, precompileManager PrecompileManager,
+) *EVM {
+ evm := &EVM{
+ Context: blockCtx,
+ TxContext: txCtx,
+ StateDB: statedb,
+ Config: config,
+ chainConfig: chainConfig,
+ chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time),
+ }
+ evm.interpreter = NewEVMInterpreter(evm)
+ evm.PrecompileManager = precompileManager
return evm
}
@@ -160,12 +167,12 @@ func (evm *EVM) Interpreter() *EVMInterpreter {
return evm.interpreter
}
-// SetBlockContext updates the block context of the EVM.
-func (evm *EVM) SetBlockContext(blockCtx BlockContext) {
- evm.Context = blockCtx
- num := blockCtx.BlockNumber
- timestamp := blockCtx.Time
- evm.chainRules = evm.chainConfig.Rules(num, blockCtx.Random != nil, timestamp)
+func (evm *EVM) GetStateDB() StateDB {
+ return evm.StateDB
+}
+
+func (evm *EVM) GetContext() *BlockContext {
+ return &evm.Context
}
// Call executes the contract associated with the addr with the given input as
@@ -182,7 +189,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
return nil, gas, ErrInsufficientBalance
}
snapshot := evm.StateDB.Snapshot()
- p, isPrecompile := evm.precompile(addr)
+ isPrecompile := evm.PrecompileManager.Has(addr)
if !evm.StateDB.Exist(addr) {
if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 {
@@ -219,7 +226,9 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
}
if isPrecompile {
- ret, gas, err = RunPrecompiledContract(p, input, gas)
+ ret, gas, err = evm.PrecompileManager.Run(
+ evm, evm.PrecompileManager.Get(addr), input, caller.Address(), value, gas, false,
+ )
} else {
// Initialise a new contract and set the code that is to be used by the EVM.
// The contract is a scoped environment for this execution context only.
@@ -241,7 +250,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
// when we're in homestead this also counts for code storage gas errors.
if err != nil {
evm.StateDB.RevertToSnapshot(snapshot)
- if err != ErrExecutionReverted {
+ if errors.Is(err, ErrExecutionReverted) {
gas = 0
}
// TODO: consider clearing up unused snapshots:
@@ -281,8 +290,10 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
}
// It is allowed to call precompiles, even via delegatecall
- if p, isPrecompile := evm.precompile(addr); isPrecompile {
- ret, gas, err = RunPrecompiledContract(p, input, gas)
+ if isPrecompile := evm.PrecompileManager.Has(addr); isPrecompile {
+ ret, gas, err = evm.PrecompileManager.Run(
+ evm, evm.PrecompileManager.Get(addr), input, caller.Address(), value, gas, false,
+ )
} else {
addrCopy := addr
// Initialise a new contract and set the code that is to be used by the EVM.
@@ -294,7 +305,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
}
if err != nil {
evm.StateDB.RevertToSnapshot(snapshot)
- if err != ErrExecutionReverted {
+ if errors.Is(err, ErrExecutionReverted) {
gas = 0
}
}
@@ -326,8 +337,11 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
}
// It is allowed to call precompiles, even via delegatecall
- if p, isPrecompile := evm.precompile(addr); isPrecompile {
- ret, gas, err = RunPrecompiledContract(p, input, gas)
+ if isPrecompile := evm.PrecompileManager.Has(addr); isPrecompile {
+ parent := caller.(*Contract)
+ ret, gas, err = evm.PrecompileManager.Run(
+ evm, evm.PrecompileManager.Get(addr), input, parent.CallerAddress, parent.value, gas, false,
+ )
} else {
addrCopy := addr
// Initialise a new contract and make initialise the delegate values
@@ -338,7 +352,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
}
if err != nil {
evm.StateDB.RevertToSnapshot(snapshot)
- if err != ErrExecutionReverted {
+ if errors.Is(err, ErrExecutionReverted) {
gas = 0
}
}
@@ -366,6 +380,9 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
// but is the correct thing to do and matters on other networks, in tests, and potential
// future scenarios
evm.StateDB.AddBalance(addr, big0)
+ if err := evm.StateDB.Error(); err != nil {
+ return nil, gas, err
+ }
// Invoke tracer hooks that signal entering/exiting a call frame
if evm.Config.Debug {
@@ -375,8 +392,10 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
}(gas)
}
- if p, isPrecompile := evm.precompile(addr); isPrecompile {
- ret, gas, err = RunPrecompiledContract(p, input, gas)
+ if isPrecompile := evm.PrecompileManager.Has(addr); isPrecompile {
+ ret, gas, err = evm.PrecompileManager.Run(
+ evm, evm.PrecompileManager.Get(addr), input, caller.Address(), new(big.Int), gas, true,
+ )
} else {
// At this point, we use a copy of address. If we don't, the go compiler will
// leak the 'contract' to the outer scope, and make allocation for 'contract'
@@ -394,7 +413,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
}
if err != nil {
evm.StateDB.RevertToSnapshot(snapshot)
- if err != ErrExecutionReverted {
+ if errors.Is(err, ErrExecutionReverted) {
gas = 0
}
}
@@ -428,6 +447,9 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
return nil, common.Address{}, gas, ErrNonceUintOverflow
}
evm.StateDB.SetNonce(caller.Address(), nonce+1)
+ if err := evm.StateDB.Error(); err != nil {
+ return nil, common.Address{}, gas, err
+ }
// We add this to the access list _before_ taking a snapshot. Even if the creation fails,
// the access-list change should not be rolled back
if evm.chainRules.IsBerlin {
@@ -443,6 +465,9 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
evm.StateDB.CreateAccount(address)
if evm.chainRules.IsEIP158 {
evm.StateDB.SetNonce(address, 1)
+ if err := evm.StateDB.Error(); err != nil {
+ return nil, common.Address{}, gas, err
+ }
}
evm.Context.Transfer(evm.StateDB, caller.Address(), address, value)
diff --git a/core/vm/instructions.go b/core/vm/instructions.go
index 77b6e02bfcc7..d0a2930b82a0 100644
--- a/core/vm/instructions.go
+++ b/core/vm/instructions.go
@@ -823,6 +823,9 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
beneficiary := scope.Stack.pop()
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance)
+ if err := interpreter.evm.StateDB.Error(); err != nil {
+ return nil, err
+ }
interpreter.evm.StateDB.Suicide(scope.Contract.Address())
if interpreter.evm.Config.Debug {
interpreter.evm.Config.Tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance)
diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go
index 61f001a692c3..1554a603ff0c 100644
--- a/core/vm/instructions_test.go
+++ b/core/vm/instructions_test.go
@@ -592,7 +592,7 @@ func TestOpTstore(t *testing.T) {
value = common.Hex2Bytes("abcdef00000000000000abba000000000deaf000000c0de00100000000133700")
)
- // Add a stateObject for the caller and the contract being called
+ // Add a StateObject for the caller and the contract being called
statedb.CreateAccount(caller)
statedb.CreateAccount(to)
diff --git a/core/vm/interface.go b/core/vm/interface.go
index 0ee32b1dd510..d3a0dc9a0f22 100644
--- a/core/vm/interface.go
+++ b/core/vm/interface.go
@@ -20,65 +20,13 @@ import (
"math/big"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/params"
+ "github.com/holiman/uint256"
)
// StateDB is an EVM database for full state querying.
-type StateDB interface {
- CreateAccount(common.Address)
-
- SubBalance(common.Address, *big.Int)
- AddBalance(common.Address, *big.Int)
- GetBalance(common.Address) *big.Int
-
- GetNonce(common.Address) uint64
- SetNonce(common.Address, uint64)
-
- GetCodeHash(common.Address) common.Hash
- GetCode(common.Address) []byte
- SetCode(common.Address, []byte)
- GetCodeSize(common.Address) int
-
- AddRefund(uint64)
- SubRefund(uint64)
- GetRefund() uint64
-
- GetCommittedState(common.Address, common.Hash) common.Hash
- GetState(common.Address, common.Hash) common.Hash
- SetState(common.Address, common.Hash, common.Hash)
-
- GetTransientState(addr common.Address, key common.Hash) common.Hash
- SetTransientState(addr common.Address, key, value common.Hash)
-
- Suicide(common.Address) bool
- HasSuicided(common.Address) bool
-
- // Exist reports whether the given account exists in state.
- // Notably this should also return true for suicided accounts.
- Exist(common.Address) bool
- // Empty returns whether the given account is empty. Empty
- // is defined according to EIP161 (balance = nonce = code = 0).
- Empty(common.Address) bool
-
- AddressInAccessList(addr common.Address) bool
- SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool)
- // AddAddressToAccessList adds the given address to the access list. This operation is safe to perform
- // even if the feature/fork is not active yet
- AddAddressToAccessList(addr common.Address)
- // AddSlotToAccessList adds the given (address,slot) to the access list. This operation is safe to perform
- // even if the feature/fork is not active yet
- AddSlotToAccessList(addr common.Address, slot common.Hash)
- Prepare(rules params.Rules, sender, coinbase common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList)
-
- RevertToSnapshot(int)
- Snapshot() int
-
- AddLog(*types.Log)
- AddPreimage(common.Hash, []byte)
-
- ForEachStorage(common.Address, func(common.Hash, common.Hash) bool) error
-}
+type StateDB = state.StateDBI
// CallContext provides a basic interface for the EVM calling conventions. The EVM
// depends on this context being implemented for doing subcalls and initialising new EVM contracts.
@@ -92,3 +40,33 @@ type CallContext interface {
// Create creates a new contract
Create(env *EVM, me ContractRef, data []byte, gas, value *big.Int) ([]byte, common.Address, error)
}
+
+type (
+ // PrecompileManager allows the EVM to execute a precompiled contract.
+ PrecompileManager interface {
+ // `Has` returns if a precompiled contract was found at `addr`.
+ Has(addr common.Address) bool
+
+ // `Get` returns the precompiled contract at `addr`. Returns nil if no
+ // contract is found at `addr`.
+ Get(addr common.Address) PrecompiledContract
+
+ GetActive(*params.Rules) []common.Address
+
+ // `Run` runs a precompiled contract and returns the remaining gas.
+ Run(evm PrecompileEVM, p PrecompiledContract, input []byte, caller common.Address,
+ value *big.Int, suppliedGas uint64, readonly bool,
+ ) (ret []byte, remainingGas uint64, err error)
+ }
+
+ // PrecompileEVM is the interface through which stateful precompiles can call back into the EVM.
+ PrecompileEVM interface {
+ GetStateDB() StateDB
+
+ Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error)
+ StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error)
+ Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error)
+ Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error)
+ GetContext() *BlockContext
+ }
+)
diff --git a/core/vm/precompile_manager.go b/core/vm/precompile_manager.go
new file mode 100644
index 000000000000..8fe962bb1fd7
--- /dev/null
+++ b/core/vm/precompile_manager.go
@@ -0,0 +1,92 @@
+// Copyright 2014 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 .
+
+package vm
+
+import (
+ "context"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/params"
+)
+
+// precompileManager is used as a default PrecompileManager for the EVM.
+type precompileManager struct {
+ rules *params.Rules
+ precompiles map[common.Address]PrecompiledContract
+}
+
+// NewPrecompileManager returns a new PrecompileManager for the current chain rules.
+func NewPrecompileManager(rules *params.Rules) PrecompileManager {
+ return &precompileManager{
+ rules: rules,
+ }
+}
+
+// Has returns whether a precompiled contract is deployed at the given address.
+func (pm *precompileManager) Has(addr common.Address) bool {
+ if pm.precompiles == nil {
+ pm.precompiles = activePrecompiles(pm.rules)
+ }
+ _, found := pm.precompiles[addr]
+ return found
+}
+
+// Get returns the precompiled contract deployed at the given address.
+func (pm *precompileManager) Get(addr common.Address) PrecompiledContract {
+ if pm.precompiles == nil {
+ pm.precompiles = activePrecompiles(pm.rules)
+ }
+ return pm.precompiles[addr]
+}
+
+// GetActive sets the chain rules on the precompile manager and returns the list of active
+// precompile addresses.
+func (pm *precompileManager) GetActive(rules *params.Rules) []common.Address {
+ pm.rules = rules
+ return ActivePrecompiles(pm.rules)
+}
+
+// Run runs the given precompiled contract with the given input data and returns the remaining gas.
+func (pm *precompileManager) Run(
+ evm PrecompileEVM, p PrecompiledContract, input []byte,
+ caller common.Address, value *big.Int, suppliedGas uint64, readonly bool,
+) (ret []byte, remainingGas uint64, err error) {
+ gasCost := p.RequiredGas(input)
+ if gasCost > suppliedGas {
+ return nil, 0, ErrOutOfGas
+ }
+
+ suppliedGas -= gasCost
+ output, err := p.Run(context.Background(), evm, input, caller, value, readonly)
+
+ return output, suppliedGas, err
+}
+
+// activePrecompiles returns the precompiled contracts for the given chain rules.
+func activePrecompiles(rules *params.Rules) map[common.Address]PrecompiledContract {
+ switch {
+ case rules.IsBerlin:
+ return PrecompiledContractsBerlin
+ case rules.IsIstanbul:
+ return PrecompiledContractsIstanbul
+ case rules.IsByzantium:
+ return PrecompiledContractsByzantium
+ default:
+ return PrecompiledContractsHomestead
+ }
+}
diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go
index 56ff5eeabe33..8927d3b7bca7 100644
--- a/core/vm/runtime/runtime.go
+++ b/core/vm/runtime/runtime.go
@@ -44,7 +44,7 @@ type Config struct {
EVMConfig vm.Config
BaseFee *big.Int
- State *state.StateDB
+ State state.StateDBI
GetHashFn func(n uint64) common.Hash
}
@@ -100,7 +100,7 @@ func setDefaults(cfg *Config) {
//
// Execute sets up an in-memory, temporary, environment for the execution of
// the given code. It makes sure that it's restored to its original state afterwards.
-func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
+func Execute(code, input []byte, cfg *Config) ([]byte, state.StateDBI, error) {
if cfg == nil {
cfg = new(Config)
}
@@ -118,7 +118,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
// Execute the preparatory steps for state transition which includes:
// - prepare accessList(post-berlin)
// - reset transient storage(eip 1153)
- cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil)
+ cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vmenv.PrecompileManager.GetActive(&rules), nil)
cfg.State.CreateAccount(address)
// set the receiver's (the executing contract) code for execution.
cfg.State.SetCode(address, code)
@@ -151,7 +151,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
// Execute the preparatory steps for state transition which includes:
// - prepare accessList(post-berlin)
// - reset transient storage(eip 1153)
- cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, nil, vm.ActivePrecompiles(rules), nil)
+ cfg.State.Prepare(rules, cfg.Origin, cfg.Coinbase, nil, vmenv.PrecompileManager.GetActive(&rules), nil)
// Call the code with the given configuration.
code, address, leftOverGas, err := vmenv.Create(
sender,
@@ -179,7 +179,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er
// Execute the preparatory steps for state transition which includes:
// - prepare accessList(post-berlin)
// - reset transient storage(eip 1153)
- statedb.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil)
+ statedb.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vmenv.PrecompileManager.GetActive(&rules), nil)
// Call the code with the given configuration.
ret, leftOverGas, err := vmenv.Call(
diff --git a/eth/api.go b/eth/api.go
index cd6510ccf9a2..06b310efff6e 100644
--- a/eth/api.go
+++ b/eth/api.go
@@ -34,7 +34,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/internal/ethapi"
+ "github.com/ethereum/go-ethereum/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
@@ -341,7 +341,7 @@ const AccountRangeMaxResults = 256
// AccountRange enumerates all accounts in the given block and start point in paging request
func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hexutil.Bytes, maxResults int, nocode, nostorage, incompletes bool) (state.IteratorDump, error) {
- var stateDb *state.StateDB
+ var stateDb state.StateDBI
var err error
if number, ok := blockNrOrHash.Number(); ok {
diff --git a/eth/api_backend.go b/eth/api_backend.go
index 78b9b08ecb32..3a15dcd34fba 100644
--- a/eth/api_backend.go
+++ b/eth/api_backend.go
@@ -174,7 +174,7 @@ func (b *EthAPIBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts)
return b.eth.miner.PendingBlockAndReceipts()
}
-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) (state.StateDBI, *types.Header, error) {
// Pending state is only known by the miner
if number == rpc.PendingBlockNumber {
block, state := b.eth.miner.Pending()
@@ -192,7 +192,7 @@ func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.B
return stateDb, header, err
}
-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) (state.StateDBI, *types.Header, error) {
if blockNr, ok := blockNrOrHash.Number(); ok {
return b.StateAndHeaderByNumber(ctx, blockNr)
}
@@ -228,7 +228,7 @@ func (b *EthAPIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int {
return nil
}
-func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) {
+func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state state.StateDBI, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) {
if vmConfig == nil {
vmConfig = b.eth.blockchain.GetVMConfig()
}
@@ -378,10 +378,10 @@ func (b *EthAPIBackend) StartMining(threads int) error {
return b.eth.StartMining(threads)
}
-func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, tracers.StateReleaseFunc, error) {
+func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base state.StateDBI, readOnly bool, preferDisk bool) (state.StateDBI, tracers.StateReleaseFunc, error) {
return b.eth.StateAtBlock(ctx, block, reexec, base, readOnly, preferDisk)
}
-func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
+func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, state.StateDBI, tracers.StateReleaseFunc, error) {
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
}
diff --git a/eth/api_test.go b/eth/api_test.go
index fca17f12171b..465dfcc6c27d 100644
--- a/eth/api_test.go
+++ b/eth/api_test.go
@@ -34,7 +34,7 @@ import (
var dumper = spew.ConfigState{Indent: " "}
-func accountRangeTest(t *testing.T, trie *state.Trie, statedb *state.StateDB, start common.Hash, requestedNum int, expectedNum int) state.IteratorDump {
+func accountRangeTest(t *testing.T, trie *state.Trie, statedb state.StateDBI, start common.Hash, requestedNum int, expectedNum int) state.IteratorDump {
result := statedb.IteratorDump(&state.DumpConfig{
SkipCode: true,
SkipStorage: true,
diff --git a/eth/backend.go b/eth/backend.go
index 6368c0e03c56..9ab37c790b7f 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -43,9 +43,9 @@ import (
"github.com/ethereum/go-ethereum/eth/gasprice"
"github.com/ethereum/go-ethereum/eth/protocols/eth"
"github.com/ethereum/go-ethereum/eth/protocols/snap"
+ "github.com/ethereum/go-ethereum/ethapi"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/internal/shutdowncheck"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/miner"
@@ -288,8 +288,7 @@ func makeExtraData(extra []byte) []byte {
// APIs return the collection of RPC services the ethereum package offers.
// NOTE, some of these services probably need to be moved to somewhere else.
func (s *Ethereum) APIs() []rpc.API {
- apis := ethapi.GetAPIs(s.APIBackend)
-
+ apis := ethapi.GetAPIs(s.APIBackend, s.BlockChain())
// Append any APIs exposed explicitly by the consensus engine
apis = append(apis, s.engine.APIs(s.BlockChain())...)
diff --git a/eth/filters/api.go b/eth/filters/api.go
index f9ae70eba796..e3b1a32d9986 100644
--- a/eth/filters/api.go
+++ b/eth/filters/api.go
@@ -29,7 +29,7 @@ import (
"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/internal/ethapi"
+ "github.com/ethereum/go-ethereum/ethapi"
"github.com/ethereum/go-ethereum/rpc"
)
diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go
index 9fc20f335b1a..662c3c0e38fd 100644
--- a/eth/filters/filter_system.go
+++ b/eth/filters/filter_system.go
@@ -553,7 +553,7 @@ func (es *EventSystem) lightFilterLogs(header *types.Header, addresses []common.
func (es *EventSystem) eventLoop() {
// Ensure all subscriptions get cleaned up
defer func() {
- es.txsSub.Unsubscribe()
+ // es.txsSub.Unsubscribe()
es.logsSub.Unsubscribe()
es.rmLogsSub.Unsubscribe()
es.pendingLogsSub.Unsubscribe()
diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go
index b70b0158ad00..242eec7383ef 100644
--- a/eth/filters/filter_system_test.go
+++ b/eth/filters/filter_system_test.go
@@ -35,9 +35,9 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/ethapi"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
)
diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go
index 13279fd96c43..5a47979981a0 100644
--- a/eth/protocols/snap/sync.go
+++ b/eth/protocols/snap/sync.go
@@ -84,8 +84,8 @@ const (
minTrienodeHealThrottle = 1
// maxTrienodeHealThrottle is the maximum divisor for throttling trie node
- // heal requests to avoid overloading the local node and exessively expanding
- // the state trie bedth wise.
+ // heal requests to avoid overloading the local node and excessively expanding
+ // the state trie breadth wise.
maxTrienodeHealThrottle = maxTrieRequestCount
// trienodeHealThrottleIncrease is the multiplier for the throttle when the
diff --git a/eth/state_accessor.go b/eth/state_accessor.go
index 59b471425542..3259777d4628 100644
--- a/eth/state_accessor.go
+++ b/eth/state_accessor.go
@@ -57,7 +57,7 @@ var noopReleaser = tracers.StateReleaseFunc(func() {})
// - preferDisk: this arg can be used by the caller to signal that even though the 'base' is
// provided, it would be preferable to start from a fresh state, if we have it
// on disk.
-func (eth *Ethereum) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (statedb *state.StateDB, release tracers.StateReleaseFunc, err error) {
+func (eth *Ethereum) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base state.StateDBI, readOnly bool, preferDisk bool) (statedb state.StateDBI, release tracers.StateReleaseFunc, err error) {
var (
current *types.Block
database state.Database
@@ -189,7 +189,7 @@ func (eth *Ethereum) StateAtBlock(ctx context.Context, block *types.Block, reexe
}
// stateAtTransaction returns the execution environment of a certain transaction.
-func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
+func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, state.StateDBI, tracers.StateReleaseFunc, error) {
// Short circuit if it's genesis block.
if block.NumberU64() == 0 {
return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis")
@@ -213,13 +213,15 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
for idx, tx := range block.Transactions() {
// Assemble the transaction call message and return if the requested offset
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
- txContext := core.NewEVMTxContext(msg)
context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil)
if idx == txIndex {
return msg, context, statedb, release, nil
}
// Not yet the searched for transaction, execute on top of the current state
- vmenv := vm.NewEVM(context, txContext, statedb, eth.blockchain.Config(), vm.Config{})
+ vmenv, vmError, err := eth.APIBackend.GetEVM(ctx, msg, statedb, block.Header(), &vm.Config{})
+ if err != nil {
+ return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("failed to get evm: %v", err)
+ }
statedb.SetTxContext(tx.Hash(), idx)
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
@@ -227,6 +229,9 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
// Ensure any modifications are committed to the state
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
+ if err := vmError(); err != nil {
+ return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("execution error: %v", err)
+ }
}
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash())
}
diff --git a/eth/tracers/api.go b/eth/tracers/api.go
index 58ad0c3c9ad7..db82fdb79f57 100644
--- a/eth/tracers/api.go
+++ b/eth/tracers/api.go
@@ -37,8 +37,8 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/tracers/logger"
+ "github.com/ethereum/go-ethereum/ethapi"
"github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
@@ -86,8 +86,8 @@ type Backend interface {
ChainConfig() *params.ChainConfig
Engine() consensus.Engine
ChainDb() ethdb.Database
- StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error)
- StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error)
+ StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base state.StateDBI, readOnly bool, preferDisk bool) (state.StateDBI, StateReleaseFunc, error)
+ StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, state.StateDBI, StateReleaseFunc, error)
}
// API is the collection of tracing APIs exposed over the private debugging endpoint.
@@ -207,7 +207,7 @@ type txTraceResult struct {
// blockTraceTask represents a single block trace task when an entire chain is
// being traced.
type blockTraceTask struct {
- statedb *state.StateDB // Intermediate state prepped for tracing
+ statedb state.StateDBI // Intermediate state prepped for tracing
block *types.Block // Block to trace the transactions from
release StateReleaseFunc // The function to release the held resource for this task
results []*txTraceResult // Trace results produced by the task
@@ -224,7 +224,7 @@ type blockTraceResult struct {
// txTraceTask represents a single transaction trace task when an entire block
// is being traced.
type txTraceTask struct {
- statedb *state.StateDB // Intermediate state prepped for tracing
+ statedb state.StateDBI // Intermediate state prepped for tracing
index int // Transaction offset in the block
}
@@ -332,7 +332,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
number uint64
traced uint64
failed error
- statedb *state.StateDB
+ statedb state.StateDBI
release StateReleaseFunc
)
// Ensure everything is properly cleaned up on any exit path
@@ -650,7 +650,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
// traceBlockParallel is for tracers that have a high overhead (read JS tracers). One thread
// runs along and executes txes without tracing enabled to generate their prestate.
// Worker threads take the tasks and the prestate and trace them.
-func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, statedb *state.StateDB, config *TraceConfig) ([]*txTraceResult, error) {
+func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, statedb state.StateDBI, config *TraceConfig) ([]*txTraceResult, error) {
// Execute all the transaction contained within the block concurrently
var (
txs = block.Transactions()
@@ -947,7 +947,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
// traceTx configures a new tracer according to the provided configuration, and
// executes the given message in the provided environment. The return value will
// be tracer dependent.
-func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
+func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb state.StateDBI, config *TraceConfig) (interface{}, error) {
var (
tracer Tracer
err error
diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go
index b1eaf60b16c4..e18678af6325 100644
--- a/eth/tracers/api_test.go
+++ b/eth/tracers/api_test.go
@@ -41,8 +41,8 @@ import (
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/tracers/logger"
+ "github.com/ethereum/go-ethereum/ethapi"
"github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
)
@@ -140,7 +140,7 @@ func (b *testBackend) teardown() {
b.chain.Stop()
}
-func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error) {
+func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base state.StateDBI, readOnly bool, preferDisk bool) (state.StateDBI, StateReleaseFunc, error) {
statedb, err := b.chain.StateAt(block.Root())
if err != nil {
return nil, nil, errStateNotFound
@@ -156,7 +156,7 @@ func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reex
return statedb, release, nil
}
-func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) {
+func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, state.StateDBI, StateReleaseFunc, error) {
parent := b.chain.GetBlock(block.ParentHash(), block.NumberU64()-1)
if parent == nil {
return nil, vm.BlockContext{}, nil, nil, errBlockNotFound
diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go
index 8e52f5b21077..49ddbe288b97 100644
--- a/eth/tracers/js/goja.go
+++ b/eth/tracers/js/goja.go
@@ -250,7 +250,7 @@ func (t *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Addr
t.ctx["block"] = t.vm.ToValue(env.Context.BlockNumber.Uint64())
// Update list of precompiles based on current block
rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil, env.Context.Time)
- t.activePrecompiles = vm.ActivePrecompiles(rules)
+ t.activePrecompiles = env.PrecompileManager.GetActive(&rules)
}
// CaptureState implements the Tracer interface to trace a single step of VM execution.
diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go
index 766ee4e4b95c..e4829bf5bba4 100644
--- a/eth/tracers/logger/access_list_tracer.go
+++ b/eth/tracers/logger/access_list_tracer.go
@@ -32,8 +32,8 @@ type accessList map[common.Address]accessListSlots
// contract that an EVM contract execution touches.
type accessListSlots map[common.Hash]struct{}
-// newAccessList creates a new accessList.
-func newAccessList() accessList {
+// NewAccessList creates a new accessList.
+func NewAccessList() accessList {
return make(map[common.Address]accessListSlots)
}
@@ -117,7 +117,7 @@ func NewAccessListTracer(acl types.AccessList, from, to common.Address, precompi
for _, addr := range precompiles {
excl[addr] = struct{}{}
}
- list := newAccessList()
+ list := NewAccessList()
for _, al := range acl {
if _, ok := excl[al.Address]; !ok {
list.addAddress(al.Address)
diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go
index 1b4649baa33e..6ae5092a9153 100644
--- a/eth/tracers/native/4byte.go
+++ b/eth/tracers/native/4byte.go
@@ -82,7 +82,7 @@ func (t *fourByteTracer) store(id []byte, size int) {
func (t *fourByteTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
// Update list of precompiles based on current block
rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil, env.Context.Time)
- t.activePrecompiles = vm.ActivePrecompiles(rules)
+ t.activePrecompiles = env.PrecompileManager.GetActive(&rules)
// Save the outer calldata also
if len(input) >= 4 {
diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go
index 5da60405062f..cb29b3617712 100644
--- a/eth/tracers/native/call_flat.go
+++ b/eth/tracers/native/call_flat.go
@@ -146,7 +146,7 @@ func (t *flatCallTracer) CaptureStart(env *vm.EVM, from common.Address, to commo
t.tracer.CaptureStart(env, from, to, create, input, gas, value)
// Update list of precompiles based on current block
rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil, env.Context.Time)
- t.activePrecompiles = vm.ActivePrecompiles(rules)
+ t.activePrecompiles = env.PrecompileManager.GetActive(&rules)
}
// CaptureEnd is called after the call finishes to finalize the tracing.
diff --git a/internal/ethapi/addrlock.go b/ethapi/addrlock.go
similarity index 100%
rename from internal/ethapi/addrlock.go
rename to ethapi/addrlock.go
diff --git a/internal/ethapi/api.go b/ethapi/api.go
similarity index 87%
rename from internal/ethapi/api.go
rename to ethapi/api.go
index 93a2d1264d32..418417f404a3 100644
--- a/internal/ethapi/api.go
+++ b/ethapi/api.go
@@ -18,6 +18,7 @@ package ethapi
import (
"context"
+ "crypto/rand"
"encoding/hex"
"errors"
"fmt"
@@ -47,6 +48,7 @@ import (
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
"github.com/tyler-smith/go-bip39"
+ "golang.org/x/crypto/sha3"
)
// EthereumAPI provides an API to access Ethereum related information.
@@ -878,7 +880,7 @@ type OverrideAccount struct {
type StateOverride map[common.Address]OverrideAccount
// Apply overrides the fields of specified accounts into the given state.
-func (diff *StateOverride) Apply(state *state.StateDB) error {
+func (diff *StateOverride) Apply(state state.StateDBI) error {
if diff == nil {
return nil
}
@@ -886,6 +888,9 @@ func (diff *StateOverride) Apply(state *state.StateDB) error {
// Override account nonce.
if account.Nonce != nil {
state.SetNonce(addr, uint64(*account.Nonce))
+ if err := state.Error(); err != nil {
+ return err
+ }
}
// Override account(contract) code.
if account.Code != nil {
@@ -894,6 +899,9 @@ func (diff *StateOverride) Apply(state *state.StateDB) error {
// Override account balance.
if account.Balance != nil {
state.SetBalance(addr, (*big.Int)(*account.Balance))
+ if err := state.Error(); err != nil {
+ return err
+ }
}
if account.State != nil && account.StateDiff != nil {
return fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex())
@@ -1449,8 +1457,9 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
to = crypto.CreateAddress(args.from(), uint64(*args.Nonce))
}
isPostMerge := header.Difficulty.Cmp(common.Big0) == 0
+ rules := b.ChainConfig().Rules(header.Number, isPostMerge, header.Time)
// Retrieve the precompiles since they don't need to be added to the access list
- precompiles := vm.ActivePrecompiles(b.ChainConfig().Rules(header.Number, isPostMerge, header.Time))
+ precompiles := vm.ActivePrecompiles(&rules) // TODO: use evm precompile manager instead
// Create an initial tracer
prevTracer := logger.NewAccessListTracer(nil, args.from(), to, precompiles)
@@ -2097,3 +2106,327 @@ func toHexSlice(b [][]byte) []string {
}
return r
}
+
+// --------------------------------------- FlashBots ------------------------------------------- //
+
+// BundleAPI offers an API for accepting bundled transactions. The BundleAPI has been heavily
+// inspired by the original mev-geth implementation.
+// (https://github.com/flashbots/mev-geth/blob/master/internal/ethapi/api.go#L2038)
+type BundleAPI struct {
+ b Backend
+ chain core.ChainContext
+}
+
+// NewBundleAPI creates a new Tx Bundle API instance.
+func NewBundleAPI(b Backend, chain core.ChainContext) *BundleAPI {
+ return &BundleAPI{b, chain}
+}
+
+// CallBundleArgs represents the arguinterface ments for a call.
+type CallBundleArgs struct {
+ Txs []hexutil.Bytes `json:"txs"`
+ BlockNumber rpc.BlockNumber `json:"blockNumber"`
+ StateBlockNumberOrHash rpc.BlockNumberOrHash `json:"stateBlockNumber"`
+ Coinbase *string `json:"coinbase"`
+ Timestamp *uint64 `json:"timestamp"`
+ Timeout *int64 `json:"timeout"`
+ GasLimit *uint64 `json:"gasLimit"`
+ Difficulty *big.Int `json:"difficulty"`
+ BaseFee *big.Int `json:"baseFee"`
+}
+
+// CallBundle will simulate a bundle of transactions at the top of a given block
+// number with the state of another (or the same) block. This can be used to
+// simulate future blocks with the current state, or it can be used to simulate
+// a past block.
+// The sender is responsible for signing the transactions and using the correct
+// nonce and ensuring validity
+func (s *BundleAPI) CallBundle(ctx context.Context, args CallBundleArgs) (map[string]interface{}, error) {
+ if len(args.Txs) == 0 {
+ return nil, errors.New("bundle missing txs")
+ }
+ if args.BlockNumber == 0 {
+ return nil, errors.New("bundle missing blockNumber")
+ }
+
+ var txs types.Transactions
+ for _, encodedTx := range args.Txs {
+ tx := new(types.Transaction)
+ if err := tx.UnmarshalBinary(encodedTx); err != nil {
+ return nil, err
+ }
+ txs = append(txs, tx)
+ }
+ defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
+
+ timeoutMilliSeconds := int64(5000)
+ if args.Timeout != nil {
+ timeoutMilliSeconds = *args.Timeout
+ }
+ timeout := time.Millisecond * time.Duration(timeoutMilliSeconds)
+ state, parent, err := s.b.StateAndHeaderByNumberOrHash(ctx, args.StateBlockNumberOrHash)
+ if state == nil || err != nil {
+ return nil, err
+ }
+ blockNumber := big.NewInt(int64(args.BlockNumber))
+
+ timestamp := parent.Time + 1
+ if args.Timestamp != nil {
+ timestamp = *args.Timestamp
+ }
+ coinbase := parent.Coinbase
+ if args.Coinbase != nil {
+ coinbase = common.HexToAddress(*args.Coinbase)
+ }
+ difficulty := parent.Difficulty
+ if args.Difficulty != nil {
+ difficulty = args.Difficulty
+ }
+ gasLimit := parent.GasLimit
+ if args.GasLimit != nil {
+ gasLimit = *args.GasLimit
+ }
+ var baseFee *big.Int
+ if args.BaseFee != nil {
+ baseFee = args.BaseFee
+ } else if s.b.ChainConfig().IsLondon(big.NewInt(args.BlockNumber.Int64())) {
+ baseFee = misc.CalcBaseFee(s.b.ChainConfig(), parent)
+ }
+ header := &types.Header{
+ ParentHash: parent.Hash(),
+ Number: blockNumber,
+ GasLimit: gasLimit,
+ Time: timestamp,
+ Difficulty: difficulty,
+ Coinbase: coinbase,
+ BaseFee: baseFee,
+ }
+ blockHash := header.Hash()
+
+ // Setup context so it may be cancelled the call has completed
+ // or, in case of unmetered gas, setup a context with a timeout.
+ var cancel context.CancelFunc
+ if timeout > 0 {
+ ctx, cancel = context.WithTimeout(ctx, timeout)
+ } else {
+ ctx, cancel = context.WithCancel(ctx)
+ }
+ // Make sure the context is cancelled when the call has completed
+ // this makes sure resources are cleaned up.
+ defer cancel()
+
+ // Setup the gas pool (also for unmetered requests)
+ // and apply the message.
+ gp := new(core.GasPool).AddGas(math.MaxUint64)
+
+ results := []map[string]interface{}{}
+ coinbaseBalanceBefore := state.GetBalance(coinbase)
+
+ bundleHash := sha3.NewLegacyKeccak256()
+ signer := types.MakeSigner(s.b.ChainConfig(), blockNumber)
+ var totalGasUsed uint64
+ gasFees := new(big.Int)
+
+ msg, err := core.TransactionToMessage(txs[0], signer, header.BaseFee)
+ if err != nil {
+ return nil, err
+ }
+
+ vmenv, vmError, err := s.b.GetEVM(ctx, msg, state, header, &vm.Config{})
+ if err != nil {
+ return nil, err
+ }
+
+ for i, tx := range txs {
+ coinbaseBalanceBeforeTx := state.GetBalance(coinbase)
+ state.SetTxContext(tx.Hash(), i)
+
+ receipt, result, err := core.ApplyTransactionWithEVMWithResult(
+ vmenv, s.b.ChainConfig(), gp, state, header.BaseFee, header.Number, blockHash, tx, &header.GasUsed,
+ )
+ if err != nil {
+ return nil, fmt.Errorf("err: %w; txhash %s", err, tx.Hash())
+ }
+ if err := vmError(); err != nil {
+ return nil, fmt.Errorf("execution error: %v", err)
+ }
+
+ txHash := tx.Hash().String()
+ from, err := types.Sender(signer, tx)
+ if err != nil {
+ return nil, fmt.Errorf("err: %w; txhash %s", err, tx.Hash())
+ }
+ to := "0x"
+ if tx.To() != nil {
+ to = tx.To().String()
+ }
+ jsonResult := map[string]interface{}{
+ "txHash": txHash,
+ "gasUsed": receipt.GasUsed,
+ "fromAddress": from.String(),
+ "toAddress": to,
+ }
+ totalGasUsed += receipt.GasUsed
+ gasPrice, err := tx.EffectiveGasTip(header.BaseFee)
+ if err != nil {
+ return nil, fmt.Errorf("err: %w; txhash %s", err, tx.Hash())
+ }
+ gasFeesTx := new(big.Int).Mul(big.NewInt(int64(receipt.GasUsed)), gasPrice)
+ gasFees.Add(gasFees, gasFeesTx)
+ bundleHash.Write(tx.Hash().Bytes())
+ if result.Err != nil {
+ jsonResult["error"] = result.Err.Error()
+ revert := result.Revert()
+ if len(revert) > 0 {
+ jsonResult["revert"] = string(revert)
+ }
+ } else {
+ dst := make([]byte, hex.EncodedLen(len(result.Return())))
+ hex.Encode(dst, result.Return())
+ jsonResult["value"] = "0x" + string(dst)
+ }
+ coinbaseDiffTx := new(big.Int).Sub(state.GetBalance(coinbase), coinbaseBalanceBeforeTx)
+ jsonResult["coinbaseDiff"] = coinbaseDiffTx.String()
+ jsonResult["gasFees"] = gasFeesTx.String()
+ jsonResult["ethSentToCoinbase"] = new(big.Int).Sub(coinbaseDiffTx, gasFeesTx).String()
+ jsonResult["gasPrice"] = new(big.Int).Div(coinbaseDiffTx, big.NewInt(int64(receipt.GasUsed))).String()
+ jsonResult["gasUsed"] = receipt.GasUsed
+ results = append(results, jsonResult)
+ }
+
+ ret := map[string]interface{}{}
+ ret["results"] = results
+ coinbaseDiff := new(big.Int).Sub(state.GetBalance(coinbase), coinbaseBalanceBefore)
+ ret["coinbaseDiff"] = coinbaseDiff.String()
+ ret["gasFees"] = gasFees.String()
+ ret["ethSentToCoinbase"] = new(big.Int).Sub(coinbaseDiff, gasFees).String()
+ ret["bundleGasPrice"] = new(big.Int).Div(coinbaseDiff, big.NewInt(int64(totalGasUsed))).String()
+ ret["totalGasUsed"] = totalGasUsed
+ ret["stateBlockNumber"] = parent.Number.Int64()
+
+ ret["bundleHash"] = "0x" + common.Bytes2Hex(bundleHash.Sum(nil))
+ return ret, nil
+}
+
+// EstimateGasBundleArgs represents the arguments for a call
+type EstimateGasBundleArgs struct {
+ Txs []TransactionArgs `json:"txs"`
+ BlockNumber rpc.BlockNumber `json:"blockNumber"`
+ StateBlockNumberOrHash rpc.BlockNumberOrHash `json:"stateBlockNumber"`
+ Coinbase *string `json:"coinbase"`
+ Timestamp *uint64 `json:"timestamp"`
+ Timeout *int64 `json:"timeout"`
+}
+
+func (s *BundleAPI) EstimateGasBundle(ctx context.Context, args EstimateGasBundleArgs) (map[string]interface{}, error) {
+ if len(args.Txs) == 0 {
+ return nil, errors.New("bundle missing txs")
+ }
+ if args.BlockNumber == 0 {
+ return nil, errors.New("bundle missing blockNumber")
+ }
+
+ timeoutMS := int64(5000)
+ if args.Timeout != nil {
+ timeoutMS = *args.Timeout
+ }
+ timeout := time.Millisecond * time.Duration(timeoutMS)
+
+ state, parent, err := s.b.StateAndHeaderByNumberOrHash(ctx, args.StateBlockNumberOrHash)
+ if state == nil || err != nil {
+ return nil, err
+ }
+ blockNumber := big.NewInt(int64(args.BlockNumber))
+ timestamp := parent.Time + 1
+ if args.Timestamp != nil {
+ timestamp = *args.Timestamp
+ }
+ coinbase := parent.Coinbase
+ if args.Coinbase != nil {
+ coinbase = common.HexToAddress(*args.Coinbase)
+ }
+
+ header := &types.Header{
+ ParentHash: parent.Hash(),
+ Number: blockNumber,
+ GasLimit: parent.GasLimit,
+ Time: timestamp,
+ Difficulty: parent.Difficulty,
+ Coinbase: coinbase,
+ BaseFee: parent.BaseFee,
+ }
+
+ // Setup context so it may be cancelled when the call
+ // has completed or, in case of unmetered gas, setup
+ // a context with a timeout
+ var cancel context.CancelFunc
+ if timeout > 0 {
+ ctx, cancel = context.WithTimeout(ctx, timeout)
+ } else {
+ ctx, cancel = context.WithCancel(ctx)
+ }
+
+ // Make sure the context is cancelled when the call has completed
+ // This makes sure resources are cleaned up
+ defer cancel()
+
+ // RPC Call gas cap
+ globalGasCap := s.b.RPCGasCap()
+
+ // Results
+ results := []map[string]interface{}{}
+
+ // Gas pool
+ gp := new(core.GasPool).AddGas(math.MaxUint64)
+
+ // Feed each of the transactions into the VM ctx
+ // And try and estimate the gas used
+ for i, txArgs := range args.Txs {
+ // Since its a txCall we'll just prepare the
+ // state with a random hash
+ var randomHash common.Hash
+ rand.Read(randomHash[:])
+
+ // New random hash since its a call
+ state.SetTxContext(randomHash, i)
+
+ // Convert tx args to msg to apply state transition
+ msg, err := txArgs.ToMessage(globalGasCap, header.BaseFee)
+ if err != nil {
+ return nil, err
+ }
+
+ // Get EVM Environment
+ vmenv, vmError, err := s.b.GetEVM(ctx, msg, state, header, &vm.Config{NoBaseFee: true})
+ if err != nil {
+ return nil, err
+ }
+
+ // Apply state transition
+ result, err := core.ApplyMessage(vmenv, msg, gp)
+ if err != nil {
+ return nil, err
+ }
+
+ // Check for the vm error
+ if err := vmError(); err != nil {
+ return nil, fmt.Errorf("execution error: %v", err)
+ }
+
+ // Modifications are committed to the state
+ // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
+ state.Finalise(vmenv.ChainConfig().IsEIP158(blockNumber))
+
+ // Append result
+ jsonResult := map[string]interface{}{
+ "gasUsed": result.UsedGas,
+ }
+ results = append(results, jsonResult)
+ }
+
+ // Return results
+ ret := map[string]interface{}{}
+ ret["results"] = results
+
+ return ret, nil
+}
diff --git a/internal/ethapi/api_test.go b/ethapi/api_test.go
similarity index 100%
rename from internal/ethapi/api_test.go
rename to ethapi/api_test.go
diff --git a/internal/ethapi/backend.go b/ethapi/backend.go
similarity index 93%
rename from internal/ethapi/backend.go
rename to ethapi/backend.go
index 98887afc803f..c74ef9dadc09 100644
--- a/internal/ethapi/backend.go
+++ b/ethapi/backend.go
@@ -63,12 +63,12 @@ type Backend interface {
BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error)
BlockByHash(ctx context.Context, hash common.Hash) (*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)
- StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error)
+ StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (state.StateDBI, *types.Header, error)
+ StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (state.StateDBI, *types.Header, error)
PendingBlockAndReceipts() (*types.Block, types.Receipts)
GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error)
GetTd(ctx context.Context, hash common.Hash) *big.Int
- GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error)
+ GetEVM(ctx context.Context, msg *core.Message, state state.StateDBI, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error)
SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription
@@ -99,7 +99,7 @@ type Backend interface {
ServiceFilter(ctx context.Context, session *bloombits.MatcherSession)
}
-func GetAPIs(apiBackend Backend) []rpc.API {
+func GetAPIs(apiBackend Backend, chain core.ChainContext) []rpc.API {
nonceLock := new(AddrLocker)
return []rpc.API{
{
@@ -123,6 +123,9 @@ func GetAPIs(apiBackend Backend) []rpc.API {
}, {
Namespace: "personal",
Service: NewPersonalAccountAPI(apiBackend, nonceLock),
+ }, {
+ Namespace: "eth",
+ Service: NewBundleAPI(apiBackend, chain),
},
}
}
diff --git a/internal/ethapi/dbapi.go b/ethapi/dbapi.go
similarity index 100%
rename from internal/ethapi/dbapi.go
rename to ethapi/dbapi.go
diff --git a/internal/ethapi/transaction_args.go b/ethapi/transaction_args.go
similarity index 100%
rename from internal/ethapi/transaction_args.go
rename to ethapi/transaction_args.go
diff --git a/internal/ethapi/transaction_args_test.go b/ethapi/transaction_args_test.go
similarity index 98%
rename from internal/ethapi/transaction_args_test.go
rename to ethapi/transaction_args_test.go
index 1b533861d5d6..b3ed71e3b64e 100644
--- a/internal/ethapi/transaction_args_test.go
+++ b/ethapi/transaction_args_test.go
@@ -291,10 +291,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) {
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) (state.StateDBI, *types.Header, error) {
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) (state.StateDBI, *types.Header, error) {
return nil, nil, nil
}
func (b *backendMock) PendingBlockAndReceipts() (*types.Block, types.Receipts) { return nil, nil }
@@ -305,7 +305,7 @@ func (b *backendMock) GetLogs(ctx context.Context, blockHash common.Hash, number
return nil, nil
}
func (b *backendMock) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil }
-func (b *backendMock) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) {
+func (b *backendMock) GetEVM(ctx context.Context, msg *core.Message, state state.StateDBI, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) {
return nil, nil, nil
}
func (b *backendMock) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { return nil }
diff --git a/ethclient/signer.go b/ethclient/signer.go
index f827d4eb56f4..9f1c247632eb 100644
--- a/ethclient/signer.go
+++ b/ethclient/signer.go
@@ -51,6 +51,16 @@ func (s *senderFromServer) Sender(tx *types.Transaction) (common.Address, error)
return s.addr, nil
}
+func (s *senderFromServer) PubKey(tx *types.Transaction) ([]byte, error) {
+ // not implemented
+ return nil, nil
+}
+
+func (s *senderFromServer) Signature(tx *types.Transaction) ([]byte, error) {
+ // not implemented
+ return nil, nil
+}
+
func (s *senderFromServer) ChainID() *big.Int {
panic("can't sign with senderFromServer")
}
diff --git a/graphql/graphql.go b/graphql/graphql.go
index 0c13cc80f555..cba51dbe1dd7 100644
--- a/graphql/graphql.go
+++ b/graphql/graphql.go
@@ -33,7 +33,7 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth/filters"
- "github.com/ethereum/go-ethereum/internal/ethapi"
+ "github.com/ethereum/go-ethereum/ethapi"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
)
@@ -83,7 +83,7 @@ type Account struct {
}
// 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.StateDBI, error) {
state, _, err := a.r.backend.StateAndHeaderByNumberOrHash(ctx, a.blockNrOrHash)
return state, err
}
@@ -1169,6 +1169,13 @@ type Resolver struct {
filterSystem *filters.FilterSystem
}
+func NewResolver(backend ethapi.Backend, filterSystem *filters.FilterSystem) *Resolver {
+ return &Resolver{
+ backend: backend,
+ filterSystem: filterSystem,
+ }
+}
+
func (r *Resolver) Block(ctx context.Context, args struct {
Number *Long
Hash *common.Hash
diff --git a/graphql/service.go b/graphql/service.go
index 4392dd83e688..0f004dfd3300 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -25,7 +25,7 @@ import (
"time"
"github.com/ethereum/go-ethereum/eth/filters"
- "github.com/ethereum/go-ethereum/internal/ethapi"
+ "github.com/ethereum/go-ethereum/ethapi"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc"
"github.com/graph-gophers/graphql-go"
@@ -103,15 +103,19 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
})
}
+type Registerable interface {
+ RegisterHandler(name string, path string, handler http.Handler)
+}
+
// New constructs a new GraphQL service instance.
-func New(stack *node.Node, backend ethapi.Backend, filterSystem *filters.FilterSystem, cors, vhosts []string) error {
+func New(stack Registerable, backend ethapi.Backend, filterSystem *filters.FilterSystem, cors, vhosts []string) error {
_, err := newHandler(stack, backend, filterSystem, cors, vhosts)
return err
}
// newHandler returns a new `http.Handler` that will answer GraphQL queries.
// It additionally exports an interactive query browser on the / endpoint.
-func newHandler(stack *node.Node, backend ethapi.Backend, filterSystem *filters.FilterSystem, cors, vhosts []string) (*handler, error) {
+func newHandler(stack Registerable, backend ethapi.Backend, filterSystem *filters.FilterSystem, cors, vhosts []string) (*handler, error) {
q := Resolver{backend, filterSystem}
s, err := graphql.ParseSchema(schema, &q)
diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go
index 388eed8a2fa6..974d404fca70 100644
--- a/internal/web3ext/web3ext.go
+++ b/internal/web3ext/web3ext.go
@@ -611,6 +611,16 @@ web3._extend({
params: 3,
inputFormatter: [web3._extend.formatters.inputCallFormatter, web3._extend.formatters.inputDefaultBlockNumberFormatter, null],
}),
+ new web3._extend.Method({
+ name: 'callBundle',
+ call: 'eth_callBundle',
+ params: 1,
+ }),
+ new web3._extend.Method({
+ name: 'estimateGasBundle',
+ call: 'eth_estimateGasBundle',
+ params: 1,
+ }),
],
properties: [
new web3._extend.Property({
diff --git a/les/api_backend.go b/les/api_backend.go
index 4b0369845a5a..575ad23e169e 100644
--- a/les/api_backend.go
+++ b/les/api_backend.go
@@ -138,7 +138,7 @@ func (b *LesApiBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts)
return nil, nil
}
-func (b *LesApiBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) {
+func (b *LesApiBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (state.StateDBI, *types.Header, error) {
header, err := b.HeaderByNumber(ctx, number)
if err != nil {
return nil, nil, err
@@ -149,7 +149,7 @@ func (b *LesApiBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.B
return light.NewState(ctx, header, b.eth.odr), header, nil
}
-func (b *LesApiBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) {
+func (b *LesApiBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (state.StateDBI, *types.Header, error) {
if blockNr, ok := blockNrOrHash.Number(); ok {
return b.StateAndHeaderByNumber(ctx, blockNr)
}
@@ -184,7 +184,7 @@ func (b *LesApiBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int {
return nil
}
-func (b *LesApiBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) {
+func (b *LesApiBackend) GetEVM(ctx context.Context, msg *core.Message, state state.StateDBI, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) {
if vmConfig == nil {
vmConfig = new(vm.Config)
}
@@ -326,10 +326,10 @@ func (b *LesApiBackend) CurrentHeader() *types.Header {
return b.eth.blockchain.CurrentHeader()
}
-func (b *LesApiBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, tracers.StateReleaseFunc, error) {
+func (b *LesApiBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base state.StateDBI, readOnly bool, preferDisk bool) (state.StateDBI, tracers.StateReleaseFunc, error) {
return b.eth.stateAtBlock(ctx, block, reexec)
}
-func (b *LesApiBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
+func (b *LesApiBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, state.StateDBI, tracers.StateReleaseFunc, error) {
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
}
diff --git a/les/client.go b/les/client.go
index 9ac85ecdac6f..bfbcbf65809c 100644
--- a/les/client.go
+++ b/les/client.go
@@ -33,8 +33,8 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/eth/gasprice"
+ "github.com/ethereum/go-ethereum/ethapi"
"github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/internal/shutdowncheck"
"github.com/ethereum/go-ethereum/les/downloader"
"github.com/ethereum/go-ethereum/les/vflux"
@@ -297,7 +297,7 @@ func (s *LightDummyAPI) Mining() bool {
// APIs returns the collection of RPC services the ethereum package offers.
// NOTE, some of these services probably need to be moved to somewhere else.
func (s *LightEthereum) APIs() []rpc.API {
- apis := ethapi.GetAPIs(s.ApiBackend)
+ apis := ethapi.GetAPIs(s.ApiBackend, s.BlockChain())
apis = append(apis, s.engine.APIs(s.BlockChain().HeaderChain())...)
return append(apis, []rpc.API{
{
diff --git a/les/odr_test.go b/les/odr_test.go
index 90b7cd08d7f5..811907dcf33c 100644
--- a/les/odr_test.go
+++ b/les/odr_test.go
@@ -92,7 +92,7 @@ func odrAccounts(ctx context.Context, db ethdb.Database, config *params.ChainCon
var (
res []byte
- st *state.StateDB
+ st state.StateDBI
err error
)
for _, addr := range acc {
diff --git a/les/state_accessor.go b/les/state_accessor.go
index 030d6b5a5004..a3ca551d887f 100644
--- a/les/state_accessor.go
+++ b/les/state_accessor.go
@@ -34,12 +34,12 @@ import (
var noopReleaser = tracers.StateReleaseFunc(func() {})
// stateAtBlock retrieves the state database associated with a certain block.
-func (leth *LightEthereum) stateAtBlock(ctx context.Context, block *types.Block, reexec uint64) (*state.StateDB, tracers.StateReleaseFunc, error) {
+func (leth *LightEthereum) stateAtBlock(ctx context.Context, block *types.Block, reexec uint64) (state.StateDBI, tracers.StateReleaseFunc, error) {
return light.NewState(ctx, block.Header(), leth.odr), noopReleaser, nil
}
// stateAtTransaction returns the execution environment of a certain transaction.
-func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
+func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, state.StateDBI, tracers.StateReleaseFunc, error) {
// Short circuit if it's genesis block.
if block.NumberU64() == 0 {
return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis")
diff --git a/light/odr_test.go b/light/odr_test.go
index 173298bb77f2..451263a729c9 100644
--- a/light/odr_test.go
+++ b/light/odr_test.go
@@ -154,7 +154,7 @@ func odrAccounts(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc
dummyAddr := common.HexToAddress("1234567812345678123456781234567812345678")
acc := []common.Address{testBankAddress, acc1Addr, acc2Addr, dummyAddr}
- var st *state.StateDB
+ var st state.StateDBI
if bc == nil {
header := lc.GetHeaderByHash(bhash)
st = NewState(ctx, header, lc.Odr())
@@ -183,7 +183,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
data[35] = byte(i)
var (
- st *state.StateDB
+ st state.StateDBI
header *types.Header
chain core.ChainContext
)
diff --git a/light/trie.go b/light/trie.go
index 0ccab1588d3d..137b98654ba0 100644
--- a/light/trie.go
+++ b/light/trie.go
@@ -35,7 +35,7 @@ var (
sha3Nil = crypto.Keccak256Hash(nil)
)
-func NewState(ctx context.Context, head *types.Header, odr OdrBackend) *state.StateDB {
+func NewState(ctx context.Context, head *types.Header, odr OdrBackend) state.StateDBI {
state, _ := state.New(head.Root, NewStateDatabase(ctx, head, odr), nil)
return state
}
diff --git a/light/txpool.go b/light/txpool.go
index e59dc3e77434..79f4dab391fe 100644
--- a/light/txpool.go
+++ b/light/txpool.go
@@ -114,7 +114,7 @@ func NewTxPool(config *params.ChainConfig, chain *LightChain, relay TxRelayBacke
}
// currentState returns the light state of the current head header
-func (pool *TxPool) currentState(ctx context.Context) *state.StateDB {
+func (pool *TxPool) currentState(ctx context.Context) state.StateDBI {
return NewState(ctx, pool.chain.CurrentHeader(), pool.odr)
}
diff --git a/miner/miner.go b/miner/miner.go
index c969aec73546..3b95b6620ef0 100644
--- a/miner/miner.go
+++ b/miner/miner.go
@@ -200,7 +200,7 @@ func (miner *Miner) SetRecommitInterval(interval time.Duration) {
}
// Pending returns the currently pending block and associated state.
-func (miner *Miner) Pending() (*types.Block, *state.StateDB) {
+func (miner *Miner) Pending() (*types.Block, state.StateDBI) {
return miner.worker.pending()
}
diff --git a/miner/miner_test.go b/miner/miner_test.go
index 6bf3edae5dbb..29c204622511 100644
--- a/miner/miner_test.go
+++ b/miner/miner_test.go
@@ -56,12 +56,12 @@ func (m *mockBackend) TxPool() *txpool.TxPool {
return m.txPool
}
-func (m *mockBackend) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (statedb *state.StateDB, err error) {
+func (m *mockBackend) StateAtBlock(block *types.Block, reexec uint64, base state.StateDBI, checkLive bool, preferDisk bool) (statedb state.StateDBI, err error) {
return nil, errors.New("not supported")
}
type testBlockChain struct {
- statedb *state.StateDB
+ statedb state.StateDBI
gasLimit uint64
chainHeadFeed *event.Feed
}
@@ -77,7 +77,7 @@ func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block
return types.NewBlock(bc.CurrentBlock(), nil, nil, nil, trie.NewStackTrie(nil))
}
-func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) {
+func (bc *testBlockChain) StateAt(common.Hash) (state.StateDBI, error) {
return bc.statedb, nil
}
diff --git a/miner/worker.go b/miner/worker.go
index 67a5842d23e0..47d22fa062bd 100644
--- a/miner/worker.go
+++ b/miner/worker.go
@@ -88,7 +88,7 @@ var (
type environment struct {
signer types.Signer
- state *state.StateDB // apply state changes here
+ state state.StateDBI // apply state changes here
ancestors mapset.Set[common.Hash] // ancestor set (used for checking uncle parent validity)
family mapset.Set[common.Hash] // family set (used for checking uncle invalidity)
tcount int // tx count in cycle
@@ -150,7 +150,7 @@ func (env *environment) discard() {
// task contains all information for consensus engine sealing and result submitting.
type task struct {
receipts []*types.Receipt
- state *state.StateDB
+ state state.StateDBI
block *types.Block
createdAt time.Time
}
@@ -236,7 +236,7 @@ type worker struct {
snapshotMu sync.RWMutex // The lock used to protect the snapshots below
snapshotBlock *types.Block
snapshotReceipts types.Receipts
- snapshotState *state.StateDB
+ snapshotState state.StateDBI
// atomic status counters
running int32 // The indicator whether the consensus engine is running or not.
@@ -381,7 +381,7 @@ func (w *worker) enablePreseal() {
}
// pending returns the pending state and corresponding block.
-func (w *worker) pending() (*types.Block, *state.StateDB) {
+func (w *worker) pending() (*types.Block, state.StateDBI) {
// return a snapshot to avoid contention on currentMu mutex
w.snapshotMu.RLock()
defer w.snapshotMu.RUnlock()
diff --git a/miner/worker_test.go b/miner/worker_test.go
index e60de679326c..9d106b317947 100644
--- a/miner/worker_test.go
+++ b/miner/worker_test.go
@@ -169,7 +169,7 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine
func (b *testWorkerBackend) BlockChain() *core.BlockChain { return b.chain }
func (b *testWorkerBackend) TxPool() *txpool.TxPool { return b.txPool }
-func (b *testWorkerBackend) StateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool, preferDisk bool) (statedb *state.StateDB, err error) {
+func (b *testWorkerBackend) StateAtBlock(block *types.Block, reexec uint64, base state.StateDBI, checkLive bool, preferDisk bool) (statedb state.StateDBI, err error) {
return nil, errors.New("not supported")
}
diff --git a/signer/core/api.go b/signer/core/api.go
index 3c1c94801b11..bdb3f6f7e0a9 100644
--- a/signer/core/api.go
+++ b/signer/core/api.go
@@ -33,7 +33,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
- "github.com/ethereum/go-ethereum/internal/ethapi"
+ "github.com/ethereum/go-ethereum/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
diff --git a/signer/core/api_test.go b/signer/core/api_test.go
index 9bb55bddca31..16a9cc59b533 100644
--- a/signer/core/api_test.go
+++ b/signer/core/api_test.go
@@ -31,7 +31,7 @@ import (
"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/internal/ethapi"
+ "github.com/ethereum/go-ethereum/ethapi"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/signer/core"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
diff --git a/signer/core/auditlog.go b/signer/core/auditlog.go
index a0b292bf714c..f13a42aa1b8f 100644
--- a/signer/core/auditlog.go
+++ b/signer/core/auditlog.go
@@ -22,7 +22,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
- "github.com/ethereum/go-ethereum/internal/ethapi"
+ "github.com/ethereum/go-ethereum/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
)
diff --git a/signer/core/cliui.go b/signer/core/cliui.go
index b1bd3206ed3f..4569260bdaf8 100644
--- a/signer/core/cliui.go
+++ b/signer/core/cliui.go
@@ -27,7 +27,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/console/prompt"
- "github.com/ethereum/go-ethereum/internal/ethapi"
+ "github.com/ethereum/go-ethereum/ethapi"
"github.com/ethereum/go-ethereum/log"
)
diff --git a/signer/core/stdioui.go b/signer/core/stdioui.go
index 6963a89122f6..9bd271c1345d 100644
--- a/signer/core/stdioui.go
+++ b/signer/core/stdioui.go
@@ -19,7 +19,7 @@ package core
import (
"context"
- "github.com/ethereum/go-ethereum/internal/ethapi"
+ "github.com/ethereum/go-ethereum/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
)
diff --git a/signer/rules/rules.go b/signer/rules/rules.go
index 5ed4514e0227..6ebe23148e5f 100644
--- a/signer/rules/rules.go
+++ b/signer/rules/rules.go
@@ -23,7 +23,7 @@ import (
"strings"
"github.com/dop251/goja"
- "github.com/ethereum/go-ethereum/internal/ethapi"
+ "github.com/ethereum/go-ethereum/ethapi"
"github.com/ethereum/go-ethereum/internal/jsre/deps"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/signer/core"
diff --git a/signer/rules/rules_test.go b/signer/rules/rules_test.go
index c35da8ecc188..a8dea13131d7 100644
--- a/signer/rules/rules_test.go
+++ b/signer/rules/rules_test.go
@@ -26,7 +26,7 @@ import (
"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/internal/ethapi"
+ "github.com/ethereum/go-ethereum/ethapi"
"github.com/ethereum/go-ethereum/signer/core"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/ethereum/go-ethereum/signer/storage"
diff --git a/tests/block_test_util.go b/tests/block_test_util.go
index b74653ea6acc..d986ac55aeaf 100644
--- a/tests/block_test_util.go
+++ b/tests/block_test_util.go
@@ -286,7 +286,7 @@ func validateHeader(h *btHeader, h2 *types.Header) error {
return nil
}
-func (t *BlockTest) validatePostState(statedb *state.StateDB) error {
+func (t *BlockTest) validatePostState(statedb state.StateDBI) error {
// validate post state accounts in test file against what we have in state db
for addr, acct := range t.json.Post {
// address is indirectly verified by the other fields, as it's the db key
diff --git a/tests/fuzzers/bls12381/precompile_fuzzer.go b/tests/fuzzers/bls12381/precompile_fuzzer.go
index cab2bcba3863..b9214661798c 100644
--- a/tests/fuzzers/bls12381/precompile_fuzzer.go
+++ b/tests/fuzzers/bls12381/precompile_fuzzer.go
@@ -18,6 +18,7 @@ package bls
import (
"bytes"
+ "context"
"fmt"
"github.com/ethereum/go-ethereum/common"
@@ -92,7 +93,7 @@ func fuzz(id byte, data []byte) int {
}
cpy := make([]byte, len(data))
copy(cpy, data)
- _, err := precompile.Run(cpy)
+ _, err := precompile.Run(context.Background(), nil, cpy, common.Address{}, nil, true)
if !bytes.Equal(cpy, data) {
panic(fmt.Sprintf("input data modified, precompile %d: %x %x", id, data, cpy))
}
diff --git a/tests/state_test.go b/tests/state_test.go
index 787427f01e45..4ad177d07759 100644
--- a/tests/state_test.go
+++ b/tests/state_test.go
@@ -239,7 +239,7 @@ func runBenchmark(b *testing.B, t *StateTest) {
b.ResetTimer()
for n := 0; n < b.N; n++ {
snapshot := statedb.Snapshot()
- statedb.Prepare(rules, msg.From, context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList)
+ statedb.Prepare(rules, msg.From, context.Coinbase, msg.To, evm.PrecompileManager.GetActive(&rules), msg.AccessList)
b.StartTimer()
start := time.Now()
diff --git a/tests/state_test_util.go b/tests/state_test_util.go
index 98acc468a1d8..f4389efd3e5b 100644
--- a/tests/state_test_util.go
+++ b/tests/state_test_util.go
@@ -182,7 +182,7 @@ func (t *StateTest) checkError(subtest StateSubtest, err error) error {
}
// Run executes a specific subtest and verifies the post-state and logs
-func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config, snapshotter bool) (*snapshot.Tree, *state.StateDB, error) {
+func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config, snapshotter bool) (*snapshot.Tree, state.StateDBI, error) {
snaps, statedb, root, err := t.RunNoVerify(subtest, vmconfig, snapshotter)
if checkedErr := t.checkError(subtest, err); checkedErr != nil {
return snaps, statedb, checkedErr
@@ -206,7 +206,7 @@ func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config, snapshotter bo
}
// RunNoVerify runs a specific subtest and returns the statedb and post-state root
-func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapshotter bool) (*snapshot.Tree, *state.StateDB, common.Hash, error) {
+func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapshotter bool) (*snapshot.Tree, state.StateDBI, common.Hash, error) {
config, eips, err := GetChainConfig(subtest.Fork)
if err != nil {
return nil, nil, common.Hash{}, UnsupportedForkError{subtest.Fork}
@@ -283,7 +283,7 @@ func (t *StateTest) gasLimit(subtest StateSubtest) uint64 {
return t.json.Tx.GasLimit[t.json.Post[subtest.Fork][subtest.Index].Indexes.Gas]
}
-func MakePreState(db ethdb.Database, accounts core.GenesisAlloc, snapshotter bool) (*snapshot.Tree, *state.StateDB) {
+func MakePreState(db ethdb.Database, accounts core.GenesisAlloc, snapshotter bool) (*snapshot.Tree, state.StateDBI) {
sdb := state.NewDatabase(db)
statedb, _ := state.New(common.Hash{}, sdb, nil)
for addr, a := range accounts {