diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 2faf274dbd7c..7f45b016283f 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -66,7 +66,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 @@ -180,7 +180,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() } @@ -619,7 +619,7 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs } } // Reject the transaction as invalid if it still fails at the highest allowance - if hi == cap { + if hi >= cap { failed, result, err := executable(hi) if err != nil { return 0, err @@ -640,7 +640,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/beacon/engine/errors.go b/beacon/engine/errors.go index 62773a0ea9f6..a08261da2a79 100644 --- a/beacon/engine/errors.go +++ b/beacon/engine/errors.go @@ -71,7 +71,7 @@ var ( SYNCING = "SYNCING" // ACCEPTED is returned by the engine API in the following calls: - // - newPayloadV1: if the payload was accepted, but not processed (side chain) + // - sV1: if the payload was accepted, but not processed (side chain) ACCEPTED = "ACCEPTED" GenericServerError = &EngineAPIError{code: -32000, msg: "Server error"} diff --git a/cmd/clef/main.go b/cmd/clef/main.go index 234699136990..9a860ce032bd 100644 --- a/cmd/clef/main.go +++ b/cmd/clef/main.go @@ -42,7 +42,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 a4ffd09e4fef..65dcc84eee33 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -117,7 +117,7 @@ type rejectedTx struct { // Apply applies a set of transactions to a pre-state func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, txIt txIterator, miningReward int64, - getTracerFn func(txIndex int, txHash common.Hash) (vm.EVMLogger, error)) (*state.StateDB, *ExecutionResult, []byte, error) { + getTracerFn func(txIndex int, txHash common.Hash) (vm.EVMLogger, error)) (state.StateDBI, *ExecutionResult, []byte, error) { // Capture errors for BLOCKHASH operation, if we haven't been supplied the // required blockhashes var hashError error @@ -245,7 +245,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, } includedTxs = append(includedTxs, tx) if hashError != nil { - return nil, nil, nil, NewError(ErrorMissingBlockhash, hashError) + return nil, nil, nil, New(ErrorMissingBlockhash, hashError) } gasUsed += msgResult.UsedGas @@ -352,7 +352,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, return statedb, execRs, body, 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(types.EmptyRootHash, sdb, nil) for addr, a := range accounts { diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index f3ffb3ed9f3e..f98769cf9226 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -118,7 +118,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/evm/staterunner.go b/cmd/evm/staterunner.go index 6e751b630f58..9fcf6122fb58 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -100,7 +100,7 @@ func runStateTest(fname string, cfg vm.Config, jsonOut, dump bool) error { for _, st := range test.Subtests() { // Run the test and aggregate the result result := &StatetestResult{Name: key, Fork: st.Fork, Pass: true} - test.Run(st, cfg, false, rawdb.HashScheme, func(err error, snaps *snapshot.Tree, statedb *state.StateDB) { + test.Run(st, cfg, false, rawdb.HashScheme, func(err error, snaps *snapshot.Tree, statedb state.StateDBI) { var root common.Hash if statedb != nil { root = statedb.IntermediateRoot(false) diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 5f52f1df5442..dd22102430a3 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -36,7 +36,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/eth/catalyst" "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 0d5939bd2032..c47d6fcb2b34 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 159c47ca0191..51f04976cbc7 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -51,11 +51,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/log" "github.com/ethereum/go-ethereum/metrics" @@ -1883,8 +1883,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 { filterSystem := filters.NewFilterSystem(backend, filters.Config{ LogCacheSize: ethcfg.FilterLogCacheSize, }) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index e856f4e6cead..6a8f67342fe1 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -347,7 +347,9 @@ func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.H } // Finalize implements consensus.Engine and processes withdrawals on top. -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) { beacon.ethone.Finalize(chain, header, state, txs, uncles, nil) return @@ -364,7 +366,9 @@ 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) { return beacon.ethone.FinalizeAndAssemble(chain, header, state, txs, uncles, receipts, nil) } diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index c693189ea5ef..c70d6e9fe400 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -580,13 +580,15 @@ func (c *Clique) Prepare(chain consensus.ChainHeaderReader, header *types.Header // Finalize implements consensus.Engine. There is no post-transaction // consensus rules in clique, do nothing here. -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 + header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) + header.UncleHash = types.CalcUncleHash(nil) } // 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 3a2c2d222916..535fc57ce92f 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -88,7 +88,7 @@ type Engine interface { // // Note: The 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 @@ -96,7 +96,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 130dfdf213bf..f7406d320a55 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -500,14 +500,14 @@ func (ethash *Ethash) Prepare(chain consensus.ChainHeaderReader, header *types.H } // Finalize implements consensus.Engine, accumulating the block and uncle rewards. -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 accumulateRewards(chain.Config(), state, header, uncles) } // 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") } @@ -569,7 +569,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 f3d65cea25ff..e343b7809751 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -20,6 +20,7 @@ import ( "errors" "fmt" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -27,18 +28,24 @@ import ( "github.com/ethereum/go-ethereum/trie" ) +type VBlockchain interface { + HasBlockAndState(hash common.Hash, number uint64) bool + HasBlock(hash common.Hash, number uint64) bool + consensus.ChainReader +} + // BlockValidator is responsible for validating block headers, uncles and // processed state. // // BlockValidator implements Validator. type BlockValidator struct { config *params.ChainConfig // Chain configuration options - bc *BlockChain // Canonical block chain + bc VBlockchain // Canonical block chain engine consensus.Engine // Consensus engine used for validating } // NewBlockValidator returns a new block validator which is safe for re-use -func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engine consensus.Engine) *BlockValidator { +func NewBlockValidator(config *params.ChainConfig, blockchain VBlockchain, engine consensus.Engine) *BlockValidator { validator := &BlockValidator{ config: config, engine: engine, @@ -121,7 +128,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { // ValidateState validates the various changes that happen after a state transition, // such as amount of used gas, the receipt roots and the state root itself. -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 f458da82573e..e398e749143a 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1385,7 +1385,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 { @@ -1473,7 +1473,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 } @@ -1484,7 +1484,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 } @@ -1710,7 +1710,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) 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 @@ -1794,7 +1794,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) 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) { + go func(start time.Time, followup *types.Block, throwaway state.StateDBI) { 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 466a86c14415..f30da1163312 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -320,15 +320,24 @@ 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) } +// StateAtBlockNumber returns a new mutable state based on a particular block number. +func (bc *BlockChain) StateAtBlockNumber(number uint64) (state.StateDBI, error) { + return bc.StateAt(bc.GetHeaderByNumber(number).Root) +} + +func (bc *BlockChain) GetOverridenState() (state.StateDBI, error) { + return state.New(bc.CurrentBlock().Root, bc.stateCache, bc.snaps) +} + // Config retrieves the chain's fork configuration. func (bc *BlockChain) Config() *params.ChainConfig { return bc.chainConfig } diff --git a/core/chain_makers.go b/core/chain_makers.go index 31c111b73e06..06e34472b119 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -41,7 +41,7 @@ type BlockGen struct { cm *chainMaker parent *types.Block header *types.Header - statedb *state.StateDB + statedb state.StateDBI gasPool *GasPool txs []*types.Transaction @@ -311,7 +311,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse } cm := newChainMaker(parent, config, engine) - genblock := func(i int, parent *types.Block, triedb *trie.Database, statedb *state.StateDB) (*types.Block, types.Receipts) { + genblock := func(i int, parent *types.Block, triedb *trie.Database, statedb state.StateDBI) (*types.Block, types.Receipts) { b := &BlockGen{i: i, cm: cm, parent: parent, statedb: statedb, engine: engine} b.header = cm.makeHeader(parent, statedb, b.engine) @@ -416,7 +416,7 @@ func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, return db, blocks, receipts } -func (cm *chainMaker) makeHeader(parent *types.Block, state *state.StateDB, engine consensus.Engine) *types.Header { +func (cm *chainMaker) makeHeader(parent *types.Block, state state.StateDBI, engine consensus.Engine) *types.Header { time := parent.Time() + 10 // block time is fixed at 10 seconds header := &types.Header{ Root: state.IntermediateRoot(cm.config.IsEIP158(parent.Number())), diff --git a/core/genesis.go b/core/genesis.go index 634be9a9e0b1..a335a66094eb 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -433,6 +433,11 @@ func (g *Genesis) ToBlock() *types.Block { if err != nil { panic(err) } + return g.ToBlockWithRoot(root) +} + +// ToBlockWithRoot returns the genesis block with the root overriden. +func (g *Genesis) ToBlockWithRoot(root common.Hash) *types.Block { head := &types.Header{ Number: new(big.Int).SetUint64(g.Number), Nonce: types.EncodeNonce(g.Nonce), diff --git a/core/headerchain.go b/core/headerchain.go index 519a32ab80aa..e7456971af1d 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -351,7 +351,7 @@ func (hc *HeaderChain) ValidateHeaderChain(chain []*types.Header) (int, error) { // otherwise they were all processed successfully. // // The returned 'write status' says if the inserted headers are part of the canonical chain -// or a side chain. +// or a s ide chain. func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, start time.Time, forker *ForkChoice) (WriteStatus, error) { if hc.procInterrupt() { return 0, errors.New("aborted") 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..6ef301761a44 --- /dev/null +++ b/core/state/interface.go @@ -0,0 +1,106 @@ +// 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) + + SelfDestruct(common.Address) + HasSelfDestructed(common.Address) bool + + Selfdestruct6780(common.Address) + + // Exist reports whether the given account exists in state. + // Notably this should also return true for self-destructed 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) + + Logs() []*types.Log + GetLogs(hash common.Hash, blockNumber uint64, blockHash common.Hash) []*types.Log + TxIndex() int + Preimages() map[common.Hash][]byte + + GetOrNewStateObject(addr common.Address) *StateObject + + DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey []byte) + Dump(opts *DumpConfig) []byte + RawDump(opts *DumpConfig) Dump + Database() Database + Error() error + SetBalance(addr common.Address, amount *big.Int) + SetStorage(addr common.Address, storage map[common.Hash]common.Hash) + GetStorageRoot(addr common.Address) common.Hash + Finalise(deleteEmptyObjects bool) + Commit(uint64, bool) (common.Hash, error) + Copy() StateDBI + SetTxContext(thash common.Hash, ti int) + StopPrefetcher() + StartPrefetcher(namespace string) + IntermediateRoot(deleteEmptyObjects bool) common.Hash + GetPrecompileManager() any +} diff --git a/core/state/journal.go b/core/state/journal.go index 137ec76395e5..f1e543391514 100644 --- a/core/state/journal.go +++ b/core/state/journal.go @@ -91,7 +91,7 @@ type ( } resetObjectChange struct { account *common.Address - prev *stateObject + prev *StateObject prevdestruct bool prevAccount []byte prevStorage map[common.Hash][]byte diff --git a/core/state/state_object.go b/core/state/state_object.go index 9383b98e4497..8f3545f5b65d 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -54,13 +54,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 as well as storages can be accessed and modified through the object. // - Finally, call commit to return the changes of storage trie and update account data. -type stateObject struct { +type StateObject struct { db *StateDB address common.Address // address of ethereum account addrHash common.Hash // hash of ethereum address of the account @@ -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, acct *types.StateAccount) *stateObject { +func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *StateObject { var ( origin = acct created = acct == nil // true if the account was not existent @@ -105,7 +105,7 @@ func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *s if acct == nil { acct = types.NewEmptyStateAccount() } - return &stateObject{ + return &StateObject{ db: db, address: address, addrHash: crypto.Keccak256Hash(address[:]), @@ -119,15 +119,15 @@ func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *s } // 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) } -func (s *stateObject) markSelfdestructed() { +func (s *StateObject) markSelfdestructed() { s.selfDestructed = true } -func (s *stateObject) touch() { +func (s *StateObject) touch() { s.db.journal.append(touchChange{ account: &s.address, }) @@ -141,7 +141,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() (Trie, error) { +func (s *StateObject) getTrie() (Trie, error) { if s.trie == nil { // Try fetching from prefetcher first if s.data.Root != types.EmptyRootHash && s.db.prefetcher != nil { @@ -160,7 +160,7 @@ func (s *stateObject) getTrie() (Trie, error) { } // GetState retrieves a value from the account storage trie. -func (s *stateObject) GetState(key common.Hash) common.Hash { +func (s *StateObject) GetState(key common.Hash) common.Hash { // If we have a dirty value for this state entry, return it value, dirty := s.dirtyStorage[key] if dirty { @@ -171,7 +171,7 @@ func (s *stateObject) GetState(key common.Hash) common.Hash { } // GetCommittedState retrieves a value from the committed account storage trie. -func (s *stateObject) GetCommittedState(key common.Hash) common.Hash { +func (s *StateObject) GetCommittedState(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 @@ -231,7 +231,7 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash { } // SetState updates a value in account storage. -func (s *stateObject) SetState(key, value common.Hash) { +func (s *StateObject) SetState(key, value common.Hash) { // If the new value is the same as old, don't set prev := s.GetState(key) if prev == value { @@ -246,13 +246,13 @@ func (s *stateObject) SetState(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 @@ -274,7 +274,7 @@ func (s *stateObject) finalise(prefetch bool) { // loading or updating of the trie, an error will be returned. Furthermore, // this function will return the mutated storage trie, or nil if there is no // storage change at all. -func (s *stateObject) updateTrie() (Trie, error) { +func (s *StateObject) updateTrie() (Trie, error) { // Make sure all dirty slots are finalized into the pending storage area s.finalise(false) @@ -362,7 +362,7 @@ func (s *stateObject) updateTrie() (Trie, error) { // updateRoot flushes all cached storage mutations to trie, recalculating the // new storage trie root. -func (s *stateObject) updateRoot() { +func (s *StateObject) updateRoot() { // Flush cached storage mutations into trie, short circuit if any error // is occurred or there is not change in the trie. tr, err := s.updateTrie() @@ -379,7 +379,7 @@ func (s *stateObject) updateRoot() { // commit obtains a set of dirty storage trie nodes and updates the account data. // The returned set can be nil if nothing to commit. This function assumes all // storage mutations have already been flushed into trie by updateRoot. -func (s *stateObject) commit() (*trienode.NodeSet, error) { +func (s *StateObject) commit() (*trienode.NodeSet, error) { // Short circuit if trie is not even loaded, don't bother with committing anything if s.trie == nil { s.origin = s.data.Copy() @@ -405,7 +405,7 @@ func (s *stateObject) commit() (*trienode.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 { @@ -419,14 +419,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), @@ -434,12 +434,12 @@ 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 { - obj := &stateObject{ +func (s *StateObject) deepCopy(db *StateDB) *StateObject { + obj := &StateObject{ db: db, address: s.address, addrHash: s.addrHash, @@ -464,12 +464,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() []byte { +func (s *StateObject) Code() []byte { if s.code != nil { return s.code } @@ -487,7 +487,7 @@ func (s *stateObject) Code() []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() int { +func (s *StateObject) CodeSize() int { if s.code != nil { return len(s.code) } @@ -501,7 +501,7 @@ func (s *stateObject) CodeSize() 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.journal.append(codeChange{ account: &s.address, @@ -511,13 +511,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, @@ -525,22 +525,22 @@ 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 } -func (s *stateObject) Root() common.Hash { +func (s *StateObject) Root() common.Hash { return s.data.Root } diff --git a/core/state/state_test.go b/core/state/state_test.go index 2f45ba44b4e4..2c476bdf0168 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -249,7 +249,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 905944cbb5b9..ddf37fa86149 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -79,7 +79,7 @@ type StateDB struct { // 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]*types.StateAccount // State objects destructed in the block along with its previous value @@ -106,7 +106,7 @@ type StateDB struct { preimages map[common.Hash][]byte // Per-transaction access list - accessList *accessList + accessList *AccessList // Transient storage transientStorage transientStorage @@ -155,14 +155,14 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) storages: make(map[common.Hash]map[common.Hash][]byte), accountsOrigin: make(map[common.Address][]byte), storagesOrigin: make(map[common.Address]map[common.Hash][]byte), - 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]*types.StateAccount), logs: make(map[common.Hash][]*types.Log), preimages: make(map[common.Hash][]byte), journal: newJournal(), - accessList: newAccessList(), + accessList: NewAccessList(), transientStorage: newTransientStorage(), hasher: crypto.NewKeccakState(), } @@ -172,6 +172,10 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) return sdb, nil } +func (s *StateDB) GetPrecompileManager() any { + return nil +} + // StartPrefetcher initializes a new trie prefetcher to pull in nodes from the // state trie concurrently while the state is mutated so that when we reach the // commit phase, most of the needed data is already hot. @@ -374,38 +378,38 @@ func (s *StateDB) HasSelfDestructed(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) } } @@ -499,7 +503,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()) @@ -531,7 +535,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()) @@ -546,7 +550,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 } @@ -557,7 +561,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 @@ -610,12 +614,12 @@ 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 { +func (s *StateDB) GetOrNewStateObject(addr common.Address) *StateObject { stateObject := s.getStateObject(addr) if stateObject == nil { stateObject, _ = s.createObject(addr) @@ -625,7 +629,7 @@ func (s *StateDB) GetOrNewStateObject(addr common.Address) *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! newobj = newObject(s, addr, nil) if prev == nil { @@ -682,9 +686,8 @@ func (s *StateDB) CreateAccount(addr common.Address) { } } -// 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 { +// GetOrNewStateObject retrieves a state object or create a new state object if nil. +func (s *StateDB) Copy() StateDBI { // Copy all the basic fields, initialize the memory ones state := &StateDB{ db: s.db, @@ -694,7 +697,7 @@ func (s *StateDB) Copy() *StateDB { storages: make(map[common.Hash]map[common.Hash][]byte), accountsOrigin: make(map[common.Address][]byte), storagesOrigin: make(map[common.Address]map[common.Hash][]byte), - 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]*types.StateAccount, len(s.stateObjectsDestruct)), @@ -1314,7 +1317,7 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er 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 df1cd5547d3d..b45ab4d6de91 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -173,10 +173,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++ { @@ -592,7 +592,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) } @@ -679,7 +679,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) } @@ -864,8 +864,8 @@ func TestStateDBAccessList(t *testing.T) { memDb := rawdb.NewMemoryDatabase() db := NewDatabase(memDb) - state, _ := New(types.EmptyRootHash, db, nil) - state.accessList = newAccessList() + state, _ := New(common.Hash{}, db, nil) + state.accessList = NewAccessList() verifyAddrs := func(astrings ...string) { t.Helper() @@ -1016,7 +1016,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 ff867309de30..c674468b9936 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 *atomic.Bool) { +func (p *statePrefetcher) Prefetch(block *types.Block, statedb state.StateDBI, cfg vm.Config, interrupt *atomic.Bool) { 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 9a4333f72330..8fc11fd23e13 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -31,18 +31,23 @@ import ( "github.com/ethereum/go-ethereum/params" ) +type SPBlockchain interface { + ChainContext + consensus.ChainHeaderReader +} + // StateProcessor is a basic Processor, which takes care of transitioning // state from one point to another. // // StateProcessor implements Processor. type StateProcessor struct { config *params.ChainConfig // Chain configuration options - bc *BlockChain // Canonical block chain + bc SPBlockchain // Canonical block chain engine consensus.Engine // Consensus engine used for block rewards } // NewStateProcessor initialises a new StateProcessor. -func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consensus.Engine) *StateProcessor { +func NewStateProcessor(config *params.ChainConfig, bc SPBlockchain, engine consensus.Engine) *StateProcessor { return &StateProcessor{ config: config, bc: bc, @@ -57,7 +62,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) @@ -104,7 +109,7 @@ 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(msg *Message, config *params.ChainConfig, gp *GasPool, statedb state.StateDBI, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) { // Create a new context to be used in the EVM environment. txContext := NewEVMTxContext(msg) evm.Reset(txContext, statedb) @@ -158,7 +163,7 @@ func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, sta // 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.Time), header.BaseFee) if err != nil { return nil, err @@ -172,7 +177,7 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo // ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root // contract. This method is exported to be used in tests. -func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB) { +func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb state.StateDBI) { // If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with // the new root msg := &Message{ diff --git a/core/state_transition.go b/core/state_transition.go index 540f63fda7ea..1435061673a1 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -406,7 +406,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, vm.ActivePrecompiles(st.evm, rules), msg.AccessList) var ( ret []byte diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 195697a8f6f7..83fe8e0fb614 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -303,7 +303,7 @@ type BlobPool struct { chain BlockChain // Chain object to access the state through head *types.Header // Current head of the chain - state *state.StateDB // Current state at the head of the chain + state state.StateDBI // Current state at the head of the chain gasTip *uint256.Int // Currently accepted minimum gas tip lookup map[common.Hash]uint64 // Lookup table mapping hashes to tx billy entries @@ -339,6 +339,18 @@ func (p *BlobPool) Filter(tx *types.Transaction) bool { return tx.Type() == types.BlobTxType } +func (p *BlobPool) PolarisRemove(hash common.Hash) { + p.lock.Lock() + defer p.lock.Unlock() + + if id, ok := p.lookup[hash]; ok { + if err := p.store.Delete(id); err != nil { + log.Error("Failed to delete blob transaction", "hash", hash, "err", err) + } + delete(p.lookup, hash) + } +} + // Init sets the gas price needed to keep a transaction in the pool and the chain // head to allow balance / nonce checks. The transaction journal will be loaded // from disk and filtered based on the provided starting settings. @@ -365,6 +377,9 @@ func (p *BlobPool) Init(gasTip *big.Int, head *types.Header, reserve txpool.Addr state, err := p.chain.StateAt(head.Root) if err != nil { state, err = p.chain.StateAt(types.EmptyRootHash) + if err != nil { + state, err = p.chain.StateAtBlockNumber(0) + } } if err != nil { return err diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index b709ad0e583f..ae5d110d2e92 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -158,7 +158,7 @@ func (bt *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block return 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/core/txpool/blobpool/interface.go b/core/txpool/blobpool/interface.go index 6f296a54bd63..2f0c3af46af5 100644 --- a/core/txpool/blobpool/interface.go +++ b/core/txpool/blobpool/interface.go @@ -40,5 +40,8 @@ type BlockChain interface { GetBlock(hash common.Hash, number uint64) *types.Block // StateAt returns a state database for a given root hash (generally the head). - StateAt(root common.Hash) (*state.StateDB, error) + StateAt(root common.Hash) (state.StateDBI, error) + + // StateAtBlockNumber returns a state database for a given block number. + StateAtBlockNumber(number uint64) (state.StateDBI, error) } diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index f7d4a2e1e186..d3d7cba30e91 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -115,7 +115,10 @@ type BlockChain interface { GetBlock(hash common.Hash, number uint64) *types.Block // StateAt returns a state database for a given root hash (generally the head). - StateAt(root common.Hash) (*state.StateDB, error) + StateAt(root common.Hash) (state.StateDBI, error) + + // StateAtBlockNumber returns a state database at the given block number. + StateAtBlockNumber(number uint64) (state.StateDBI, error) } // Config are the configuration parameters of the transaction pool. @@ -208,7 +211,7 @@ type LegacyPool struct { mu sync.RWMutex currentHead atomic.Pointer[types.Header] // Current head of the blockchain - 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 locals *accountSet // Set of local transaction to exempt from eviction rules @@ -300,6 +303,9 @@ func (pool *LegacyPool) Init(gasTip *big.Int, head *types.Header, reserve txpool statedb, err := pool.chain.StateAt(head.Root) if err != nil { statedb, err = pool.chain.StateAt(types.EmptyRootHash) + if err != nil { + statedb, err = pool.chain.StateAtBlockNumber(head.Number.Uint64()) + } } if err != nil { return err @@ -1064,6 +1070,10 @@ func (pool *LegacyPool) Has(hash common.Hash) bool { return pool.all.Get(hash) != nil } +func (pool *LegacyPool) PolarisRemove(hash common.Hash) { + pool.removeTx(hash, false, true) +} + // removeTx removes a single transaction from the queue, moving all subsequent // transactions back to the future queue. // @@ -1400,17 +1410,31 @@ func (pool *LegacyPool) reset(oldHead, newHead *types.Header) { } } // Initialize the internal state to the current head + // Initialize the internal state to the current head if newHead == nil { newHead = pool.chain.CurrentBlock() // Special case during testing } + if newHead == nil { + newHead = &types.Header{ + Number: big.NewInt(0), + } + } statedb, err := pool.chain.StateAt(newHead.Root) if err != nil { - log.Error("Failed to reset txpool state", "err", err) - return + // Beginning of Block Number X == the same as State Root of Block Number X-1 + statedb, err = pool.chain.StateAtBlockNumber(newHead.Number.Uint64() + 1) + if err != nil { + log.Warn("Failed to get new state", "err", err) + } } + pool.currentHead.Store(newHead) pool.currentState = statedb - pool.pendingNonces = newNoncer(statedb) + if pool.currentState != nil { + pool.pendingNonces = newNoncer(statedb) + } else { + pool.pendingNonces = &noncer{} + } // Inject any transactions discarded due to reorgs log.Debug("Reinjecting stale transactions", "count", len(reinject)) diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index 0366a58d61ab..9ea35b7e3d34 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -63,7 +63,7 @@ func init() { type testBlockChain struct { config *params.ChainConfig gasLimit atomic.Uint64 - statedb *state.StateDB + statedb state.StateDBI chainHeadFeed *event.Feed } @@ -88,7 +88,11 @@ 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 +} + +func (bc *testBlockChain) StateAtBlockNumber(uint64) (state.StateDBI, error) { return bc.statedb, nil } @@ -246,7 +250,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/txpool/legacypool/noncer.go b/core/txpool/legacypool/noncer.go index 2c65dd2caea7..ba1b9f4c880c 100644 --- a/core/txpool/legacypool/noncer.go +++ b/core/txpool/legacypool/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/subpool.go b/core/txpool/subpool.go index de05b38d433d..21d21b72142d 100644 --- a/core/txpool/subpool.go +++ b/core/txpool/subpool.go @@ -82,6 +82,8 @@ type SubPool interface { // one another. Init(gasTip *big.Int, head *types.Header, reserve AddressReserver) error + PolarisRemove(common.Hash) + // Close terminates any background processing threads and releases any held // resources. Close() error diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 0d4e05da4c18..27c225fb4c9f 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -170,6 +170,12 @@ func (p *TxPool) Close() error { return nil } +func (p *TxPool) Remove(txHash common.Hash) { + for _, subpool := range p.subpools { + subpool.PolarisRemove(txHash) + } +} + // loop is the transaction pool's main event loop, waiting for and reacting to // outside blockchain events as well as for various reporting and transaction // eviction events. diff --git a/core/txpool/validation.go b/core/txpool/validation.go index 0df363d81d87..2af18137139c 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -169,7 +169,7 @@ func validateBlobSidecar(hashes []common.Hash, sidecar *types.BlobTxSidecar) err // ValidationOptionsWithState define certain differences between stateful transaction // validation across the different pools without having to duplicate those checks. type ValidationOptionsWithState struct { - State *state.StateDB // State database to check nonces and balances against + State state.StateDBI // State database to check nonces and balances against // FirstNonceGap is an optional callback to retrieve the first nonce gap in // the list of pooled transactions of a specific account. If this method is diff --git a/core/types.go b/core/types.go index 36eb0d1dedbe..e2eb5912f59f 100644 --- a/core/types.go +++ b/core/types.go @@ -33,7 +33,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. @@ -41,7 +41,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 *atomic.Bool) + Prefetch(block *types.Block, statedb state.StateDBI, cfg vm.Config, interrupt *atomic.Bool) } // Processor is an interface for processing blocks using a given initial state. @@ -49,5 +49,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/vm/contracts.go b/core/vm/contracts.go index 574bb9bef6a8..065ddcbfae95 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -17,6 +17,7 @@ package vm import ( + "context" "crypto/sha256" "encoding/binary" "errors" @@ -38,8 +39,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) ([]byte, error) } // PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum @@ -148,44 +153,39 @@ func init() { } // ActivePrecompiles returns the precompiles enabled with the current configuration. -func ActivePrecompiles(rules params.Rules) []common.Address { +func ActivePrecompiles(evm *EVM, rules params.Rules) []common.Address { + var precompiles []common.Address switch { case rules.IsCancun: - return PrecompiledAddressesCancun + precompiles = append(precompiles, PrecompiledAddressesCancun...) case rules.IsBerlin: - return PrecompiledAddressesBerlin + precompiles = append(precompiles, PrecompiledAddressesBerlin...) case rules.IsIstanbul: - return PrecompiledAddressesIstanbul + precompiles = append(precompiles, PrecompiledAddressesIstanbul...) case rules.IsByzantium: - return PrecompiledAddressesByzantium + precompiles = append(precompiles, PrecompiledAddressesByzantium...) default: - return PrecompiledAddressesHomestead + precompiles = append(precompiles, PrecompiledAddressesHomestead...) } -} -// 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 + if evm != nil { + precompiles = append(precompiles, evm.PrecompileManager.GetActive(rules)...) } - suppliedGas -= gasCost - output, err := p.Run(input) - return output, suppliedGas, err + return precompiles } // 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) ([]byte, error) { const ecRecoverInputLength = 128 input = common.RightPadBytes(input, ecRecoverInputLength) @@ -219,6 +219,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 @@ -226,7 +230,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) ([]byte, error) { h := sha256.Sum256(input) return h[:], nil } @@ -234,6 +238,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 @@ -241,7 +249,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) ([]byte, error) { ripemd := ripemd160.New() ripemd.Write(input) return common.LeftPadBytes(ripemd.Sum(nil), 32), nil @@ -250,6 +258,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 @@ -257,8 +269,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) ([]byte, error) { + return input, nil } // bigModExp implements a native big integer exponential modular operation. @@ -266,6 +278,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) @@ -286,10 +302,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 { @@ -383,7 +400,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) ([]byte, error) { var ( baseLen = new(big.Int).SetBytes(getData(input, 0, 32)).Uint64() expLen = new(big.Int).SetBytes(getData(input, 32, 32)).Uint64() @@ -458,12 +475,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) ([]byte, error) { return runBn256Add(input) } @@ -471,12 +492,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) ([]byte, error) { return runBn256Add(input) } @@ -496,12 +521,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) ([]byte, error) { return runBn256ScalarMul(input) } @@ -509,12 +538,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) ([]byte, error) { return runBn256ScalarMul(input) } @@ -564,12 +597,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) ([]byte, error) { return runBn256Pairing(input) } @@ -577,17 +614,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) ([]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. @@ -608,7 +653,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) ([]byte, error) { // Make sure the input is valid (correct length and final flag) if len(input) != blake2FInputLength { return nil, errBlake2FInvalidInputLength @@ -657,12 +702,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) ([]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). @@ -695,12 +744,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) ([]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). @@ -731,6 +784,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 @@ -750,7 +807,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) ([]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). @@ -788,12 +845,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) ([]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). @@ -826,12 +887,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) ([]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). @@ -862,6 +927,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 @@ -881,7 +950,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) ([]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). @@ -919,12 +988,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) ([]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 @@ -998,12 +1071,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) ([]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. @@ -1033,12 +1110,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) ([]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. @@ -1072,6 +1153,10 @@ func (c *bls12381MapG2) Run(input []byte) ([]byte, error) { return g.EncodePoint(r), nil } +func (b *kzgPointEvaluation) RegistryKey() common.Address { + return common.BytesToAddress([]byte{19}) +} + // kzgPointEvaluation implements the EIP-4844 point evaluation precompile. type kzgPointEvaluation struct{} @@ -1093,7 +1178,7 @@ var ( ) // Run executes the point evaluation precompile. -func (b *kzgPointEvaluation) Run(input []byte) ([]byte, error) { +func (b *kzgPointEvaluation) Run(_ context.Context, _ PrecompileEVM, input []byte, _ common.Address, _ *big.Int) ([]byte, error) { if len(input) != blobVerifyInputLength { return nil, errBlobVerifyInvalidInputLength } diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go index f40e2c8f9ea3..df626fa85ebc 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" @@ -93,6 +95,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)) + 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 35f0a3f7c283..53dff56c823b 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -55,6 +55,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 088b18aaa4ff..a2a15d079ee6 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -17,6 +17,7 @@ package vm import ( + "errors" "math/big" "sync/atomic" @@ -52,6 +53,9 @@ func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) { precompiles = PrecompiledContractsHomestead } p, ok := precompiles[addr] + if p == nil || !ok { + p, ok = evm.PrecompileManager.Get(addr, &evm.chainRules) + } return p, ok } @@ -102,6 +106,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 @@ -146,6 +152,12 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time), } evm.interpreter = NewEVMInterpreter(evm) + if pm := statedb.GetPrecompileManager(); pm != nil { + evm.PrecompileManager = pm.(PrecompileManager) + } else { + evm.PrecompileManager = NewPrecompileManager() + } + return evm } @@ -224,7 +236,7 @@ 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, p, 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. @@ -246,7 +258,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: @@ -287,7 +299,7 @@ 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) + ret, gas, err = evm.PrecompileManager.Run(evm, p, 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. @@ -299,7 +311,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 } } @@ -332,7 +344,7 @@ 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) + ret, gas, err = evm.PrecompileManager.Run(evm, p, input, caller.Address(), new(big.Int), gas, false) } else { addrCopy := addr // Initialise a new contract and make initialise the delegate values @@ -343,7 +355,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 } } @@ -381,7 +393,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte } if p, isPrecompile := evm.precompile(addr); isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas) + ret, gas, err = evm.PrecompileManager.Run(evm, p, 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' @@ -399,7 +411,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 } } @@ -494,7 +506,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, // when we're in homestead this also counts for code storage gas errors. if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) { evm.StateDB.RevertToSnapshot(snapshot) - if err != ErrExecutionReverted { + if !errors.Is(err, ErrExecutionReverted) { contract.UseGas(contract.Gas) } } @@ -527,3 +539,5 @@ func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment * // ChainConfig returns the environment's chain configuration func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig } +func (evm *EVM) GetContext() *BlockContext { return &evm.Context } +func (evm *EVM) GetStateDB() StateDB { return evm.StateDB } diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index 807073336d6d..d408d80e9df6 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -595,7 +595,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 26814d3d2f0e..aa331078c45d 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" + "github.com/holiman/uint256" ) // StateDB is an EVM database for full state querying. @@ -78,6 +79,8 @@ type StateDB interface { AddLog(*types.Log) AddPreimage(common.Hash, []byte) + + GetPrecompileManager() any } // CallContext provides a basic interface for the EVM calling conventions. The EVM @@ -92,3 +95,30 @@ 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 { + // `Get` returns the precompiled contract at `addr`. Returns nil if no + // contract is found at `addr`. + Get(addr common.Address, rules *params.Rules) (PrecompiledContract, bool) + + 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..967a1a37b0b3 --- /dev/null +++ b/core/vm/precompile_manager.go @@ -0,0 +1,61 @@ +// 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 { +} + +// NewPrecompileManager returns a new PrecompileManager for the current chain rules. +func NewPrecompileManager() PrecompileManager { + return &precompileManager{} +} + +// Get returns the precompiled contract deployed at the given address. +func (pm *precompileManager) Get(addr common.Address, rules *params.Rules) (PrecompiledContract, bool) { + return nil, false +} + +// 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 { + return nil +} + +// 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, _ 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) + + return output, suppliedGas, err +} diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index d10457e7faa9..8e407ddbcd6a 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -49,7 +49,7 @@ type Config struct { BlobFeeCap *big.Int Random *common.Hash - State *state.StateDB + State state.StateDBI GetHashFn func(n uint64) common.Hash } @@ -107,7 +107,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) } @@ -125,7 +125,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, vm.ActivePrecompiles(vmenv, rules), nil) cfg.State.CreateAccount(address) // set the receiver's (the executing contract) code for execution. cfg.State.SetCode(address, code) @@ -158,7 +158,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, vm.ActivePrecompiles(vmenv, rules), nil) // Call the code with the given configuration. code, address, leftOverGas, err := vmenv.Create( sender, @@ -186,7 +186,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, vm.ActivePrecompiles(vmenv, rules), nil) // Call the code with the given configuration. ret, leftOverGas, err := vmenv.Call( diff --git a/eth/api_backend.go b/eth/api_backend.go index 84eb200095cd..914287d035a4 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -186,7 +186,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() @@ -210,7 +210,7 @@ func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.B return stateDb, header, nil } -func (b *EthAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { +func (b *EthAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (state.StateDBI, *types.Header, error) { if blockNr, ok := blockNrOrHash.Number(); ok { return b.StateAndHeaderByNumber(ctx, blockNr) } @@ -249,7 +249,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, blockCtx *vm.BlockContext) *vm.EVM { +func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state state.StateDBI, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM { if vmConfig == nil { vmConfig = b.eth.blockchain.GetVMConfig() } @@ -263,6 +263,11 @@ func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *st return vm.NewEVM(context, txContext, state, b.eth.blockchain.Config(), *vmConfig) } +func (b *EthAPIBackend) GetBlockContext(ctx context.Context, header *types.Header) *vm.BlockContext { + blockContext := core.NewEVMBlockContext(header, b.eth.BlockChain(), nil) + return &blockContext +} + func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { return b.eth.BlockChain().SubscribeRemovedLogsEvent(ch) } @@ -408,10 +413,10 @@ func (b *EthAPIBackend) StartMining() error { return b.eth.StartMining() } -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_debug.go b/eth/api_debug.go index 05010a3969c6..d2f971768f20 100644 --- a/eth/api_debug.go +++ b/eth/api_debug.go @@ -28,7 +28,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "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/log" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" @@ -134,7 +134,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.Dump, error) { - var stateDb *state.StateDB + var stateDb state.StateDBI var err error if number, ok := blockNrOrHash.Number(); ok { @@ -229,7 +229,7 @@ func (api *DebugAPI) StorageRangeAt(ctx context.Context, blockNrOrHash rpc.Block return storageRangeAt(statedb, block.Root(), contractAddress, keyStart, maxResult) } -func storageRangeAt(statedb *state.StateDB, root common.Hash, address common.Address, start []byte, maxResult int) (StorageRangeResult, error) { +func storageRangeAt(statedb state.StateDBI, root common.Hash, address common.Address, start []byte, maxResult int) (StorageRangeResult, error) { storageRoot := statedb.GetStorageRoot(address) if storageRoot == types.EmptyRootHash || storageRoot == (common.Hash{}) { return StorageRangeResult{}, nil // empty storage diff --git a/eth/api_debug_test.go b/eth/api_debug_test.go index 184b90dd09ad..2effbc7f63c6 100644 --- a/eth/api_debug_test.go +++ b/eth/api_debug_test.go @@ -36,7 +36,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.Dump { +func accountRangeTest(t *testing.T, trie *state.Trie, statedb state.StateDBI, start common.Hash, requestedNum int, expectedNum int) state.Dump { result := statedb.RawDump(&state.DumpConfig{ SkipCode: true, SkipStorage: true, diff --git a/eth/backend.go b/eth/backend.go index 774ffaf24877..276af2e86dea 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -44,9 +44,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" @@ -250,7 +250,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } eth.miner = miner.New(eth, &config.Miner, eth.blockchain.Config(), eth.EventMux(), eth.engine, eth.isLocalBlock) - eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData)) + eth.miner.SetExtra(MakeExtraData(config.Miner.ExtraData)) eth.APIBackend = &EthAPIBackend{stack.Config().ExtRPCEnabled(), stack.Config().AllowUnprotectedTxs, eth, nil} if eth.APIBackend.allowUnprotectedTxs { @@ -287,7 +287,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { return eth, nil } -func makeExtraData(extra []byte) []byte { +func MakeExtraData(extra []byte) []byte { if len(extra) == 0 { // create default extradata extra, _ = rlp.EncodeToBytes([]interface{}{ @@ -307,8 +307,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())...) @@ -476,6 +475,7 @@ func (s *Ethereum) Miner() *miner.Miner { return s.miner } func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain } +func (s *Ethereum) MinerChain() miner.BlockChain { return s.blockchain } func (s *Ethereum) TxPool() *txpool.TxPool { return s.txPool } func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux } func (s *Ethereum) Engine() consensus.Engine { return s.engine } diff --git a/eth/catalyst/queue.go b/eth/catalyst/queue.go index 634dc1b2e6c2..5bca4ad9037a 100644 --- a/eth/catalyst/queue.go +++ b/eth/catalyst/queue.go @@ -72,7 +72,7 @@ func (q *payloadQueue) put(id engine.PayloadID, payload *miner.Payload) { } } -// get retrieves a previously stored payload item or nil if it does not exist. +// get retrieves a previously stored payload item or nil if it does not exi func (q *payloadQueue) get(id engine.PayloadID, full bool) *engine.ExecutionPayloadEnvelope { q.lock.RLock() defer q.lock.RUnlock() diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index f1cfa92d5d69..f1bed65ae300 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -359,6 +359,7 @@ func (d *Downloader) LegacySync(id string, head common.Hash, td, ttd *big.Int, m // it will use the best peer possible and synchronize if its TD is higher than our own. If any of the // checks fail an error will be returned. This method is synchronous func (d *Downloader) synchronise(id string, hash common.Hash, td, ttd *big.Int, mode SyncMode, beaconMode bool, beaconPing chan struct{}) error { + fmt.Println("\n\n\n SYNCING FROM PEER", id, "\n\n\n") // The beacon header syncer is async. It will start this synchronization and // will continue doing other tasks. However, if synchronization needs to be // cancelled, the syncer needs to know if we reached the startup point (and diff --git a/eth/filters/api.go b/eth/filters/api.go index a4eaa9cec805..9cafe50c9786 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_test.go b/eth/filters/filter_system_test.go index 27cad8826aa0..0b3349b32e0b 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/gasestimator/gasestimator.go b/eth/gasestimator/gasestimator.go index a36c6707479d..02dbcc05c1a5 100644 --- a/eth/gasestimator/gasestimator.go +++ b/eth/gasestimator/gasestimator.go @@ -41,7 +41,7 @@ type Options struct { Config *params.ChainConfig // Chain configuration for hard fork selection Chain core.ChainContext // Chain context to access past block hashes Header *types.Header // Header defining the block context to execute in - State *state.StateDB // Pre-state on top of which to estimate the gas + State state.StateDBI // Pre-state on top of which to estimate the gas ErrorRatio float64 // Allowed overestimation ratio for faster estimation termination } diff --git a/eth/gasprice/gasprice.go b/eth/gasprice/gasprice.go index b71964981145..d4f7d6774dd9 100644 --- a/eth/gasprice/gasprice.go +++ b/eth/gasprice/gasprice.go @@ -18,6 +18,7 @@ package gasprice import ( "context" + "fmt" "math/big" "sync" @@ -156,6 +157,7 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) { lastHead, lastPrice := oracle.lastHead, oracle.lastPrice oracle.cacheLock.RUnlock() if headHash == lastHead { + // fmt.Println("CACHE 1 HEAD HAD LAST HEAD", lastPrice, headHash) return new(big.Int).Set(lastPrice), nil } oracle.fetchLock.Lock() @@ -166,6 +168,7 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) { lastHead, lastPrice = oracle.lastHead, oracle.lastPrice oracle.cacheLock.RUnlock() if headHash == lastHead { + // fmt.Println("CACHE 2 HEAD HAD LAST HEAD", lastPrice, headHash) return new(big.Int).Set(lastPrice), nil } var ( @@ -185,6 +188,7 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) { res := <-result if res.err != nil { close(quit) + fmt.Println("CLOSE QUIT", lastPrice) return new(big.Int).Set(lastPrice), res.err } exp-- @@ -219,6 +223,7 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) { oracle.lastPrice = price oracle.cacheLock.Unlock() + fmt.Println("RETURNING SUGGEST TIP CAP", price) return new(big.Int).Set(price), nil } diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 24694df66c36..42303e5dae79 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -37,7 +37,7 @@ import ( // for releasing state. var noopReleaser = tracers.StateReleaseFunc(func() {}) -func (eth *Ethereum) hashState(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) hashState(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 @@ -174,7 +174,7 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u return statedb, func() { triedb.Dereference(block.Root()) }, nil } -func (eth *Ethereum) pathState(block *types.Block) (*state.StateDB, func(), error) { +func (eth *Ethereum) pathState(block *types.Block) (state.StateDBI, func(), error) { // Check if the requested state is available in the live chain. statedb, err := eth.blockchain.StateAt(block.Root()) if err == nil { @@ -208,7 +208,7 @@ func (eth *Ethereum) pathState(block *types.Block) (*state.StateDB, func(), erro // - 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) { if eth.blockchain.TrieDB().Scheme() == rawdb.HashScheme { return eth.hashState(ctx, block, reexec, base, readOnly, preferDisk) } @@ -216,7 +216,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") diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 7c0028601dfb..c78dea5f0e6d 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -36,8 +36,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" @@ -85,8 +85,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. @@ -184,7 +184,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 @@ -201,7 +201,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 } @@ -309,7 +309,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 @@ -627,7 +627,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() @@ -873,7 +873,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc var ( err error block *types.Block - statedb *state.StateDB + statedb state.StateDBI release StateReleaseFunc ) if hash, ok := blockNrOrHash.Hash(); ok { @@ -934,7 +934,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 49c3ebb67d7f..25ddef77a7d8 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -39,8 +39,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" "golang.org/x/exp/slices" @@ -139,7 +139,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 @@ -155,7 +155,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 07c138bae47b..341919521a27 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -280,7 +280,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 = vm.ActivePrecompiles(env, 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 5a2c4f91115f..6140e4072232 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 = vm.ActivePrecompiles(env, 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 266ab9900146..2670faffa407 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -148,7 +148,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 = vm.ActivePrecompiles(env, 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 99% rename from internal/ethapi/api.go rename to ethapi/api.go index c0b28e4b69ea..0beb81985452 100644 --- a/internal/ethapi/api.go +++ b/ethapi/api.go @@ -950,7 +950,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 } @@ -958,6 +958,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 { @@ -966,6 +969,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()) @@ -1063,7 +1069,7 @@ func (context *ChainContext) GetHeader(hash common.Hash, number uint64) *types.H return header } -func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, overrides *StateOverride, blockOverrides *BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) { +func doCall(ctx context.Context, b Backend, args TransactionArgs, state state.StateDBI, header *types.Header, overrides *StateOverride, blockOverrides *BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) { if err := overrides.Apply(state); err != nil { return nil, err } @@ -1084,11 +1090,11 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.S if err != nil { return nil, err } - blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil) + blockCtx := b.GetBlockContext(ctx, header) if blockOverrides != nil { - blockOverrides.Apply(&blockCtx) + blockOverrides.Apply(blockCtx) } - evm := b.GetEVM(ctx, msg, state, header, &vm.Config{NoBaseFee: true}, &blockCtx) + evm := b.GetEVM(ctx, msg, state, header, &vm.Config{NoBaseFee: true}, blockCtx) // Wait for the context to be done and cancel the evm. Even if the // EVM has finished, cancelling may be done (repeatedly) @@ -1519,8 +1525,14 @@ 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)) + state, _, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) + if err != nil { + return nil, 0, nil, err + } + + precompiles := vm.ActivePrecompiles(vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, state, b.ChainConfig(), vm.Config{}), rules) // TODO: use evm precompile manager instead // Create an initial tracer prevTracer := logger.NewAccessListTracer(nil, args.from(), to, precompiles) diff --git a/internal/ethapi/api_test.go b/ethapi/api_test.go similarity index 99% rename from internal/ethapi/api_test.go rename to ethapi/api_test.go index c2490ac70315..426ca45a55ef 100644 --- a/internal/ethapi/api_test.go +++ b/ethapi/api_test.go @@ -501,7 +501,7 @@ func (b testBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc. func (b testBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) { return b.chain.GetBlock(hash, uint64(number.Int64())).Body(), nil } -func (b testBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { +func (b testBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (state.StateDBI, *types.Header, error) { if number == rpc.PendingBlockNumber { panic("pending state not implemented") } @@ -515,7 +515,7 @@ func (b testBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.Bloc stateDb, err := b.chain.StateAt(header.Root) return stateDb, header, err } -func (b testBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { +func (b testBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (state.StateDBI, *types.Header, error) { if blockNr, ok := blockNrOrHash.Number(); ok { return b.StateAndHeaderByNumber(ctx, blockNr) } @@ -536,7 +536,7 @@ func (b testBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int { } return big.NewInt(1) } -func (b testBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockContext *vm.BlockContext) *vm.EVM { +func (b testBackend) GetEVM(ctx context.Context, msg *core.Message, state state.StateDBI, header *types.Header, vmConfig *vm.Config, blockContext *vm.BlockContext) *vm.EVM { if vmConfig == nil { vmConfig = b.chain.GetVMConfig() } @@ -547,6 +547,10 @@ func (b testBackend) GetEVM(ctx context.Context, msg *core.Message, state *state } return vm.NewEVM(context, txContext, state, b.chain.Config(), *vmConfig) } +func (b testBackend) GetBlockContext(ctx context.Context, header *types.Header) *vm.BlockContext { + blockContext := core.NewEVMBlockContext(header, b.chain, nil) + return &blockContext +} func (b testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { panic("implement me") } 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 50f338f5cab3..1b0a554c2d8e 100644 --- a/internal/ethapi/backend.go +++ b/ethapi/backend.go @@ -41,8 +41,8 @@ import ( // both full and light clients) with access to necessary functions. type Backend interface { // General Ethereum API + GetBlockContext(context.Context, *types.Header) *vm.BlockContext SyncProgress() ethereum.SyncProgress - SuggestGasTipCap(ctx context.Context) (*big.Int, error) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) ChainDb() ethdb.Database @@ -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, blockCtx *vm.BlockContext) *vm.EVM + GetEVM(ctx context.Context, msg *core.Message, state state.StateDBI, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM 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{ { 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 97% rename from internal/ethapi/transaction_args_test.go rename to ethapi/transaction_args_test.go index ab7c2f70edfa..209bec2683ab 100644 --- a/internal/ethapi/transaction_args_test.go +++ b/ethapi/transaction_args_test.go @@ -313,10 +313,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 } @@ -327,7 +327,10 @@ 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, blockCtx *vm.BlockContext) *vm.EVM { +func (b *backendMock) GetEVM(ctx context.Context, msg *core.Message, state state.StateDBI, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM { + return nil +} +func (b *backendMock) GetBlockContext(ctx context.Context, header *types.Header) *vm.BlockContext { return 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 49be23af69dd..ec246cedd3b8 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -35,7 +35,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" ) @@ -86,7 +86,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 } diff --git a/graphql/service.go b/graphql/service.go index 584165bdb802..f6f20c34a3d6 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" diff --git a/miner/miner.go b/miner/miner.go index b7273948f5e7..cf41628bf05a 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" @@ -39,10 +40,24 @@ import ( // Backend wraps all methods required for mining. Only full node is capable // to offer all the functions here. type Backend interface { - BlockChain() *core.BlockChain + MinerChain() BlockChain TxPool() *txpool.TxPool } +type BlockChain interface { + GetVMConfig() *vm.Config + Engine() consensus.Engine + CurrentBlock() *types.Header + StateAt(common.Hash) (state.StateDBI, error) + StateAtBlockNumber(uint64) (state.StateDBI, error) + GetBlockByHash(common.Hash) *types.Block + consensus.ChainHeaderReader + HasBlock(common.Hash, uint64) bool + SubscribeChainHeadEvent(chan<- core.ChainHeadEvent) event.Subscription + WriteBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state state.StateDBI, emitHeadEvent bool) (status core.WriteStatus, err error) + GetOverridenState() (state.StateDBI, error) +} + // Config is the configuration parameters of mining. type Config struct { Etherbase common.Address `toml:",omitempty"` // Public address for block mining rewards @@ -204,7 +219,7 @@ func (miner *Miner) SetRecommitInterval(interval time.Duration) { // Pending returns the currently pending block and associated state. The returned // values can be nil in case the pending block is not initialized -func (miner *Miner) Pending() (*types.Block, *state.StateDB) { +func (miner *Miner) Pending() (*types.Block, state.StateDBI) { return miner.worker.pending() } @@ -224,6 +239,12 @@ func (miner *Miner) PendingBlockAndReceipts() (*types.Block, types.Receipts) { return miner.worker.pendingBlockAndReceipts() } +// Etherbase returns the current etherbase address used by the miner for mining. +func (miner *Miner) Etherbase() common.Address { + return miner.worker.etherbase() +} + +// SetEtherbase sets the etherbase address used by the miner for mining. func (miner *Miner) SetEtherbase(addr common.Address) { miner.worker.setEtherbase(addr) } diff --git a/miner/miner_test.go b/miner/miner_test.go index 411d6026ce9f..36102f9d9765 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -40,7 +40,7 @@ import ( ) type mockBackend struct { - bc *core.BlockChain + bc BlockChain txPool *txpool.TxPool } @@ -51,7 +51,11 @@ func NewMockBackend(bc *core.BlockChain, txPool *txpool.TxPool) *mockBackend { } } -func (m *mockBackend) BlockChain() *core.BlockChain { +func (m *mockBackend) BlockChain() BlockChain { + return m.bc +} + +func (m *mockBackend) MinerChain() BlockChain { return m.bc } @@ -59,14 +63,14 @@ 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 { root common.Hash config *params.ChainConfig - statedb *state.StateDB + statedb state.StateDBI gasLimit uint64 chainHeadFeed *event.Feed } @@ -86,7 +90,11 @@ 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 +} + +func (bc *testBlockChain) StateAtBlockNumber(uint64) (state.StateDBI, error) { return bc.statedb, nil } diff --git a/miner/ordering.go b/miner/ordering.go index 4c3055f0d317..8b4d05ef3ea7 100644 --- a/miner/ordering.go +++ b/miner/ordering.go @@ -80,22 +80,22 @@ func (s *txByPriceAndTime) Pop() interface{} { return x } -// transactionsByPriceAndNonce represents a set of transactions that can return +// TransactionsByPriceAndNonce represents a set of transactions that can return // transactions in a profit-maximizing sorted order, while supporting removing // entire batches of transactions for non-executable accounts. -type transactionsByPriceAndNonce struct { +type TransactionsByPriceAndNonce struct { txs map[common.Address][]*txpool.LazyTransaction // Per account nonce-sorted list of transactions heads txByPriceAndTime // Next transaction for each unique account (price heap) signer types.Signer // Signer for the set of transactions baseFee *big.Int // Current base fee } -// newTransactionsByPriceAndNonce creates a transaction set that can retrieve +// NewTransactionsByPriceAndNonce creates a transaction set that can retrieve // price sorted transactions in a nonce-honouring way. // // Note, the input map is reowned so the caller should not interact any more with // if after providing it to the constructor. -func newTransactionsByPriceAndNonce(signer types.Signer, txs map[common.Address][]*txpool.LazyTransaction, baseFee *big.Int) *transactionsByPriceAndNonce { +func NewTransactionsByPriceAndNonce(signer types.Signer, txs map[common.Address][]*txpool.LazyTransaction, baseFee *big.Int) *TransactionsByPriceAndNonce { // Initialize a price and received time based heap with the head transactions heads := make(txByPriceAndTime, 0, len(txs)) for from, accTxs := range txs { @@ -110,7 +110,7 @@ func newTransactionsByPriceAndNonce(signer types.Signer, txs map[common.Address] heap.Init(&heads) // Assemble and return the transaction set - return &transactionsByPriceAndNonce{ + return &TransactionsByPriceAndNonce{ txs: txs, heads: heads, signer: signer, @@ -119,7 +119,7 @@ func newTransactionsByPriceAndNonce(signer types.Signer, txs map[common.Address] } // Peek returns the next transaction by price. -func (t *transactionsByPriceAndNonce) Peek() *txpool.LazyTransaction { +func (t *TransactionsByPriceAndNonce) Peek() *txpool.LazyTransaction { if len(t.heads) == 0 { return nil } @@ -127,7 +127,7 @@ func (t *transactionsByPriceAndNonce) Peek() *txpool.LazyTransaction { } // Shift replaces the current best head with the next one from the same account. -func (t *transactionsByPriceAndNonce) Shift() { +func (t *TransactionsByPriceAndNonce) Shift() { acc := t.heads[0].from if txs, ok := t.txs[acc]; ok && len(txs) > 0 { if wrapped, err := newTxWithMinerFee(txs[0], acc, t.baseFee); err == nil { @@ -142,6 +142,6 @@ func (t *transactionsByPriceAndNonce) Shift() { // Pop removes the best transaction, *not* replacing it with the next one from // the same account. This should be used when a transaction cannot be executed // and hence all subsequent ones should be discarded from the same account. -func (t *transactionsByPriceAndNonce) Pop() { +func (t *TransactionsByPriceAndNonce) Pop() { heap.Pop(&t.heads) } diff --git a/miner/ordering_test.go b/miner/ordering_test.go index e5868d7a067e..7bb712be0d7e 100644 --- a/miner/ordering_test.go +++ b/miner/ordering_test.go @@ -101,7 +101,7 @@ func testTransactionPriceNonceSort(t *testing.T, baseFee *big.Int) { expectedCount += count } // Sort the transactions and cross check the nonce ordering - txset := newTransactionsByPriceAndNonce(signer, groups, baseFee) + txset := NewTransactionsByPriceAndNonce(signer, groups, baseFee) txs := types.Transactions{} for tx := txset.Peek(); tx != nil; tx = txset.Peek() { @@ -167,7 +167,7 @@ func TestTransactionTimeSort(t *testing.T) { }) } // Sort the transactions and cross check the nonce ordering - txset := newTransactionsByPriceAndNonce(signer, groups, nil) + txset := NewTransactionsByPriceAndNonce(signer, groups, nil) txs := types.Transactions{} for tx := txset.Peek(); tx != nil; tx = txset.Peek() { diff --git a/miner/payload_building.go b/miner/payload_building.go index 69ffab75b5d1..384db74bac3d 100644 --- a/miner/payload_building.go +++ b/miner/payload_building.go @@ -226,6 +226,7 @@ func (w *worker) buildPayload(args *BuildPayloadArgs) (*Payload, error) { case <-timer.C: start := time.Now() r := w.getSealingBlock(fullParams) + if r.err == nil { payload.update(r, time.Since(start)) } diff --git a/miner/worker.go b/miner/worker.go index 2ed91cc18781..f456ce651a07 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -83,7 +83,7 @@ var ( // information of the sealing block generation. type environment struct { signer types.Signer - state *state.StateDB // apply state changes here + state state.StateDBI // apply state changes here tcount int // tx count in cycle gasPool *core.GasPool // available gas used to pack transactions coinbase common.Address @@ -131,7 +131,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 } @@ -176,7 +176,7 @@ type worker struct { chainConfig *params.ChainConfig engine consensus.Engine eth Backend - chain *core.BlockChain + chain BlockChain // Feeds pendingLogsFeed event.Feed @@ -212,7 +212,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 atomic.Bool // The indicator whether the consensus engine is running or not. @@ -246,7 +246,7 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus chainConfig: chainConfig, engine: engine, eth: eth, - chain: eth.BlockChain(), + chain: eth.MinerChain(), mux: mux, isLocalBlock: isLocalBlock, coinbase: config.Etherbase, @@ -266,7 +266,7 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus // Subscribe for transaction insertion events (whether from network or resurrects) worker.txsSub = eth.TxPool().SubscribeTransactions(worker.txsCh, true) // Subscribe events for blockchain - worker.chainHeadSub = eth.BlockChain().SubscribeChainHeadEvent(worker.chainHeadCh) + worker.chainHeadSub = eth.MinerChain().SubscribeChainHeadEvent(worker.chainHeadCh) // Sanitize recommit interval if the user-specified one is too short. recommit := worker.config.Recommit @@ -337,7 +337,7 @@ func (w *worker) setRecommitInterval(interval time.Duration) { // pending returns the pending state and corresponding block. The returned // values can be nil in case the pending block is not initialized. -func (w *worker) pending() (*types.Block, *state.StateDB) { +func (w *worker) pending() (*types.Block, state.StateDBI) { w.snapshotMu.RLock() defer w.snapshotMu.RUnlock() if w.snapshotState == nil { @@ -422,7 +422,7 @@ func (w *worker) newWorkLoop(recommit time.Duration) { <-timer.C // discard the initial tick // commit aborts in-flight transaction execution with given signal and resubmits a new one. - commit := func(s int32) { + _ = func(s int32) { if interrupt != nil { interrupt.Store(s) } @@ -451,12 +451,12 @@ func (w *worker) newWorkLoop(recommit time.Duration) { case <-w.startCh: clearPending(w.chain.CurrentBlock().Number.Uint64()) timestamp = time.Now().Unix() - commit(commitInterruptNewHead) + // commit(commitInterruptNewHead) case head := <-w.chainHeadCh: clearPending(head.Block.NumberU64()) timestamp = time.Now().Unix() - commit(commitInterruptNewHead) + // commit(commitInterruptNewHead) case <-timer.C: // If sealing is running resubmit a new work cycle periodically to pull in @@ -467,7 +467,7 @@ func (w *worker) newWorkLoop(recommit time.Duration) { timer.Reset(recommit) continue } - commit(commitInterruptResubmit) + // commit(commitInterruptResubmit) } case interval := <-w.resubmitIntervalCh: @@ -527,49 +527,49 @@ func (w *worker) mainLoop() { case req := <-w.getWorkCh: req.result <- w.generateWork(req.params) - case ev := <-w.txsCh: + case _ = <-w.txsCh: // Apply transactions to the pending state if we're not sealing // // Note all transactions received may not be continuous with transactions // already included in the current sealing block. These transactions will // be automatically eliminated. - if !w.isRunning() && w.current != nil { - // If block is already full, abort - if gp := w.current.gasPool; gp != nil && gp.Gas() < params.TxGas { - continue - } - txs := make(map[common.Address][]*txpool.LazyTransaction, len(ev.Txs)) - for _, tx := range ev.Txs { - acc, _ := types.Sender(w.current.signer, tx) - txs[acc] = append(txs[acc], &txpool.LazyTransaction{ - Pool: w.eth.TxPool(), // We don't know where this came from, yolo resolve from everywhere - Hash: tx.Hash(), - Tx: nil, // Do *not* set this! We need to resolve it later to pull blobs in - Time: tx.Time(), - GasFeeCap: tx.GasFeeCap(), - GasTipCap: tx.GasTipCap(), - Gas: tx.Gas(), - BlobGas: tx.BlobGas(), - }) - } - txset := newTransactionsByPriceAndNonce(w.current.signer, txs, w.current.header.BaseFee) - tcount := w.current.tcount - w.commitTransactions(w.current, txset, nil) - - // Only update the snapshot if any new transactions were added - // to the pending block - if tcount != w.current.tcount { - w.updateSnapshot(w.current) - } - } else { - // Special case, if the consensus engine is 0 period clique(dev mode), - // submit sealing work here since all empty submission will be rejected - // by clique. Of course the advance sealing(empty submission) is disabled. - if w.chainConfig.Clique != nil && w.chainConfig.Clique.Period == 0 { - w.commitWork(nil, time.Now().Unix()) - } - } - w.newTxs.Add(int32(len(ev.Txs))) + // if !w.isRunning() && w.current != nil { + // // If block is already full, abort + // if gp := w.current.gasPool; gp != nil && gp.Gas() < params.TxGas { + // continue + // } + // txs := make(map[common.Address][]*txpool.LazyTransaction, len(ev.Txs)) + // for _, tx := range ev.Txs { + // acc, _ := types.Sender(w.current.signer, tx) + // txs[acc] = append(txs[acc], &txpool.LazyTransaction{ + // Pool: w.eth.TxPool(), // We don't know where this came from, yolo resolve from everywhere + // Hash: tx.Hash(), + // Tx: nil, // Do *not* set this! We need to resolve it later to pull blobs in + // Time: tx.Time(), + // GasFeeCap: tx.GasFeeCap(), + // GasTipCap: tx.GasTipCap(), + // Gas: tx.Gas(), + // BlobGas: tx.BlobGas(), + // }) + // } + // txset := newTransactionsByPriceAndNonce(w.current.signer, txs, w.current.header.BaseFee) + // tcount := w.current.tcount + // w.commitTransactions(w.current, txset, nil) + + // // Only update the snapshot if any new transactions were added + // // to the pending block + // if tcount != w.current.tcount { + // w.updateSnapshot(w.current) + // } + // } else { + // // Special case, if the consensus engine is 0 period clique(dev mode), + // // submit sealing work here since all empty submission will be rejected + // // by clique. Of course the advance sealing(empty submission) is disabled. + // if w.chainConfig.Clique != nil && w.chainConfig.Clique.Period == 0 { + // w.commitWork(nil, time.Now().Unix()) + // } + // } + // w.newTxs.Add(int32(len(ev.Txs))) // System stopped case <-w.exitCh: @@ -709,7 +709,11 @@ func (w *worker) makeEnv(parent *types.Header, header *types.Header, coinbase co // the miner to speed block sealing up a bit. state, err := w.chain.StateAt(parent.Root) if err != nil { - return nil, err + // Beginning of Block Number X == the same as State Root of Block Number X-1 + state, err = w.chain.GetOverridenState() + if err != nil { + return nil, err + } } state.StartPrefetcher("miner") @@ -792,7 +796,7 @@ func (w *worker) applyTransaction(env *environment, tx *types.Transaction) (*typ return receipt, err } -func (w *worker) commitTransactions(env *environment, txs *transactionsByPriceAndNonce, interrupt *atomic.Int32) error { +func (w *worker) commitTransactions(env *environment, txs *TransactionsByPriceAndNonce, interrupt *atomic.Int32) error { gasLimit := env.header.GasLimit if env.gasPool == nil { env.gasPool = new(core.GasPool).AddGas(gasLimit) @@ -998,13 +1002,13 @@ func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment) err // Fill the block with all available pending transactions. if len(localTxs) > 0 { - txs := newTransactionsByPriceAndNonce(env.signer, localTxs, env.header.BaseFee) + txs := NewTransactionsByPriceAndNonce(env.signer, localTxs, env.header.BaseFee) if err := w.commitTransactions(env, txs, interrupt); err != nil { return err } } if len(remoteTxs) > 0 { - txs := newTransactionsByPriceAndNonce(env.signer, remoteTxs, env.header.BaseFee) + txs := NewTransactionsByPriceAndNonce(env.signer, remoteTxs, env.header.BaseFee) if err := w.commitTransactions(env, txs, interrupt); err != nil { return err } @@ -1036,6 +1040,10 @@ func (w *worker) generateWork(params *generateParams) *newPayloadResult { if err != nil { return &newPayloadResult{err: err} } + + // TODO: figure out if this is kosher (probably okay for our use case). + w.updateSnapshot(work) + return &newPayloadResult{ block: block, fees: totalFees(block, work.receipts), diff --git a/miner/worker_test.go b/miner/worker_test.go index 59fbbbcdca9a..f61b5f8e751b 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -144,8 +144,9 @@ 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) BlockChain() BlockChain { return b.chain } +func (b *testWorkerBackend) MinerChain() BlockChain { return b.chain } +func (b *testWorkerBackend) TxPool() *txpool.TxPool { return b.txPool } func (b *testWorkerBackend) newRandomTx(creation bool) *types.Transaction { var tx *types.Transaction diff --git a/node/node.go b/node/node.go index 41c9971fe8e6..1c1b04827c81 100644 --- a/node/node.go +++ b/node/node.go @@ -65,6 +65,9 @@ type Node struct { inprocHandler *rpc.Server // In-process RPC request handler to process the API requests databases map[*closeTrackingDB]struct{} // All open databases + + // for Polaris + disableP2P bool } const ( @@ -200,6 +203,11 @@ func (n *Node) Start() error { return err } +// SetP2PDisabled sets the P2P disabled flag. +func (n *Node) SetP2PDisabled(disableP2P bool) { + n.disableP2P = disableP2P +} + // Close stops the Node and releases resources acquired in // Node constructor New. func (n *Node) Close() error { @@ -265,9 +273,11 @@ func (n *Node) doClose(errs []error) error { // openEndpoints starts all network and RPC endpoints. func (n *Node) openEndpoints() error { // start networking endpoints - n.log.Info("Starting peer-to-peer node", "instance", n.server.Name) - if err := n.server.Start(); err != nil { - return convertFileLockError(err) + if !n.disableP2P { + n.log.Info("Starting peer-to-peer node", "instance", n.server.Name) + if err := n.server.Start(); err != nil { + return convertFileLockError(err) + } } // start RPC endpoints err := n.startRPC() diff --git a/params/protocol_params.go b/params/protocol_params.go index 8a5c01184941..882960c5b598 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -128,7 +128,7 @@ const ( DefaultElasticityMultiplier = 2 // Bounds the maximum gas limit an EIP-1559 block may have. InitialBaseFee = 1000000000 // Initial base fee for EIP-1559 blocks. - MaxCodeSize = 24576 // Maximum bytecode to permit for a contract + MaxCodeSize = 40000 // Maximum bytecode to permit for a contract MaxInitCodeSize = 2 * MaxCodeSize // Maximum initcode to permit in a creation transaction and create instructions // Precompiled contract gas prices diff --git a/signer/core/api.go b/signer/core/api.go index 43eb89ee0077..51c287fb95f1 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 69229dadaf26..39f7f019f484 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 d2207c9eb8d5..f23407d5b5cc 100644 --- a/signer/core/auditlog.go +++ b/signer/core/auditlog.go @@ -23,7 +23,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" "golang.org/x/exp/slog" 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 a0ce6844171f..83ea9d26937e 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 c9921e57a958..398da4643f9e 100644 --- a/signer/rules/rules.go +++ b/signer/rules/rules.go @@ -24,7 +24,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 d27de22b29a9..5596fbada247 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 e0130be48a0b..830b730352a0 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -321,7 +321,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 763ed56e9f7a..6f7db94fd96a 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" @@ -82,7 +83,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) 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 ae78a53a7eb8..687244bfae48 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -89,7 +89,7 @@ func TestState(t *testing.T) { t.Run(key+"/hash/trie", func(t *testing.T) { withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error { var result error - test.Run(subtest, vmconfig, false, rawdb.HashScheme, func(err error, snaps *snapshot.Tree, state *state.StateDB) { + test.Run(subtest, vmconfig, false, rawdb.HashScheme, func(err error, snaps *snapshot.Tree, state state.StateDBI) { result = st.checkFailure(t, err) }) return result @@ -98,7 +98,7 @@ func TestState(t *testing.T) { t.Run(key+"/hash/snap", func(t *testing.T) { withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error { var result error - test.Run(subtest, vmconfig, true, rawdb.HashScheme, func(err error, snaps *snapshot.Tree, state *state.StateDB) { + test.Run(subtest, vmconfig, true, rawdb.HashScheme, func(err error, snaps *snapshot.Tree, state state.StateDBI) { if snaps != nil && state != nil { if _, err := snaps.Journal(state.IntermediateRoot(false)); err != nil { result = err @@ -113,7 +113,7 @@ func TestState(t *testing.T) { t.Run(key+"/path/trie", func(t *testing.T) { withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error { var result error - test.Run(subtest, vmconfig, false, rawdb.PathScheme, func(err error, snaps *snapshot.Tree, state *state.StateDB) { + test.Run(subtest, vmconfig, false, rawdb.PathScheme, func(err error, snaps *snapshot.Tree, state state.StateDBI) { result = st.checkFailure(t, err) }) return result @@ -122,7 +122,7 @@ func TestState(t *testing.T) { t.Run(key+"/path/snap", func(t *testing.T) { withTrace(t, test.gasLimit(subtest), func(vmconfig vm.Config) error { var result error - test.Run(subtest, vmconfig, true, rawdb.PathScheme, func(err error, snaps *snapshot.Tree, state *state.StateDB) { + test.Run(subtest, vmconfig, true, rawdb.PathScheme, func(err error, snaps *snapshot.Tree, state state.StateDBI) { if snaps != nil && state != nil { if _, err := snaps.Journal(state.IntermediateRoot(false)); err != nil { result = err @@ -282,7 +282,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 745a3c6b287a..68671c2fa900 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -190,7 +190,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, scheme string, postCheck func(err error, snaps *snapshot.Tree, state *state.StateDB)) (result error) { +func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config, snapshotter bool, scheme string, postCheck func(err error, snaps *snapshot.Tree, state state.StateDBI)) (result error) { triedb, snaps, statedb, root, err := t.RunNoVerify(subtest, vmconfig, snapshotter, scheme) // Invoke the callback at the end of function for further analysis. @@ -228,7 +228,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, scheme string) (*trie.Database, *snapshot.Tree, *state.StateDB, common.Hash, error) { +func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapshotter bool, scheme string) (*trie.Database, *snapshot.Tree, state.StateDBI, common.Hash, error) { config, eips, err := GetChainConfig(subtest.Fork) if err != nil { return nil, nil, nil, common.Hash{}, UnsupportedForkError{subtest.Fork} @@ -309,7 +309,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, scheme string) (*trie.Database, *snapshot.Tree, *state.StateDB) { +func MakePreState(db ethdb.Database, accounts core.GenesisAlloc, snapshotter bool, scheme string) (*trie.Database, *snapshot.Tree, state.StateDBI) { tconf := &trie.Config{Preimages: true} if scheme == rawdb.HashScheme { tconf.HashDB = hashdb.Defaults