diff --git a/accounts/abi/bind/bind_extra_test.go b/accounts/abi/bind/bind_extra_test.go index aa78b672ae..25c5a68e62 100644 --- a/accounts/abi/bind/bind_extra_test.go +++ b/accounts/abi/bind/bind_extra_test.go @@ -18,11 +18,12 @@ import ( "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/types" "github.com/ava-labs/libevm/crypto" + "github.com/stretchr/testify/require" ) // TestGetSenderNativeAssetCall checks that the NativeAssetCall proxies the // caller address This behavior is disabled on the network and is only to test -// previous behavior. Note the test uses ApricotPhase2Config. +// previous behavior. Note the test uses [params.TestApricotPhase2Config]. func TestGetSenderNativeAssetCall(t *testing.T) { // pragma solidity >=0.8.0 <0.9.0; // contract GetSenderNativeAssetCall { @@ -34,7 +35,7 @@ func TestGetSenderNativeAssetCall(t *testing.T) { // _sender = msg.sender; // } // } - rawABI := `[ + const rawABI = `[ { "inputs": [], "name": "getSender", @@ -51,17 +52,17 @@ func TestGetSenderNativeAssetCall(t *testing.T) { } ]` bytecode := common.FromHex(`6080604052348015600f57600080fd5b506101608061001f6000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806350c36a521461003b5780635e01eb5a14610045575b600080fd5b610043610063565b005b61004d6100a5565b60405161005a919061010f565b60405180910390f35b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006100f9826100ce565b9050919050565b610109816100ee565b82525050565b60006020820190506101246000830184610100565b9291505056fea26469706673582212209023ce54f38e749b58f44e8da750354578080ce16df95037b7305ed7e480c36d64736f6c634300081b0033`) - setSenderMethodName := "setSender" - getSenderMethodName := "getSender" + const setSenderMethodName = "setSender" + const getSenderMethodName = "getSender" parsedABI, err := abi.JSON(bytes.NewReader([]byte(rawABI))) - if err != nil { - t.Fatalf("Failed to parse ABI: %v", err) - } + require.NoError(t, err, "Failed to parse ABI") // Generate a new random account and a funded simulator - key, _ := crypto.GenerateKey() - auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) + key, err := crypto.GenerateKey() + require.NoError(t, err, "Failed to generate key") + auth, err := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) + require.NoError(t, err, "Failed to create transactor") alloc := types.GenesisAlloc{auth.From: {Balance: big.NewInt(1000000000000000000)}} atApricotPhase2 := func(nodeConf *node.Config, ethConf *ethconfig.Config) { chainConfig := *params.TestApricotPhase2Config @@ -73,13 +74,14 @@ func TestGetSenderNativeAssetCall(t *testing.T) { Backend: b, Client: b.Client(), } - defer sim.Close() + t.Cleanup(func() { + err = sim.Close() + require.NoError(t, err, "Failed to close simulator") + }) // Deploy the get/setSender contract _, _, interactor, err := bind.DeployContract(auth, parsedABI, bytecode, sim) - if err != nil { - t.Fatalf("Failed to deploy interactor contract: %v", err) - } + require.NoError(t, err, "Failed to deploy interactor contract") sim.Commit(false) // Setting NativeAssetCall in the transact opts will proxy the call through @@ -91,21 +93,15 @@ func TestGetSenderNativeAssetCall(t *testing.T) { AssetAmount: big.NewInt(0), }, } - if _, err := interactor.Transact(opts, setSenderMethodName); err != nil { - t.Fatalf("Failed to set sender: %v", err) - } + _, err = interactor.Transact(opts, setSenderMethodName) + require.NoError(t, err, "Failed to set sender") sim.Commit(true) - var results []interface{} - if err := interactor.Call(nil, &results, getSenderMethodName); err != nil { - t.Fatalf("Failed to get sender: %v", err) - } - if len(results) != 1 { - t.Fatalf("Expected one result, got %d", len(results)) - } - if addr, ok := results[0].(common.Address); !ok { - t.Fatalf("Expected address, got %T", results[0]) - } else if addr != auth.From { - t.Fatalf("Address mismatch: have '%v'", addr) - } + var results []any + err = interactor.Call(nil, &results, getSenderMethodName) + require.NoError(t, err, "Failed to get sender") + require.Len(t, results, 1) + addr, ok := results[0].(common.Address) + require.Truef(t, ok, "Expected %T, got %T", common.Address{}, results[0]) + require.Equal(t, addr, auth.From, "Address mismatch") } diff --git a/consensus/dummy/consensus.go b/consensus/dummy/consensus.go index 2d1cb2783f..f9177abdb0 100644 --- a/consensus/dummy/consensus.go +++ b/consensus/dummy/consensus.go @@ -148,19 +148,19 @@ func NewFullFaker() *DummyEngine { } } -func verifyHeaderGasFields(configExtra *extras.ChainConfig, header *types.Header, parent *types.Header) error { - if err := customheader.VerifyGasUsed(configExtra, parent, header); err != nil { +func verifyHeaderGasFields(config *extras.ChainConfig, header *types.Header, parent *types.Header) error { + if err := customheader.VerifyGasUsed(config, parent, header); err != nil { return err } - if err := customheader.VerifyGasLimit(configExtra, parent, header); err != nil { + if err := customheader.VerifyGasLimit(config, parent, header); err != nil { return err } - if err := customheader.VerifyExtraPrefix(configExtra, parent, header); err != nil { + if err := customheader.VerifyExtraPrefix(config, parent, header); err != nil { return err } // Verify header.BaseFee matches the expected value. - expectedBaseFee, err := customheader.BaseFee(configExtra, parent, header.Time) + expectedBaseFee, err := customheader.BaseFee(config, parent, header.Time) if err != nil { return fmt.Errorf("failed to calculate base fee: %w", err) } @@ -172,7 +172,7 @@ func verifyHeaderGasFields(configExtra *extras.ChainConfig, header *types.Header // Enforce BlockGasCost constraints expectedBlockGasCost := customheader.BlockGasCost( - configExtra, + config, parent, header.Time, ) @@ -181,7 +181,7 @@ func verifyHeaderGasFields(configExtra *extras.ChainConfig, header *types.Header } // Verify ExtDataGasUsed not present before AP4 - if !configExtra.IsApricotPhase4(header.Time) { + if !config.IsApricotPhase4(header.Time) { if headerExtra.ExtDataGasUsed != nil { return fmt.Errorf("invalid extDataGasUsed before fork: have %d, want ", headerExtra.ExtDataGasUsed) } @@ -377,19 +377,19 @@ func (eng *DummyEngine) Finalize(chain consensus.ChainHeaderReader, block *types } } - configExtra := params.GetExtra(chain.Config()) + config := params.GetExtra(chain.Config()) timestamp := block.Time() // Verify the BlockGasCost set in the header matches the expected value. blockGasCost := customtypes.BlockGasCost(block) expectedBlockGasCost := customheader.BlockGasCost( - configExtra, + config, parent, timestamp, ) if !utils.BigEqual(blockGasCost, expectedBlockGasCost) { return fmt.Errorf("invalid blockGasCost: have %d, want %d", blockGasCost, expectedBlockGasCost) } - if configExtra.IsApricotPhase4(timestamp) { + if config.IsApricotPhase4(timestamp) { // Validate extDataGasUsed and BlockGasCost match expectations // // NOTE: This is a duplicate check of what is already performed in @@ -440,10 +440,9 @@ func (eng *DummyEngine) FinalizeAndAssemble(chain consensus.ChainHeaderReader, h header.Time, ) if configExtra.IsApricotPhase4(header.Time) { - ext := customtypes.GetHeaderExtra(header) - ext.ExtDataGasUsed = extDataGasUsed - if ext.ExtDataGasUsed == nil { - ext.ExtDataGasUsed = new(big.Int).Set(common.Big0) + headerExtra.ExtDataGasUsed = extDataGasUsed + if headerExtra.ExtDataGasUsed == nil { + headerExtra.ExtDataGasUsed = new(big.Int) } // Verify that this block covers the block fee. diff --git a/core/blockchain.go b/core/blockchain.go index db672a32ac..ab42f107cf 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -67,13 +67,15 @@ import ( // ====== If resolving merge conflicts ====== // -// All calls to metrics.NewRegistered*() have been replaced with -// metrics.GetOrRegister*() and this package's corresponding libevm package -// imported above. Together these ensure that the metric here is the same as the -// one with the same name in libevm. +// All calls to metrics.NewRegistered*() for metrics also defined in libevm/core have been +// replaced either with: +// - metrics.GetOrRegister*() to get a metric already registered in libevm/core, or register it +// here otherwise +// - [getOrOverrideAsRegisteredCounter] to get a metric already registered in libevm/core +// only if it is a [metrics.Counter]. If it is not, the metric is unregistered and registered +// as a [metrics.Counter] here. // -// Note, however, those that have had their types overridden as -// [metrics.Counter]. +// These replacements ensure the same metrics are shared between the two packages. var ( accountReadTimer = getOrOverrideAsRegisteredCounter("chain/account/reads", nil) accountHashTimer = getOrOverrideAsRegisteredCounter("chain/account/hashes", nil) @@ -195,7 +197,7 @@ func (c *CacheConfig) triedbConfig() *triedb.Config { config.DBOverride = hashdb.Config{ CleanCacheSize: c.TrieCleanLimit * 1024 * 1024, StatsPrefix: trieCleanCacheStatsNamespace, - ReferenceRootAtomicallyOnUpdate: true, // Automatically reference root nodes when an update is made + ReferenceRootAtomicallyOnUpdate: true, }.BackendConstructor } if c.StateScheme == rawdb.PathScheme { @@ -1172,8 +1174,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, parentRoot common. } // Commit all cached state changes into underlying memory database. - var err error - _, err = bc.commitWithSnap(block, parentRoot, state) + _, err := bc.commitWithSnap(block, parentRoot, state) if err != nil { return err } @@ -1695,8 +1696,8 @@ func (bc *BlockChain) reprocessBlock(parent *types.Block, current *types.Block) func (bc *BlockChain) commitWithSnap( current *types.Block, parentRoot common.Hash, statedb *state.StateDB, ) (common.Hash, error) { - // blockHashes must be passed through Commit since snapshots are based on the - // block hash. + // blockHashes must be passed through [state.StateDB]'s Commit since snapshots + // are based on the block hash. blockHashes := snapshot.WithBlockHashes(current.Hash(), current.ParentHash()) root, err := statedb.Commit(current.NumberU64(), bc.chainConfig.IsEIP158(current.Number()), blockHashes) if err != nil { @@ -1851,7 +1852,7 @@ func (bc *BlockChain) reprocessState(current *types.Block, reexec uint64) error // Flatten snapshot if initialized, holding a reference to the state root until the next block // is processed. if err := bc.flattenSnapshot(func() error { - if previousRoot != (common.Hash{}) { + if previousRoot != (common.Hash{}) && previousRoot != root { triedb.Dereference(previousRoot) } previousRoot = root diff --git a/core/blockchain_ext.go b/core/blockchain_ext.go index db3d0dae00..875f9b8296 100644 --- a/core/blockchain_ext.go +++ b/core/blockchain_ext.go @@ -5,9 +5,9 @@ package core import "github.com/ava-labs/libevm/metrics" // getOrOverrideAsRegisteredCounter searches for a metric already registered -// with`name`. If a metric is found and it is a Counter, it is returned. If a -// metric is found and it is not a Counter, it is unregistered and replaced with -// a new registered Counter. If no metric is found, a new Counter is constructed +// with `name`. If a metric is found and it is a [metrics.Counter], it is returned. If a +// metric is found and it is not a [metrics.Counter], it is unregistered and replaced with +// a new registered [metrics.Counter]. If no metric is found, a new [metrics.Counter] is constructed // and registered. // // This is necessary for a metric defined in libevm with the same name but a @@ -17,11 +17,10 @@ func getOrOverrideAsRegisteredCounter(name string, r metrics.Registry) metrics.C r = metrics.DefaultRegistry } - switch c := r.GetOrRegister(name, metrics.NewCounter).(type) { - case metrics.Counter: + if c, ok := r.GetOrRegister(name, metrics.NewCounter).(metrics.Counter); ok { return c - default: // `name` must have already been registered to be any other type - r.Unregister(name) - return metrics.NewRegisteredCounter(name, r) } + // `name` must have already been registered to be any other type + r.Unregister(name) + return metrics.NewRegisteredCounter(name, r) } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index ed55f35c38..6565da75e1 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -14,7 +14,6 @@ import ( "github.com/ava-labs/coreth/core/state" "github.com/ava-labs/coreth/core/state/pruner" "github.com/ava-labs/coreth/params" - "github.com/ava-labs/coreth/params/extras" "github.com/ava-labs/coreth/plugin/evm/customrawdb" "github.com/ava-labs/coreth/plugin/evm/upgrade/ap3" "github.com/ava-labs/libevm/common" @@ -425,11 +424,8 @@ func TestUngracefulAsyncShutdown(t *testing.T) { // Ensure that key1 has some funds in the genesis block. genesisBalance := big.NewInt(1000000) gspec := &Genesis{ - Config: params.WithExtra( - ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}, - &extras.ChainConfig{}, - ), - Alloc: types.GenesisAlloc{addr1: {Balance: genesisBalance}}, + Config: ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}, + Alloc: types.GenesisAlloc{addr1: {Balance: genesisBalance}}, } blockchain, err := create(chainDB, gspec, common.Hash{}) diff --git a/core/chain_makers.go b/core/chain_makers.go index 8dcc3c69dc..f2fa1e9ee7 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -373,12 +373,12 @@ func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, func (cm *chainMaker) makeHeader(parent *types.Block, gap uint64, state *state.StateDB, engine consensus.Engine) *types.Header { time := parent.Time() + gap // block time is fixed at [gap] seconds - configExtra := params.GetExtra(cm.config) - gasLimit, err := header.GasLimit(configExtra, parent.Header(), time) + config := params.GetExtra(cm.config) + gasLimit, err := header.GasLimit(config, parent.Header(), time) if err != nil { panic(err) } - baseFee, err := header.BaseFee(configExtra, parent.Header(), time) + baseFee, err := header.BaseFee(config, parent.Header(), time) if err != nil { panic(err) } diff --git a/core/evm.go b/core/evm.go index 079b39f495..d42e47422f 100644 --- a/core/evm.go +++ b/core/evm.go @@ -49,14 +49,14 @@ func init() { type hooks struct{} -// OverrideNewEVMArgs is a hook that is called back when a new EVM is created. +// OverrideNewEVMArgs is a hook that is called in [vm.NewEVM]. // It allows for the modification of the EVM arguments before the EVM is created. // Specifically, we set Random to be the same as Difficulty since Shanghai. // This allows using the same jump table as upstream. // Then we set Difficulty to 0 as it is post Merge in upstream. // Additionally we wrap the StateDB with the appropriate StateDB wrapper, // which is used in coreth to process historical pre-AP1 blocks with the -// GetCommittedState method as it was historically. +// [StateDbAP1.GetCommittedState] method as it was historically. func (hooks) OverrideNewEVMArgs(args *vm.NewEVMArgs) *vm.NewEVMArgs { rules := args.ChainConfig.Rules(args.BlockContext.BlockNumber, params.IsMergeTODO, args.BlockContext.Time) args.StateDB = wrapStateDB(rules, args.StateDB) @@ -79,7 +79,7 @@ func wrapStateDB(rules params.Rules, db vm.StateDB) vm.StateDB { if params.GetRulesExtra(rules).IsApricotPhase1 { db = &StateDbAP1{db.(extstate.VmStateDB)} } - return &extstate.StateDB{VmStateDB: db.(extstate.VmStateDB)} + return extstate.New(db.(extstate.VmStateDB)) } type StateDbAP1 struct { @@ -121,7 +121,6 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common if header.ExcessBlobGas != nil { blobBaseFee = eip4844.CalcBlobFee(*header.ExcessBlobGas) } - return vm.BlockContext{ CanTransfer: CanTransfer, Transfer: Transfer, @@ -144,14 +143,14 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common // NewEVMBlockContextWithPredicateResults creates a new context for use in the // EVM with an override for the predicate results. The miner uses this to pass // predicate results to the EVM when header.Extra is not fully formed yet. -func NewEVMBlockContextWithPredicateResults(rules extras.AvalancheRules, header *types.Header, chain ChainContext, author *common.Address, predicateResults []byte) vm.BlockContext { +func NewEVMBlockContextWithPredicateResults(rules extras.AvalancheRules, header *types.Header, chain ChainContext, author *common.Address, predicateBytes []byte) vm.BlockContext { blockCtx := NewEVMBlockContext(header, chain, author) // Note this only sets the block context, which is the hand-off point for // the EVM. The actual header is not modified. blockCtx.Header.Extra = customheader.SetPredicateBytesInExtra( rules, bytes.Clone(header.Extra), - predicateResults, + predicateBytes, ) return blockCtx } diff --git a/core/extstate/statedb.go b/core/extstate/statedb.go index 21b1586052..2ee0d6bbdc 100644 --- a/core/extstate/statedb.go +++ b/core/extstate/statedb.go @@ -16,28 +16,38 @@ import ( type VmStateDB interface { vm.StateDB Logs() []*types.Log - GetTxHash() common.Hash GetBalanceMultiCoin(common.Address, common.Hash) *big.Int AddBalanceMultiCoin(common.Address, common.Hash, *big.Int) SubBalanceMultiCoin(common.Address, common.Hash, *big.Int) } +type vmStateDB = VmStateDB + type StateDB struct { - VmStateDB + vmStateDB // Ordered storage slots to be used in predicate verification as set in the tx access list. - // Only set in PrepareAccessList, and un-modified through execution. + // Only set in [StateDB.Prepare], and un-modified through execution. predicateStorageSlots map[common.Address][][]byte } +// New creates a new [*StateDB] with the given [VmStateDB], effectively wrapping it +// with additional functionality. +func New(vm VmStateDB) *StateDB { + return &StateDB{ + vmStateDB: vm, + predicateStorageSlots: make(map[common.Address][][]byte), + } +} + func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) { rulesExtra := params.GetRulesExtra(rules) s.predicateStorageSlots = predicate.PreparePredicateStorageSlots(rulesExtra, list) - s.VmStateDB.Prepare(rules, sender, coinbase, dst, precompiles, list) + s.vmStateDB.Prepare(rules, sender, coinbase, dst, precompiles, list) } -// GetLogData returns the underlying topics and data from each log included in the StateDB +// GetLogData returns the underlying topics and data from each log included in the [StateDB]. // Test helper function. func (s *StateDB) GetLogData() (topics [][]common.Hash, data [][]byte) { for _, log := range s.Logs() { @@ -59,10 +69,7 @@ func (s *StateDB) GetLogData() (topics [][]common.Hash, data [][]byte) { // GetPredicateStorageSlots(AddrA, 1) -> Predicate3 func (s *StateDB) GetPredicateStorageSlots(address common.Address, index int) ([]byte, bool) { predicates, exists := s.predicateStorageSlots[address] - if !exists { - return nil, false - } - if index >= len(predicates) { + if !exists || index >= len(predicates) { return nil, false } return predicates[index], true @@ -70,8 +77,5 @@ func (s *StateDB) GetPredicateStorageSlots(address common.Address, index int) ([ // SetPredicateStorageSlots sets the predicate storage slots for the given address func (s *StateDB) SetPredicateStorageSlots(address common.Address, predicates [][]byte) { - if s.predicateStorageSlots == nil { - s.predicateStorageSlots = make(map[common.Address][][]byte) - } s.predicateStorageSlots[address] = predicates } diff --git a/core/extstate/test_statedb.go b/core/extstate/test_statedb.go index 3da7113b5a..903480dfe0 100644 --- a/core/extstate/test_statedb.go +++ b/core/extstate/test_statedb.go @@ -16,5 +16,5 @@ func NewTestStateDB(t testing.TB) contract.StateDB { db := rawdb.NewMemoryDatabase() statedb, err := state.New(common.Hash{}, state.NewDatabase(db), nil) require.NoError(t, err) - return &StateDB{VmStateDB: statedb} + return New(statedb) } diff --git a/core/genesis.go b/core/genesis.go index ee2059f2db..465d503ef6 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -53,7 +53,7 @@ import ( var errGenesisNoConfig = errors.New("genesis has no chain configuration") -// Deprecated: use types.GenesisAccount instead. +// Deprecated: use types.Account instead. type GenesisAccount = types.Account // Deprecated: use types.GenesisAlloc instead. diff --git a/core/genesis_test.go b/core/genesis_test.go index 857f6115c7..cbc2de60c2 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -45,6 +45,7 @@ import ( "github.com/ava-labs/libevm/core/types" "github.com/ava-labs/libevm/core/vm" "github.com/ava-labs/libevm/ethdb" + ethparams "github.com/ava-labs/libevm/params" "github.com/ava-labs/libevm/trie" "github.com/ava-labs/libevm/triedb" "github.com/davecgh/go-spew/spew" @@ -159,7 +160,7 @@ func testSetupGenesis(t *testing.T, scheme string) { }, wantHash: customghash, wantConfig: customg.Config, - wantErr: ¶ms.ConfigCompatError{ + wantErr: ðparams.ConfigCompatError{ What: "ApricotPhase1 fork block timestamp", StoredTime: u64(90), NewTime: u64(100), diff --git a/core/state/database.go b/core/state/database.go index f0fdec065d..fe1fb7a0b0 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -1,4 +1,4 @@ -// (c) 2019-2020, Ava Labs, Inc. +// (c) 2019-2025, Ava Labs, Inc. // // This file is a derived work, based on the go-ethereum library whose original // notices appear below. @@ -27,165 +27,24 @@ package state import ( - "errors" - "fmt" - - "github.com/ava-labs/libevm/common" - "github.com/ava-labs/libevm/common/lru" - "github.com/ava-labs/libevm/core/rawdb" ethstate "github.com/ava-labs/libevm/core/state" - "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/libevm/ethdb" - "github.com/ava-labs/libevm/trie" - "github.com/ava-labs/libevm/trie/utils" "github.com/ava-labs/libevm/triedb" - "github.com/crate-crypto/go-ipa/banderwagon" ) -const ( - // Number of codehash->size associations to keep. - codeSizeCacheSize = 100000 - - // Cache size granted for caching clean code. - codeCacheSize = 64 * 1024 * 1024 - - // commitmentSize is the size of commitment stored in cache. - commitmentSize = banderwagon.UncompressedSize - - // Cache item granted for caching commitment results. - commitmentCacheItems = 64 * 1024 * 1024 / (commitmentSize + common.AddressLength) +type ( + Database = ethstate.Database + Trie = ethstate.Trie ) -// Database wraps access to tries and contract code. -type Database interface { - // OpenTrie opens the main account trie. - OpenTrie(root common.Hash) (Trie, error) - - // OpenStorageTrie opens the storage trie of an account. - OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, trie Trie) (Trie, error) - - // CopyTrie returns an independent copy of the given trie. - CopyTrie(Trie) Trie - - // ContractCode retrieves a particular contract's code. - ContractCode(addr common.Address, codeHash common.Hash) ([]byte, error) - - // ContractCodeSize retrieves a particular contracts code's size. - ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) - - // DiskDB returns the underlying key-value disk database. - DiskDB() ethdb.KeyValueStore - - // TrieDB returns the underlying trie database for managing trie nodes. - TrieDB() *triedb.Database -} - -// Trie is a Ethereum Merkle Patricia trie. -type Trie = ethstate.Trie - -// NewDatabase creates a backing store for state. The returned database is safe for -// concurrent use, but does not retain any recent trie nodes in memory. To keep some -// historical state in memory, use the NewDatabaseWithConfig constructor. -func NewDatabase(db ethdb.Database) Database { - return NewDatabaseWithConfig(db, nil) -} - -// NewDatabaseWithConfig creates a backing store for state. The returned database -// is safe for concurrent use and retains a lot of collapsed RLP trie nodes in a -// large memory cache. -func NewDatabaseWithConfig(db ethdb.Database, config *triedb.Config) Database { - return &cachingDB{ - disk: db, - codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), - codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), - triedb: triedb.NewDatabase(db, config), - } -} - -// NewDatabaseWithNodeDB creates a state database with an already initialized node database. -func NewDatabaseWithNodeDB(db ethdb.Database, triedb *triedb.Database) Database { - return &cachingDB{ - disk: db, - codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), - codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), - triedb: triedb, - } -} - -type cachingDB struct { - disk ethdb.KeyValueStore - codeSizeCache *lru.Cache[common.Hash, int] - codeCache *lru.SizeConstrainedCache[common.Hash, []byte] - triedb *triedb.Database -} - -// OpenTrie opens the main account trie at a specific root hash. -func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { - if db.triedb.IsVerkle() { - return trie.NewVerkleTrie(root, db.triedb, utils.NewPointCache(commitmentCacheItems)) - } - tr, err := trie.NewStateTrie(trie.StateTrieID(root), db.triedb) - if err != nil { - return nil, err - } - return tr, nil -} - -// OpenStorageTrie opens the storage trie of an account. -func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, self Trie) (Trie, error) { - // In the verkle case, there is only one tree. But the two-tree structure - // is hardcoded in the codebase. So we need to return the same trie in this - // case. - if db.triedb.IsVerkle() { - return self, nil - } - tr, err := trie.NewStateTrie(trie.StorageTrieID(stateRoot, crypto.Keccak256Hash(address.Bytes()), root), db.triedb) - if err != nil { - return nil, err - } - return tr, nil -} - -// CopyTrie returns an independent copy of the given trie. -func (db *cachingDB) CopyTrie(t Trie) Trie { - switch t := t.(type) { - case *trie.StateTrie: - return t.Copy() - default: - panic(fmt.Errorf("unknown trie type %T", t)) - } -} - -// ContractCode retrieves a particular contract's code. -func (db *cachingDB) ContractCode(address common.Address, codeHash common.Hash) ([]byte, error) { - code, _ := db.codeCache.Get(codeHash) - if len(code) > 0 { - return code, nil - } - code = rawdb.ReadCode(db.disk, codeHash) - if len(code) > 0 { - db.codeCache.Add(codeHash, code) - db.codeSizeCache.Add(codeHash, len(code)) - return code, nil - } - return nil, errors.New("not found") -} - -// ContractCodeSize retrieves a particular contracts code's size. -func (db *cachingDB) ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) { - if cached, ok := db.codeSizeCache.Get(codeHash); ok { - return cached, nil - } - code, err := db.ContractCode(addr, codeHash) - return len(code), err +func NewDatabase(db ethdb.Database) ethstate.Database { + return ethstate.NewDatabase(db) } -// DiskDB returns the underlying key-value disk database. -func (db *cachingDB) DiskDB() ethdb.KeyValueStore { - return db.disk +func NewDatabaseWithConfig(db ethdb.Database, config *triedb.Config) ethstate.Database { + return ethstate.NewDatabaseWithConfig(db, config) } -// TrieDB retrieves any intermediate trie-node caching layer. -func (db *cachingDB) TrieDB() *triedb.Database { - return db.triedb +func NewDatabaseWithNodeDB(db ethdb.Database, triedb *triedb.Database) ethstate.Database { + return ethstate.NewDatabaseWithNodeDB(db, triedb) } diff --git a/core/state/snapshot/iterator.go b/core/state/snapshot/iterator.go index ae4d8d6718..46da2873f9 100644 --- a/core/state/snapshot/iterator.go +++ b/core/state/snapshot/iterator.go @@ -39,34 +39,11 @@ import ( // Iterator is an iterator to step over all the accounts or the specific // storage in a snapshot which may or may not be composed of multiple layers. -type Iterator interface { - // Next steps the iterator forward one element, returning false if exhausted, - // or an error if iteration failed for some reason (e.g. root being iterated - // becomes stale and garbage collected). - Next() bool - - // Error returns any failure that occurred during iteration, which might have - // caused a premature iteration exit (e.g. snapshot stack becoming stale). - Error() error - - // Hash returns the hash of the account or storage slot the iterator is - // currently at. - Hash() common.Hash - - // Release releases associated resources. Release should always succeed and - // can be called multiple times without causing error. - Release() -} +type Iterator = ethsnapshot.Iterator // AccountIterator is an iterator to step over all the accounts in a snapshot, // which may or may not be composed of multiple layers. -type AccountIterator interface { - Iterator - - // Account returns the RLP encoded slim account the iterator is currently at. - // An error will be returned if the iterator becomes invalid - Account() []byte -} +type AccountIterator = ethsnapshot.AccountIterator // StorageIterator is an iterator to step over the specific storage in a snapshot, // which may or may not be composed of multiple layers. diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 27cc625962..6c5ead709b 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -58,10 +58,10 @@ const ( // ====== If resolving merge conflicts ====== // -// All calls to metrics.NewRegistered*() have been replaced with -// metrics.GetOrRegister*() and this package's corresponding libevm package -// imported above. Together these ensure that the metric here is the same as the -// one with the same name in libevm. +// All calls to metrics.NewRegistered*() for metrics also defined in libevm/core/state/snapshot +// have been replaced with metrics.GetOrRegister*() to get metrics already registered in +// libevm/core/state/snapshot or register them here otherwise. These replacements ensure the +// same metrics are shared between the two packages. var ( snapshotCleanAccountHitMeter = metrics.GetOrRegisterMeter("state/snapshot/clean/account/hit", nil) snapshotCleanAccountMissMeter = metrics.GetOrRegisterMeter("state/snapshot/clean/account/miss", nil) diff --git a/core/state/statedb.go b/core/state/statedb.go index 82e01d3c1a..cfde4a80a5 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -162,7 +162,7 @@ func (s *StateDB) Copy() *StateDB { } // NormalizeCoinID ORs the 0th bit of the first byte in -// [coinID], which ensures this bit will be 1 and all other +// `coinID`, which ensures this bit will be 1 and all other // bits are left the same. // This partitions multicoin storage from normal state storage. func NormalizeCoinID(coinID *common.Hash) { @@ -170,7 +170,7 @@ func NormalizeCoinID(coinID *common.Hash) { } // NormalizeStateKey ANDs the 0th bit of the first byte in -// [key], which ensures this bit will be 0 and all other bits +// `key`, which ensures this bit will be 0 and all other bits // are left the same. // This partitions normal state storage from multicoin storage. func NormalizeStateKey(key *common.Hash) { diff --git a/core/state/statedb_multicoin_test.go b/core/state/statedb_multicoin_test.go index bfc1e6fce3..5cfd06540b 100644 --- a/core/state/statedb_multicoin_test.go +++ b/core/state/statedb_multicoin_test.go @@ -13,6 +13,7 @@ import ( "github.com/ava-labs/libevm/core/rawdb" "github.com/ava-labs/libevm/crypto" "github.com/holiman/uint256" + "github.com/stretchr/testify/require" ) func TestMultiCoinOperations(t *testing.T) { @@ -20,31 +21,29 @@ func TestMultiCoinOperations(t *testing.T) { addr := common.Address{1} assetID := common.Hash{2} - root, _ := s.state.Commit(0, false) - s.state, _ = New(root, s.state.db, s.state.snaps) + root, err := s.state.Commit(0, false) + require.NoError(t, err, "committing state") + s.state, err = New(root, s.state.db, s.state.snaps) + require.NoError(t, err, "creating statedb") s.state.AddBalance(addr, new(uint256.Int)) balance := s.state.GetBalanceMultiCoin(addr, assetID) - if balance.Cmp(big.NewInt(0)) != 0 { - t.Fatal("expected zero multicoin balance") - } + require.Equal(t, "0", balance.String(), "expected zero big.Int multicoin balance as string") s.state.AddBalanceMultiCoin(addr, assetID, big.NewInt(10)) s.state.SubBalanceMultiCoin(addr, assetID, big.NewInt(5)) s.state.AddBalanceMultiCoin(addr, assetID, big.NewInt(3)) balance = s.state.GetBalanceMultiCoin(addr, assetID) - if balance.Cmp(big.NewInt(8)) != 0 { - t.Fatal("expected multicoin balance to be 8") - } + require.Equal(t, "8", balance.String(), "unexpected multicoin balance string") } func TestMultiCoinSnapshot(t *testing.T) { db := rawdb.NewMemoryDatabase() sdb := NewDatabase(db) - // Create empty snapshot.Tree and StateDB + // Create empty [snapshot.Tree] and [StateDB] root := common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") // Use the root as both the stateRoot and blockHash for this test. snapTree := snapshot.NewTestTree(db, root, root) @@ -56,82 +55,80 @@ func TestMultiCoinSnapshot(t *testing.T) { var stateDB *StateDB assertBalances := func(regular, multicoin1, multicoin2 int64) { balance := stateDB.GetBalance(addr) - if balance.Cmp(uint256.NewInt(uint64(regular))) != 0 { - t.Fatal("incorrect non-multicoin balance") - } + require.Equal(t, uint256.NewInt(uint64(regular)), balance, "incorrect non-multicoin balance") balanceBig := stateDB.GetBalanceMultiCoin(addr, assetID1) - if balanceBig.Cmp(big.NewInt(multicoin1)) != 0 { - t.Fatal("incorrect multicoin1 balance") - } + require.Equal(t, big.NewInt(multicoin1).String(), balanceBig.String(), "incorrect multicoin1 balance") balanceBig = stateDB.GetBalanceMultiCoin(addr, assetID2) - if balanceBig.Cmp(big.NewInt(multicoin2)) != 0 { - t.Fatal("incorrect multicoin2 balance") - } + require.Equal(t, big.NewInt(multicoin2).String(), balanceBig.String(), "incorrect multicoin2 balance") } // Create new state - stateDB, _ = New(root, sdb, snapTree) + stateDB, err := New(root, sdb, snapTree) + require.NoError(t, err, "creating statedb") assertBalances(0, 0, 0) stateDB.AddBalance(addr, uint256.NewInt(10)) assertBalances(10, 0, 0) // Commit and get the new root - root, _ = stateDB.Commit(0, false, snapshot.WithBlockHashes(common.Hash{}, common.Hash{})) + root, err = stateDB.Commit(0, false, snapshot.WithBlockHashes(common.Hash{}, common.Hash{})) + require.NoError(t, err, "committing statedb") assertBalances(10, 0, 0) // Create a new state from the latest root, add a multicoin balance, and // commit it to the tree. - stateDB, _ = New(root, sdb, snapTree) + stateDB, err = New(root, sdb, snapTree) + require.NoError(t, err, "creating statedb") stateDB.AddBalanceMultiCoin(addr, assetID1, big.NewInt(10)) - root, _ = stateDB.Commit(0, false, snapshot.WithBlockHashes(common.Hash{}, common.Hash{})) + root, err = stateDB.Commit(0, false, snapshot.WithBlockHashes(common.Hash{}, common.Hash{})) + require.NoError(t, err, "committing statedb") assertBalances(10, 10, 0) // Add more layers than the cap and ensure the balances and layers are correct for i := 0; i < 256; i++ { - stateDB, _ = New(root, sdb, snapTree) + stateDB, err = New(root, sdb, snapTree) + require.NoErrorf(t, err, "creating statedb %d", i) stateDB.AddBalanceMultiCoin(addr, assetID1, big.NewInt(1)) stateDB.AddBalanceMultiCoin(addr, assetID2, big.NewInt(2)) - root, _ = stateDB.Commit(0, false, snapshot.WithBlockHashes(common.Hash{}, common.Hash{})) + root, err = stateDB.Commit(0, false, snapshot.WithBlockHashes(common.Hash{}, common.Hash{})) + require.NoErrorf(t, err, "committing statedb %d", i) } assertBalances(10, 266, 512) // Do one more add, including the regular balance which is now in the // collapsed snapshot - stateDB, _ = New(root, sdb, snapTree) + stateDB, err = New(root, sdb, snapTree) + require.NoError(t, err, "creating statedb") stateDB.AddBalance(addr, uint256.NewInt(1)) stateDB.AddBalanceMultiCoin(addr, assetID1, big.NewInt(1)) - root, _ = stateDB.Commit(0, false, snapshot.WithBlockHashes(common.Hash{}, common.Hash{})) - stateDB, _ = New(root, sdb, snapTree) + root, err = stateDB.Commit(0, false, snapshot.WithBlockHashes(common.Hash{}, common.Hash{})) + require.NoError(t, err, "committing statedb") + + stateDB, err = New(root, sdb, snapTree) + require.NoError(t, err, "creating statedb") assertBalances(11, 267, 512) } func TestGenerateMultiCoinAccounts(t *testing.T) { - var ( - diskdb = rawdb.NewMemoryDatabase() - database = NewDatabase(diskdb) + diskdb := rawdb.NewMemoryDatabase() + database := NewDatabase(diskdb) - addr = common.BytesToAddress([]byte("addr1")) - addrHash = crypto.Keccak256Hash(addr[:]) + addr := common.BytesToAddress([]byte("addr1")) + addrHash := crypto.Keccak256Hash(addr[:]) - assetID = common.BytesToHash([]byte("coin1")) - assetBalance = big.NewInt(10) - ) + assetID := common.BytesToHash([]byte("coin1")) + assetBalance := big.NewInt(10) stateDB, err := New(common.Hash{}, database, nil) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err, "creating statedb") stateDB.AddBalanceMultiCoin(addr, assetID, assetBalance) root, err := stateDB.Commit(0, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err, "committing statedb") triedb := database.TrieDB() - if err := triedb.Commit(root, true); err != nil { - t.Fatal(err) - } + err = triedb.Commit(root, true) + require.NoError(t, err, "committing trie") + // Build snapshot from scratch snapConfig := snapshot.Config{ CacheSize: 16, @@ -140,29 +137,19 @@ func TestGenerateMultiCoinAccounts(t *testing.T) { SkipVerify: true, } snaps, err := snapshot.New(snapConfig, diskdb, triedb, common.Hash{}, root) - if err != nil { - t.Error("Unexpected error while rebuilding snapshot:", err) - } + require.NoError(t, err, "rebuilding snapshot") // Get latest snapshot and make sure it has the correct account and storage snap := snaps.Snapshot(root) snapAccount, err := snap.Account(addrHash) - if err != nil { - t.Fatal(err) - } - if !customtypes.IsMultiCoin(snapAccount) { - t.Fatalf("Expected SnapAccount to return IsMultiCoin: true, found: false") - } + require.NoError(t, err, "getting account from snapshot") + require.True(t, customtypes.IsMultiCoin(snapAccount), "snap account must be multi-coin") NormalizeCoinID(&assetID) assetHash := crypto.Keccak256Hash(assetID.Bytes()) storageBytes, err := snap.Storage(addrHash, assetHash) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err, "getting storage from snapshot") actualAssetBalance := new(big.Int).SetBytes(storageBytes) - if actualAssetBalance.Cmp(assetBalance) != 0 { - t.Fatalf("Expected asset balance: %v, found %v", assetBalance, actualAssetBalance) - } + require.Equal(t, assetBalance, actualAssetBalance, "incorrect asset balance") } diff --git a/core/state_processor.go b/core/state_processor.go index b3c4c32d3f..4b00c141db 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -94,7 +94,6 @@ func (p *StateProcessor) Process(block *types.Block, parent *types.Header, state if beaconRoot := block.BeaconRoot(); beaconRoot != nil { ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) } - // Iterate over and process the individual transactions for i, tx := range block.Transactions() { msg, err := TransactionToMessage(tx, signer, header.BaseFee) @@ -102,7 +101,6 @@ func (p *StateProcessor) Process(block *types.Block, parent *types.Header, state return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } statedb.SetTxContext(tx.Hash(), i) - receipt, err := applyTransaction(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv) if err != nil { return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) @@ -110,7 +108,6 @@ func (p *StateProcessor) Process(block *types.Block, parent *types.Header, state receipts = append(receipts, receipt) allLogs = append(allLogs, receipt.Logs...) } - // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) if err := p.engine.Finalize(p.bc, block, parent, statedb, receipts); err != nil { return nil, nil, 0, fmt.Errorf("engine finalization check failed: %w", err) @@ -129,6 +126,7 @@ func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, sta if err != nil { return nil, err } + // Update the state with pending changes. var root []byte if config.IsByzantium(blockNumber) { @@ -185,7 +183,7 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, blockContext // 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, evm *vm.EVM, statedb *state.StateDB) { +func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB) { // If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with // the new root msg := &Message{ @@ -197,8 +195,8 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM, statedb *state. To: ¶ms.BeaconRootsStorageAddress, Data: beaconRoot[:], } - evm.Reset(NewEVMTxContext(msg), statedb) + vmenv.Reset(NewEVMTxContext(msg), statedb) statedb.AddAddressToAccessList(params.BeaconRootsStorageAddress) - _, _, _ = evm.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) + _, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) statedb.Finalise(true) } diff --git a/core/state_processor_ext.go b/core/state_processor_ext.go index e1d6ef43b9..9145111aa6 100644 --- a/core/state_processor_ext.go +++ b/core/state_processor_ext.go @@ -1,4 +1,6 @@ -// (c) 2025, Ava Labs, Inc. +// (c) 2025, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + package core import ( @@ -15,16 +17,17 @@ import ( ) // ApplyPrecompileActivations checks if any of the precompiles specified by the chain config are enabled or disabled by the block -// transition from [parentTimestamp] to the timestamp set in [blockContext]. If this is the case, it calls [Configure] +// transition from `parentTimestamp` to the timestamp set in `blockContext`. If this is the case, it calls [modules.Module]'s Configure // to apply the necessary state transitions for the upgrade. // This function is called within genesis setup to configure the starting state for precompiles enabled at genesis. -// In block processing and building, ApplyUpgrades is called instead which also applies state upgrades. +// In block processing and building, [ApplyUpgrades] is called instead which also applies state upgrades. func ApplyPrecompileActivations(c *params.ChainConfig, parentTimestamp *uint64, blockContext contract.ConfigurationBlockContext, statedb *state.StateDB) error { blockTimestamp := blockContext.Timestamp() - // Note: RegisteredModules returns precompiles sorted by module addresses. - // This ensures that the order we call Configure for each precompile is consistent. - // This ensures even if precompiles read/write state other than their own they will observe - // an identical global state in a deterministic order when they are configured. + // Note: [modules.RegisteredModules] returns precompiles sorted by module addresses. + // This ensures: + // - the order we call [modules.Module]'s Configure for each precompile is consistent + // - even if precompiles read/write state other than their own they will observe + // an identical global state in a deterministic order when they are configured. extra := params.GetExtra(c) for _, module := range modules.RegisteredModules() { for _, activatingConfig := range extra.GetActivatingPrecompileConfigs(module.Address, parentTimestamp, blockTimestamp, extra.PrecompileUpgrades) { @@ -33,32 +36,32 @@ func ApplyPrecompileActivations(c *params.ChainConfig, parentTimestamp *uint64, if activatingConfig.IsDisabled() { log.Info("Disabling precompile", "name", module.ConfigKey) statedb.SelfDestruct(module.Address) - // Calling Finalise here effectively commits Suicide call and wipes the contract state. + // Calling [state.StateDB]'s Finalise here effectively commits the SelfDestruct call and wipes the contract state. // This enables re-configuration of the same contract state in the same block. - // Without an immediate Finalise call after the Suicide, a reconfigured precompiled state can be wiped out - // since Suicide will be committed after the reconfiguration. + // Without an immediate Finalise call after the SelfDestruct, a reconfigured precompiled state can be wiped out + // since SelfDestruct will be committed after the reconfiguration. statedb.Finalise(true) + continue + } + var printIntf interface{} + marshalled, err := json.Marshal(activatingConfig) + if err == nil { + printIntf = string(marshalled) } else { - var printIntf interface{} - marshalled, err := json.Marshal(activatingConfig) - if err == nil { - printIntf = string(marshalled) - } else { - printIntf = activatingConfig - } + printIntf = activatingConfig + } - log.Info("Activating new precompile", "name", module.ConfigKey, "config", printIntf) - // Set the nonce of the precompile's address (as is done when a contract is created) to ensure - // that it is marked as non-empty and will not be cleaned up when the statedb is finalized. - statedb.SetNonce(module.Address, 1) - // Set the code of the precompile's address to a non-zero length byte slice to ensure that the precompile - // can be called from within Solidity contracts. Solidity adds a check before invoking a contract to ensure - // that it does not attempt to invoke a non-existent contract. - statedb.SetCode(module.Address, []byte{0x1}) - extstatedb := &extstate.StateDB{VmStateDB: statedb} - if err := module.Configure(params.GetExtra(c), activatingConfig, extstatedb, blockContext); err != nil { - return fmt.Errorf("could not configure precompile, name: %s, reason: %w", module.ConfigKey, err) - } + log.Info("Activating new precompile", "name", module.ConfigKey, "config", printIntf) + // Set the nonce of the precompile's address (as is done when a contract is created) to ensure + // that it is marked as non-empty and will not be cleaned up when the statedb is finalized. + statedb.SetNonce(module.Address, 1) + // Set the code of the precompile's address to a non-zero length byte slice to ensure that the precompile + // can be called from within Solidity contracts. Solidity adds a check before invoking a contract to ensure + // that it does not attempt to invoke a non-existent contract. + statedb.SetCode(module.Address, []byte{0x1}) + extstatedb := extstate.New(statedb) + if err := module.Configure(params.GetExtra(c), activatingConfig, extstatedb, blockContext); err != nil { + return fmt.Errorf("could not configure precompile, name: %s, reason: %w", module.ConfigKey, err) } } } @@ -75,16 +78,16 @@ func ApplyUpgrades(c *params.ChainConfig, parentTimestamp *uint64, blockContext return ApplyPrecompileActivations(c, parentTimestamp, blockContext, statedb) } -// BlockContext implements the `contract.ConfigurationBlockContext` interface. +// BlockContext implements [contract.ConfigurationBlockContext]. type BlockContext struct { number *big.Int timestamp uint64 } -// NewBlockContext creates a new block context using the block number -// and block time provided. This function is usually necessary to convert -// a `*types.Block` to be passed as a `contract.ConfigurationBlockContext` -// interface to [ApplyUpgrades]. +// NewBlockContext creates a [BlockContext] using the block number +// and block timestamp provided. This function is usually necessary to convert +// a `*types.Block` to be passed as a [contract.ConfigurationBlockContext] +// to [ApplyUpgrades]. func NewBlockContext(number *big.Int, timestamp uint64) *BlockContext { return &BlockContext{ number: number, diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index fb44f041e1..3402cdeb8e 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -115,9 +115,9 @@ func (bc *testBlockChain) CurrentBlock() *types.Header { BaseFee: mid, Extra: make([]byte, ap3.WindowSize), } - configExtra := params.GetExtra(bc.config) + config := params.GetExtra(bc.config) baseFee, err := header.BaseFee( - configExtra, parent, blockTime, + config, parent, blockTime, ) if err != nil { panic(err) diff --git a/core/txpool/blobpool/metrics.go b/core/txpool/blobpool/metrics.go index f4e9657945..4763c5f6a2 100644 --- a/core/txpool/blobpool/metrics.go +++ b/core/txpool/blobpool/metrics.go @@ -35,10 +35,10 @@ import ( // ====== If resolving merge conflicts ====== // -// All calls to metrics.NewRegistered*() have been replaced with -// metrics.GetOrRegister*() and this package's corresponding libevm package -// imported above. Together these ensure that the metric here is the same as the -// one with the same name in libevm. +// All calls to metrics.NewRegistered*() for metrics also defined in libevm/core/txpool/blobpool +// have been replaced with metrics.GetOrRegister*() to get metrics already registered in +// libevm/core/txpool/blobpool or register them here otherwise. These replacements ensure the +// same metrics are shared between the two packages. var ( // datacapGauge tracks the user's configured capacity for the blob pool. It // is mostly a way to expose/debug issues. diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index c72936f075..5515d59bc2 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -84,10 +84,10 @@ var ( // ====== If resolving merge conflicts ====== // -// All calls to metrics.NewRegistered*() have been replaced with -// metrics.GetOrRegister*() and this package's corresponding libevm package -// imported above. Together these ensure that the metric here is the same as the -// one with the same name in libevm. +// All calls to metrics.NewRegistered*() for metrics also defined in libevm/core/txpool/legacypool +// have been replaced with metrics.GetOrRegister*() to get metrics already registered in +// libevm/core/txpool/legacypool or register them here otherwise. These replacements ensure the +// same metrics are shared between the two packages. var ( // Metrics for the pending pool pendingDiscardMeter = metrics.GetOrRegisterMeter("txpool/pending/discard", nil) @@ -1778,13 +1778,14 @@ func (pool *LegacyPool) demoteUnexecutables() { } func (pool *LegacyPool) startPeriodicFeeUpdate() { - if params.GetExtra(pool.chainconfig).ApricotPhase3BlockTimestamp == nil { + ap3Timestamp := params.GetExtra(pool.chainconfig).ApricotPhase3BlockTimestamp + if ap3Timestamp == nil { return } // Call updateBaseFee here to ensure that there is not a [baseFeeUpdateInterval] delay // when starting up in ApricotPhase3 before the base fee is updated. - if time.Now().After(utils.Uint64ToTime(params.GetExtra(pool.chainconfig).ApricotPhase3BlockTimestamp)) { + if time.Now().After(utils.Uint64ToTime(ap3Timestamp)) { pool.updateBaseFee() } @@ -1796,8 +1797,9 @@ func (pool *LegacyPool) periodicBaseFeeUpdate() { defer pool.wg.Done() // Sleep until its time to start the periodic base fee update or the tx pool is shutting down + ap3Time := utils.Uint64ToTime(params.GetExtra(pool.chainconfig).ApricotPhase3BlockTimestamp) select { - case <-time.After(time.Until(utils.Uint64ToTime(params.GetExtra(pool.chainconfig).ApricotPhase3BlockTimestamp))): + case <-time.After(time.Until(ap3Time)): case <-pool.generalShutdownChan: return // Return early if shutting down } diff --git a/eth/api_debug_test.go b/eth/api_debug_test.go index b1e6a6eba0..26ccd03694 100644 --- a/eth/api_debug_test.go +++ b/eth/api_debug_test.go @@ -34,16 +34,13 @@ import ( "testing" "github.com/ava-labs/coreth/core/state" + "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/rawdb" "github.com/ava-labs/libevm/core/types" + "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/libevm/triedb" - "github.com/holiman/uint256" - "github.com/davecgh/go-spew/spew" - - "github.com/ava-labs/libevm/common" - "github.com/ava-labs/libevm/crypto" - + "github.com/holiman/uint256" "golang.org/x/exp/slices" ) diff --git a/eth/tracers/tracers.go b/eth/tracers/tracers.go index e235b4c5e6..2f0a0a8dab 100644 --- a/eth/tracers/tracers.go +++ b/eth/tracers/tracers.go @@ -18,10 +18,6 @@ package tracers import ( - "errors" - "fmt" - - "github.com/ava-labs/libevm/core/vm" ethtracers "github.com/ava-labs/libevm/eth/tracers" ) @@ -36,26 +32,6 @@ type Tracer = ethtracers.Tracer // DefaultDirectory is the collection of tracers bundled by default. var DefaultDirectory = ethtracers.DefaultDirectory -const ( - memoryPadLimit = 1024 * 1024 -) - // GetMemoryCopyPadded returns offset + size as a new slice. // It zero-pads the slice if it extends beyond memory bounds. -func GetMemoryCopyPadded(m *vm.Memory, offset, size int64) ([]byte, error) { - if offset < 0 || size < 0 { - return nil, errors.New("offset or size must not be negative") - } - if int(offset+size) < m.Len() { // slice fully inside memory - return m.GetCopy(offset, size), nil - } - paddingNeeded := int(offset+size) - m.Len() - if paddingNeeded > memoryPadLimit { - return nil, fmt.Errorf("reached limit for padding memory slice: %d", paddingNeeded) - } - cpy := make([]byte, size) - if overlap := int64(m.Len()) - offset; overlap > 0 { - copy(cpy, m.GetPtr(offset, overlap)) - } - return cpy, nil -} +var GetMemoryCopyPadded = ethtracers.GetMemoryCopyPadded diff --git a/go.mod b/go.mod index a770e40274..7ea125295f 100644 --- a/go.mod +++ b/go.mod @@ -6,10 +6,9 @@ require ( github.com/VictoriaMetrics/fastcache v1.12.1 github.com/ava-labs/avalanchego v1.12.3-name-fortuna.0.0.20250326131842-1e9f474dee74 github.com/ava-labs/libevm v1.13.14-0.2.0.rc.4 - github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 github.com/davecgh/go-spew v1.1.1 github.com/deckarep/golang-set/v2 v2.1.0 - github.com/fjl/gencodec v0.1.1-0.20250314100332-a3c3302847ce + github.com/fjl/gencodec v0.1.1 github.com/google/go-cmp v0.7.0 github.com/gorilla/rpc v1.2.0 github.com/gorilla/websocket v1.5.0 @@ -56,6 +55,7 @@ require ( github.com/consensys/bavard v0.1.13 // indirect github.com/consensys/gnark-crypto v0.12.1 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect + github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 // indirect github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/dlclark/regexp2 v1.7.0 // indirect diff --git a/go.sum b/go.sum index ff0f1d35de..7e07f33b2f 100644 --- a/go.sum +++ b/go.sum @@ -173,8 +173,8 @@ github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/fjl/gencodec v0.1.1-0.20250314100332-a3c3302847ce h1:MjcqyNZgJADSmUq8jNoDNHm+zzJpxTQSB5zmdeowI98= -github.com/fjl/gencodec v0.1.1-0.20250314100332-a3c3302847ce/go.mod h1:chDHL3wKXuBgauP8x3XNZkl5EIAR5SoCTmmmDTZRzmw= +github.com/fjl/gencodec v0.1.1 h1:DhQY29Q6JLXB/GgMqE86NbOEuvckiYcJCbXFu02toms= +github.com/fjl/gencodec v0.1.1/go.mod h1:chDHL3wKXuBgauP8x3XNZkl5EIAR5SoCTmmmDTZRzmw= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= diff --git a/metrics/prometheus/prometheus.go b/metrics/prometheus/prometheus.go index 7cc4e68536..bfa73245c9 100644 --- a/metrics/prometheus/prometheus.go +++ b/metrics/prometheus/prometheus.go @@ -197,7 +197,6 @@ func metricFamily(registry Registry, name string) (mf *dto.MetricFamily, err err }, }}, }, nil - default: return nil, fmt.Errorf("metric %q: type is not supported: %T", name, metric) } diff --git a/nativeasset/contract.go b/nativeasset/contract.go index e4860d9876..991c3dec44 100644 --- a/nativeasset/contract.go +++ b/nativeasset/contract.go @@ -102,14 +102,14 @@ func UnpackNativeAssetCallInput(input []byte) (common.Address, common.Hash, *big return to, assetID, assetAmount, callData, nil } -// Run implements StatefulPrecompiledContract +// Run implements [contract.StatefulPrecompiledContract] func (c *NativeAssetCall) Run(accessibleState contract.AccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { env := accessibleState.GetPrecompileEnv() if !env.UseGas(c.GasCost) { return nil, 0, vm.ErrOutOfGas } ret, err = c.run(env, accessibleState.GetStateDB(), caller, addr, input, readOnly) - // This precompile will be wrapped in a libevm `legacy` wrapper, which + // This precompile will be wrapped in a libevm `legacy.PrecompiledStatefulContract`, which // allows for the deprecated pattern of returning remaining gas by calling // env.UseGas() on the difference between gas in and gas out. Since we call // UseGas() ourselves, we therefore return `suppliedGas` unchanged to stop @@ -119,7 +119,7 @@ func (c *NativeAssetCall) Run(accessibleState contract.AccessibleState, caller c // run implements the contract logic, using `env.Gas()` and `env.UseGas()` in // place of `suppliedGas` and returning `remainingGas`, respectively. This -// avoids mixing gas-accounting patterns when using env.Call(). +// avoids mixing gas-accounting patterns when using `env.Call()`. func (c *NativeAssetCall) run(env vm.PrecompileEnvironment, stateDB contract.StateDB, caller common.Address, addr common.Address, input []byte, readOnly bool) (ret []byte, err error) { if readOnly { return nil, vm.ErrExecutionReverted @@ -131,8 +131,8 @@ func (c *NativeAssetCall) run(env vm.PrecompileEnvironment, stateDB contract.Sta return nil, vm.ErrExecutionReverted } - // Note: it is not possible for a negative assetAmount to be passed in here due to the fact that decoding a - // byte slice into a *big.Int type will always return a positive value, as documented on [big.Int.SetBytes]. + // Note: it is not possible for a negative `assetAmount` to be passed in here due to the fact that decoding a + // byte slice into a [*big.Int] will always return a positive value, as documented on [big.Int.SetBytes]. if assetAmount.Sign() != 0 && stateDB.GetBalanceMultiCoin(caller, assetID).Cmp(assetAmount) < 0 { return nil, vm.ErrInsufficientBalance } @@ -146,7 +146,7 @@ func (c *NativeAssetCall) run(env vm.PrecompileEnvironment, stateDB contract.Sta stateDB.CreateAccount(to) } - // Send [assetAmount] of [assetID] to [to] address + // Send `assetAmount` of `assetID` to `to` address stateDB.SubBalanceMultiCoin(caller, assetID, assetAmount) stateDB.AddBalanceMultiCoin(to, assetID, assetAmount) @@ -159,9 +159,6 @@ func (c *NativeAssetCall) run(env vm.PrecompileEnvironment, stateDB contract.Sta if err != vm.ErrExecutionReverted { env.UseGas(env.Gas()) } - // TODO: consider clearing up unused snapshots: - //} else { - // evm.StateDB.DiscardSnapshot(snapshot) } return ret, err } diff --git a/params/config.go b/params/config.go index cd622e724c..0e6c927ec5 100644 --- a/params/config.go +++ b/params/config.go @@ -46,7 +46,7 @@ var ( AvalancheLocalChainID = big.NewInt(43112) ) -// Guarantees extras initialisation before a call to [ChainConfig.Rules]. +// Guarantees extras initialisation before a call to [params.ChainConfig.Rules]. var _ = libevmInit() var ( diff --git a/params/config_extra.go b/params/config_extra.go index 6efd6c4cdc..ab8f7cc89c 100644 --- a/params/config_extra.go +++ b/params/config_extra.go @@ -21,8 +21,6 @@ const ( IsMergeTODO = true ) -type ConfigCompatError = extras.ConfigCompatError - // SetEthUpgrades enables Etheruem network upgrades using the same time as // the Avalanche network upgrade that enables them. func SetEthUpgrades(c *ChainConfig) { diff --git a/params/config_libevm.go b/params/config_libevm.go index 6ab46dbe7e..4cb663e6f4 100644 --- a/params/config_libevm.go +++ b/params/config_libevm.go @@ -1,4 +1,4 @@ -// (c) 2019-2020, Ava Labs, Inc. All rights reserved. +// (c) 2024-2025, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. package params @@ -14,7 +14,7 @@ import ( ) // libevmInit would ideally be a regular init() function, but it MUST be run -// before any calls to [ChainConfig.Rules]. See `config.go` for its call site. +// before any calls to [params.ChainConfig.Rules]. See `config.go` for its call site. func libevmInit() any { payloads = ethparams.RegisterExtras(ethparams.Extras[*extras.ChainConfig, RulesExtra]{ ReuseJSONRoot: true, // Reuse the root JSON input when unmarshalling the extra payload. diff --git a/params/config_test.go b/params/config_test.go index 3ad2097a07..4b665503f2 100644 --- a/params/config_test.go +++ b/params/config_test.go @@ -35,6 +35,7 @@ import ( "github.com/ava-labs/coreth/params/extras" "github.com/ava-labs/coreth/utils" + ethparams "github.com/ava-labs/libevm/params" ) func TestCheckCompatible(t *testing.T) { @@ -42,7 +43,7 @@ func TestCheckCompatible(t *testing.T) { stored, new *ChainConfig headBlock uint64 headTimestamp uint64 - wantErr *ConfigCompatError + wantErr *ethparams.ConfigCompatError } tests := []test{ {stored: TestChainConfig, new: TestChainConfig, headBlock: 0, headTimestamp: 0, wantErr: nil}, @@ -60,7 +61,7 @@ func TestCheckCompatible(t *testing.T) { new: &ChainConfig{HomesteadBlock: nil}, headBlock: 3, headTimestamp: 30, - wantErr: &ConfigCompatError{ + wantErr: ðparams.ConfigCompatError{ What: "Homestead fork block", StoredBlock: big.NewInt(0), NewBlock: nil, @@ -72,7 +73,7 @@ func TestCheckCompatible(t *testing.T) { new: &ChainConfig{HomesteadBlock: big.NewInt(1)}, headBlock: 3, headTimestamp: 30, - wantErr: &ConfigCompatError{ + wantErr: ðparams.ConfigCompatError{ What: "Homestead fork block", StoredBlock: big.NewInt(0), NewBlock: big.NewInt(1), @@ -84,7 +85,7 @@ func TestCheckCompatible(t *testing.T) { new: &ChainConfig{HomesteadBlock: big.NewInt(25), EIP150Block: big.NewInt(20)}, headBlock: 25, headTimestamp: 250, - wantErr: &ConfigCompatError{ + wantErr: ðparams.ConfigCompatError{ What: "EIP150 fork block", StoredBlock: big.NewInt(10), NewBlock: big.NewInt(20), @@ -103,7 +104,7 @@ func TestCheckCompatible(t *testing.T) { new: &ChainConfig{ConstantinopleBlock: big.NewInt(30), PetersburgBlock: big.NewInt(31)}, headBlock: 40, headTimestamp: 400, - wantErr: &ConfigCompatError{ + wantErr: ðparams.ConfigCompatError{ What: "Petersburg fork block", StoredBlock: nil, NewBlock: big.NewInt(31), @@ -115,7 +116,7 @@ func TestCheckCompatible(t *testing.T) { new: TestApricotPhase4Config, headBlock: 0, headTimestamp: 0, - wantErr: &ConfigCompatError{ + wantErr: ðparams.ConfigCompatError{ What: "ApricotPhase5 fork block timestamp", StoredTime: utils.NewUint64(0), NewTime: nil, @@ -127,7 +128,7 @@ func TestCheckCompatible(t *testing.T) { new: TestApricotPhase4Config, headBlock: 10, headTimestamp: 100, - wantErr: &ConfigCompatError{ + wantErr: ðparams.ConfigCompatError{ What: "ApricotPhase5 fork block timestamp", StoredTime: utils.NewUint64(0), NewTime: nil, diff --git a/params/extras/config.go b/params/extras/config.go index e6a260a61d..0816bcd6a0 100644 --- a/params/extras/config.go +++ b/params/extras/config.go @@ -118,15 +118,15 @@ type ChainConfig struct { UpgradeConfig `json:"-"` // Config specified in upgradeBytes (avalanche network upgrades or enable/disabling precompiles). Not serialized. } -func (c *ChainConfig) CheckConfigCompatible(newcfg_ *ethparams.ChainConfig, headNumber *big.Int, headTimestamp uint64) *ConfigCompatError { +func (c *ChainConfig) CheckConfigCompatible(newcfg_ *ethparams.ChainConfig, headNumber *big.Int, headTimestamp uint64) *ethparams.ConfigCompatError { if c == nil { return nil } newcfg, ok := newcfg_.Hooks().(*ChainConfig) if !ok { - // Proper registration of the extras on libevm side should prevent this from happening. + // Proper registration of the extras on the libevm side should prevent this from happening. // Return an error to prevent the chain from starting, just in case. - return newTimestampCompatError( + return ethparams.NewTimestampCompatError( fmt.Sprintf("ChainConfig.Hooks() is not of the expected type *extras.ChainConfig, got %T", newcfg_.Hooks()), utils.NewUint64(0), nil, @@ -137,12 +137,6 @@ func (c *ChainConfig) CheckConfigCompatible(newcfg_ *ethparams.ChainConfig, head return err } - // Check that the precompiles on the new config are compatible with the existing precompile config. - // XXX: This is missing in master? - // if err := c.checkPrecompilesCompatible(newcfg.PrecompileUpgrades, headTimestamp); err != nil { - // return err - // } - return nil } @@ -172,8 +166,7 @@ func isForkTimestampIncompatible(s1, s2 *uint64, head uint64) bool { } // isTimestampForked returns whether a fork scheduled at timestamp s is active -// at the given head timestamp. Whilst this method is the same as isBlockForked, -// they are explicitly separate for clearer reading. +// at the given head timestamp. func isTimestampForked(s *uint64, head uint64) bool { if s == nil { return false @@ -191,34 +184,6 @@ func configTimestampEqual(x, y *uint64) bool { return *x == *y } -// ConfigCompatError is raised if the locally-stored blockchain is initialised with a -// ChainConfig that would alter the past. -type ConfigCompatError = ethparams.ConfigCompatError - -// newTimestampCompatError is taken verbatim from upstream. -// TODO: export this function from upstream in libevm, so it can be used here. -func newTimestampCompatError(what string, storedtime, newtime *uint64) *ConfigCompatError { - var rew *uint64 - switch { - case storedtime == nil: - rew = newtime - case newtime == nil || *storedtime < *newtime: - rew = storedtime - default: - rew = newtime - } - err := &ConfigCompatError{ - What: what, - StoredTime: storedtime, - NewTime: newtime, - RewindToTime: 0, - } - if rew != nil && *rew > 0 { - err.RewindToTime = *rew - 1 - } - return err -} - // UnmarshalJSON parses the JSON-encoded data and stores the result in the // object pointed to by c. // This is a custom unmarshaler to handle the Precompiles field. @@ -269,8 +234,7 @@ func (c *ChainConfig) CheckConfigForkOrder() error { } // checkForks checks that forks are enabled in order and returns an error if not. -// [blockFork] is true if the fork is a block number fork, false if it is a timestamp fork -// TODO: This code was adapted from CheckConfigForkOrder, consider refactoring to avoid duplication. +// `blockFork` is true if the fork is a block number fork, false if it is a timestamp fork func checkForks(forks []fork, blockFork bool) error { lastFork := fork{} for _, cur := range forks { @@ -321,17 +285,17 @@ func (c *ChainConfig) Verify() error { return nil } -// IsPrecompileEnabled returns whether precompile with [address] is enabled at [timestamp]. +// IsPrecompileEnabled returns whether precompile with `address` is enabled at `timestamp`. func (c *ChainConfig) IsPrecompileEnabled(address common.Address, timestamp uint64) bool { config := c.GetActivePrecompileConfig(address, timestamp) return config != nil && !config.IsDisabled() } -// IsForkTransition returns true if [fork] activates during the transition from -// [parent] to [current]. -// Taking [parent] as a pointer allows for us to pass nil when checking forks +// IsForkTransition returns true if `fork` activates during the transition from +// `parent` to `current`. +// Taking `parent` as a pointer allows for us to pass nil when checking forks // that activate during genesis. -// Note: [parent] and [current] can be either both timestamp values, or both +// Note: `parent` and `current` can be either both timestamp values, or both // block number values, since this function works for both block number and // timestamp activated forks. func IsForkTransition(fork *uint64, parent *uint64, current uint64) bool { @@ -342,10 +306,3 @@ func IsForkTransition(fork *uint64, parent *uint64, current uint64) bool { currentForked := isTimestampForked(fork, current) return !parentForked && currentForked } - -func ptrToString(val *uint64) string { - if val == nil { - return "nil" - } - return fmt.Sprintf("%d", *val) -} diff --git a/params/extras/network_upgrades.go b/params/extras/network_upgrades.go index f55c1758a3..066109bb35 100644 --- a/params/extras/network_upgrades.go +++ b/params/extras/network_upgrades.go @@ -9,6 +9,7 @@ import ( "github.com/ava-labs/avalanchego/upgrade" "github.com/ava-labs/coreth/utils" + ethparams "github.com/ava-labs/libevm/params" ) type NetworkUpgrades struct { @@ -50,45 +51,45 @@ func (n *NetworkUpgrades) Equal(other *NetworkUpgrades) bool { return reflect.DeepEqual(n, other) } -func (n *NetworkUpgrades) checkNetworkUpgradesCompatible(newcfg *NetworkUpgrades, time uint64) *ConfigCompatError { +func (n *NetworkUpgrades) checkNetworkUpgradesCompatible(newcfg *NetworkUpgrades, time uint64) *ethparams.ConfigCompatError { if isForkTimestampIncompatible(n.ApricotPhase1BlockTimestamp, newcfg.ApricotPhase1BlockTimestamp, time) { - return newTimestampCompatError("ApricotPhase1 fork block timestamp", n.ApricotPhase1BlockTimestamp, newcfg.ApricotPhase1BlockTimestamp) + return ethparams.NewTimestampCompatError("ApricotPhase1 fork block timestamp", n.ApricotPhase1BlockTimestamp, newcfg.ApricotPhase1BlockTimestamp) } if isForkTimestampIncompatible(n.ApricotPhase2BlockTimestamp, newcfg.ApricotPhase2BlockTimestamp, time) { - return newTimestampCompatError("ApricotPhase2 fork block timestamp", n.ApricotPhase2BlockTimestamp, newcfg.ApricotPhase2BlockTimestamp) + return ethparams.NewTimestampCompatError("ApricotPhase2 fork block timestamp", n.ApricotPhase2BlockTimestamp, newcfg.ApricotPhase2BlockTimestamp) } if isForkTimestampIncompatible(n.ApricotPhase3BlockTimestamp, newcfg.ApricotPhase3BlockTimestamp, time) { - return newTimestampCompatError("ApricotPhase3 fork block timestamp", n.ApricotPhase3BlockTimestamp, newcfg.ApricotPhase3BlockTimestamp) + return ethparams.NewTimestampCompatError("ApricotPhase3 fork block timestamp", n.ApricotPhase3BlockTimestamp, newcfg.ApricotPhase3BlockTimestamp) } if isForkTimestampIncompatible(n.ApricotPhase4BlockTimestamp, newcfg.ApricotPhase4BlockTimestamp, time) { - return newTimestampCompatError("ApricotPhase4 fork block timestamp", n.ApricotPhase4BlockTimestamp, newcfg.ApricotPhase4BlockTimestamp) + return ethparams.NewTimestampCompatError("ApricotPhase4 fork block timestamp", n.ApricotPhase4BlockTimestamp, newcfg.ApricotPhase4BlockTimestamp) } if isForkTimestampIncompatible(n.ApricotPhase5BlockTimestamp, newcfg.ApricotPhase5BlockTimestamp, time) { - return newTimestampCompatError("ApricotPhase5 fork block timestamp", n.ApricotPhase5BlockTimestamp, newcfg.ApricotPhase5BlockTimestamp) + return ethparams.NewTimestampCompatError("ApricotPhase5 fork block timestamp", n.ApricotPhase5BlockTimestamp, newcfg.ApricotPhase5BlockTimestamp) } if isForkTimestampIncompatible(n.ApricotPhasePre6BlockTimestamp, newcfg.ApricotPhasePre6BlockTimestamp, time) { - return newTimestampCompatError("ApricotPhasePre6 fork block timestamp", n.ApricotPhasePre6BlockTimestamp, newcfg.ApricotPhasePre6BlockTimestamp) + return ethparams.NewTimestampCompatError("ApricotPhasePre6 fork block timestamp", n.ApricotPhasePre6BlockTimestamp, newcfg.ApricotPhasePre6BlockTimestamp) } if isForkTimestampIncompatible(n.ApricotPhase6BlockTimestamp, newcfg.ApricotPhase6BlockTimestamp, time) { - return newTimestampCompatError("ApricotPhase6 fork block timestamp", n.ApricotPhase6BlockTimestamp, newcfg.ApricotPhase6BlockTimestamp) + return ethparams.NewTimestampCompatError("ApricotPhase6 fork block timestamp", n.ApricotPhase6BlockTimestamp, newcfg.ApricotPhase6BlockTimestamp) } if isForkTimestampIncompatible(n.ApricotPhasePost6BlockTimestamp, newcfg.ApricotPhasePost6BlockTimestamp, time) { - return newTimestampCompatError("ApricotPhasePost6 fork block timestamp", n.ApricotPhasePost6BlockTimestamp, newcfg.ApricotPhasePost6BlockTimestamp) + return ethparams.NewTimestampCompatError("ApricotPhasePost6 fork block timestamp", n.ApricotPhasePost6BlockTimestamp, newcfg.ApricotPhasePost6BlockTimestamp) } if isForkTimestampIncompatible(n.BanffBlockTimestamp, newcfg.BanffBlockTimestamp, time) { - return newTimestampCompatError("Banff fork block timestamp", n.BanffBlockTimestamp, newcfg.BanffBlockTimestamp) + return ethparams.NewTimestampCompatError("Banff fork block timestamp", n.BanffBlockTimestamp, newcfg.BanffBlockTimestamp) } if isForkTimestampIncompatible(n.CortinaBlockTimestamp, newcfg.CortinaBlockTimestamp, time) { - return newTimestampCompatError("Cortina fork block timestamp", n.CortinaBlockTimestamp, newcfg.CortinaBlockTimestamp) + return ethparams.NewTimestampCompatError("Cortina fork block timestamp", n.CortinaBlockTimestamp, newcfg.CortinaBlockTimestamp) } if isForkTimestampIncompatible(n.DurangoBlockTimestamp, newcfg.DurangoBlockTimestamp, time) { - return newTimestampCompatError("Durango fork block timestamp", n.DurangoBlockTimestamp, newcfg.DurangoBlockTimestamp) + return ethparams.NewTimestampCompatError("Durango fork block timestamp", n.DurangoBlockTimestamp, newcfg.DurangoBlockTimestamp) } if isForkTimestampIncompatible(n.EtnaTimestamp, newcfg.EtnaTimestamp, time) { - return newTimestampCompatError("Etna fork block timestamp", n.EtnaTimestamp, newcfg.EtnaTimestamp) + return ethparams.NewTimestampCompatError("Etna fork block timestamp", n.EtnaTimestamp, newcfg.EtnaTimestamp) } if isForkTimestampIncompatible(n.FortunaTimestamp, newcfg.FortunaTimestamp, time) { - return newTimestampCompatError("Fortuna fork block timestamp", n.FortunaTimestamp, newcfg.FortunaTimestamp) + return ethparams.NewTimestampCompatError("Fortuna fork block timestamp", n.FortunaTimestamp, newcfg.FortunaTimestamp) } return nil @@ -253,3 +254,10 @@ func (n *NetworkUpgrades) GetAvalancheRules(timestamp uint64) AvalancheRules { IsFortuna: n.IsFortuna(timestamp), } } + +func ptrToString(val *uint64) string { + if val == nil { + return "nil" + } + return fmt.Sprintf("%d", *val) +} diff --git a/params/extras/precompile_upgrade.go b/params/extras/precompile_upgrade.go index 6f1522673d..7e216530bf 100644 --- a/params/extras/precompile_upgrade.go +++ b/params/extras/precompile_upgrade.go @@ -12,6 +12,7 @@ import ( "github.com/ava-labs/coreth/precompile/precompileconfig" "github.com/ava-labs/coreth/utils" "github.com/ava-labs/libevm/common" + ethparams "github.com/ava-labs/libevm/params" ) var errNoKey = errors.New("PrecompileUpgrade cannot be empty") @@ -172,7 +173,7 @@ func (c *ChainConfig) GetActivatingPrecompileConfigs(address common.Address, fro // new upgrade to be applied as long as it activates after the last accepted block. // //nolint:unused -func (c *ChainConfig) checkPrecompilesCompatible(precompileUpgrades []PrecompileUpgrade, time uint64) *ConfigCompatError { +func (c *ChainConfig) checkPrecompilesCompatible(precompileUpgrades []PrecompileUpgrade, time uint64) *ethparams.ConfigCompatError { for _, module := range modules.RegisteredModules() { if err := c.checkPrecompileCompatible(module.Address, precompileUpgrades, time); err != nil { return err @@ -188,7 +189,7 @@ func (c *ChainConfig) checkPrecompilesCompatible(precompileUpgrades []Precompile // Upgrades that have already gone into effect cannot be modified or absent from [precompileUpgrades]. // //nolint:unused -func (c *ChainConfig) checkPrecompileCompatible(address common.Address, precompileUpgrades []PrecompileUpgrade, time uint64) *ConfigCompatError { +func (c *ChainConfig) checkPrecompileCompatible(address common.Address, precompileUpgrades []PrecompileUpgrade, time uint64) *ethparams.ConfigCompatError { // All active upgrades (from nil to [lastTimestamp]) must match. activeUpgrades := c.GetActivatingPrecompileConfigs(address, nil, time, c.PrecompileUpgrades) newUpgrades := c.GetActivatingPrecompileConfigs(address, nil, time, precompileUpgrades) @@ -197,7 +198,7 @@ func (c *ChainConfig) checkPrecompileCompatible(address common.Address, precompi for i, upgrade := range activeUpgrades { if len(newUpgrades) <= i { // missing upgrade - return newTimestampCompatError( + return ethparams.NewTimestampCompatError( fmt.Sprintf("missing PrecompileUpgrade[%d]", i), upgrade.Timestamp(), nil, @@ -205,7 +206,7 @@ func (c *ChainConfig) checkPrecompileCompatible(address common.Address, precompi } // All upgrades that have activated must be identical. if !upgrade.Equal(newUpgrades[i]) { - return newTimestampCompatError( + return ethparams.NewTimestampCompatError( fmt.Sprintf("PrecompileUpgrade[%d]", i), upgrade.Timestamp(), newUpgrades[i].Timestamp(), @@ -215,7 +216,7 @@ func (c *ChainConfig) checkPrecompileCompatible(address common.Address, precompi // then, make sure newUpgrades does not have additional upgrades // that are already activated. (cannot perform retroactive upgrade) if len(newUpgrades) > len(activeUpgrades) { - return newTimestampCompatError( + return ethparams.NewTimestampCompatError( fmt.Sprintf("cannot retroactively enable PrecompileUpgrade[%d]", len(activeUpgrades)), nil, newUpgrades[len(activeUpgrades)].Timestamp(), // this indexes to the first element in newUpgrades after the end of activeUpgrades diff --git a/params/extras/rules.go b/params/extras/rules.go index 40b51a3ba2..237cc791a7 100644 --- a/params/extras/rules.go +++ b/params/extras/rules.go @@ -34,7 +34,7 @@ func (r *Rules) PredicaterExists(addr common.Address) bool { return ok } -// IsPrecompileEnabled returns true if the precompile at [addr] is enabled for this rule set. +// IsPrecompileEnabled returns true if the precompile at `addr` is enabled for this rule set. func (r *Rules) IsPrecompileEnabled(addr common.Address) bool { _, ok := r.Precompiles[addr] return ok diff --git a/params/hooks_libevm.go b/params/hooks_libevm.go index ff502f9859..af7e24a25f 100644 --- a/params/hooks_libevm.go +++ b/params/hooks_libevm.go @@ -1,10 +1,12 @@ -// (c) 2019-2020, Ava Labs, Inc. All rights reserved. +// (c) 2024-2025, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. package params import ( + "maps" "math/big" + "slices" "github.com/ava-labs/avalanchego/snow" "github.com/ava-labs/coreth/nativeasset" @@ -18,7 +20,6 @@ import ( "github.com/ava-labs/libevm/core/vm" "github.com/ava-labs/libevm/libevm" "github.com/ava-labs/libevm/libevm/legacy" - "golang.org/x/exp/maps" ) type RulesExtra extras.Rules @@ -74,7 +75,7 @@ func (r RulesExtra) ActivePrecompiles(existing []common.Address) []common.Addres } var addresses []common.Address - addresses = append(addresses, maps.Keys(precompiles)...) + addresses = slices.AppendSeq(addresses, maps.Keys(precompiles)) addresses = append(addresses, existing...) return addresses } @@ -117,7 +118,7 @@ func makePrecompile(contract contract.StatefulPrecompiledContract) libevm.Precom panic(err) // Should never happen, as results are already validated in block validation } } - accessableState := accessableState{ + accessibleState := accessibleState{ env: env, blockContext: &precompileBlockContext{ number: env.BlockNumber(), @@ -125,7 +126,7 @@ func makePrecompile(contract contract.StatefulPrecompiledContract) libevm.Precom predicateResults: predicateResults, }, } - return contract.Run(accessableState, env.Addresses().Caller, env.Addresses().Self, input, suppliedGas, env.ReadOnly()) + return contract.Run(accessibleState, env.Addresses().Caller, env.Addresses().Self, input, suppliedGas, env.ReadOnly()) } return vm.NewStatefulPrecompile(legacy.PrecompiledStatefulContract(run).Upgrade()) } @@ -145,13 +146,14 @@ func (r RulesExtra) PrecompileOverride(addr common.Address) (libevm.PrecompiledC return makePrecompile(module.Contract), true } -type accessableState struct { +type accessibleState struct { env vm.PrecompileEnvironment blockContext *precompileBlockContext } -func (a accessableState) GetStateDB() contract.StateDB { - // XXX: this should be moved to the precompiles +func (a accessibleState) GetStateDB() contract.StateDB { + // TODO the contracts should be refactored to call `env.ReadOnlyState` + // or `env.StateDB` based on the env.ReadOnly() flag var state libevm.StateReader if a.env.ReadOnly() { state = a.env.ReadOnlyState() @@ -161,19 +163,19 @@ func (a accessableState) GetStateDB() contract.StateDB { return state.(contract.StateDB) } -func (a accessableState) GetBlockContext() contract.BlockContext { +func (a accessibleState) GetBlockContext() contract.BlockContext { return a.blockContext } -func (a accessableState) GetChainConfig() precompileconfig.ChainConfig { +func (a accessibleState) GetChainConfig() precompileconfig.ChainConfig { return GetExtra(a.env.ChainConfig()) } -func (a accessableState) GetSnowContext() *snow.Context { +func (a accessibleState) GetSnowContext() *snow.Context { return GetExtra(a.env.ChainConfig()).SnowCtx } -func (a accessableState) GetPrecompileEnv() vm.PrecompileEnvironment { +func (a accessibleState) GetPrecompileEnv() vm.PrecompileEnvironment { return a.env } diff --git a/plugin/evm/block.go b/plugin/evm/block.go index 77f580fa04..d9ed019cf0 100644 --- a/plugin/evm/block.go +++ b/plugin/evm/block.go @@ -153,8 +153,8 @@ func (b *Block) Accept(context.Context) error { // Call Accept for relevant precompile logs. Note we do this prior to // calling Accept on the blockChain so any side effects (eg warp signatures) // take place before the accepted log is emitted to subscribers. - rules := b.vm.chainConfig.Rules(b.ethBlock.Number(), params.IsMergeTODO, b.ethBlock.Time()) - if err := b.handlePrecompileAccept(*params.GetRulesExtra(rules)); err != nil { + rules := b.vm.rules(b.ethBlock.Number(), b.ethBlock.Time()) + if err := b.handlePrecompileAccept(rules); err != nil { return err } if err := vm.blockChain.Accept(b.ethBlock); err != nil { @@ -281,7 +281,7 @@ func (b *Block) Verify(context.Context) error { // ShouldVerifyWithContext implements the block.WithVerifyContext interface func (b *Block) ShouldVerifyWithContext(context.Context) (bool, error) { - rules := params.GetRulesExtra(b.vm.chainConfig.Rules(b.ethBlock.Number(), params.IsMergeTODO, b.ethBlock.Time())) + rules := b.vm.rules(b.ethBlock.Number(), b.ethBlock.Time()) predicates := rules.Predicaters // Short circuit early if there are no predicates to verify if len(predicates) == 0 { @@ -386,7 +386,7 @@ func (b *Block) verifyPredicates(predicateContext *precompileconfig.PredicateCon return fmt.Errorf("failed to marshal predicate results: %w", err) } extraData := b.ethBlock.Extra() - avalancheRules := params.GetRulesExtra(rules).AvalancheRules + avalancheRules := rulesExtra.AvalancheRules headerPredicateResultsBytes := header.PredicateBytesFromExtra(avalancheRules, extraData) if !bytes.Equal(headerPredicateResultsBytes, predicateResultsBytes) { return fmt.Errorf("%w (remote: %x local: %x)", errInvalidHeaderPredicateResults, headerPredicateResultsBytes, predicateResultsBytes) diff --git a/plugin/evm/customrawdb/database_ext.go b/plugin/evm/customrawdb/database_ext.go index 907e4fed40..c9a6c83f26 100644 --- a/plugin/evm/customrawdb/database_ext.go +++ b/plugin/evm/customrawdb/database_ext.go @@ -7,14 +7,14 @@ import ( "bytes" "github.com/ava-labs/libevm/common" - ethrawdb "github.com/ava-labs/libevm/core/rawdb" + "github.com/ava-labs/libevm/core/rawdb" "github.com/ava-labs/libevm/ethdb" ) // InspectDatabase traverses the entire database and checks the size // of all different categories of data. func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { - type stat = ethrawdb.DatabaseStat + type stat = rawdb.DatabaseStat stats := []struct { name string keyLen int @@ -27,12 +27,12 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { {"Block numbers synced to", syncPerformedKeyLength, syncPerformedPrefix, &stat{}}, } - options := []ethrawdb.InspectDatabaseOption{ - ethrawdb.WithDatabaseMetadataKeys(func(key []byte) bool { + options := []rawdb.InspectDatabaseOption{ + rawdb.WithDatabaseMetadataKeys(func(key []byte) bool { return bytes.Equal(key, snapshotBlockHashKey) || bytes.Equal(key, syncRootKey) }), - ethrawdb.WithDatabaseStatRecorder(func(key []byte, size common.StorageSize) bool { + rawdb.WithDatabaseStatRecorder(func(key []byte, size common.StorageSize) bool { for _, s := range stats { if len(key) == s.keyLen && bytes.HasPrefix(key, s.keyPrefix) { s.stat.Add(size) @@ -41,7 +41,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { } return false }), - ethrawdb.WithDatabaseStatsTransformer(func(rows [][]string) [][]string { + rawdb.WithDatabaseStatsTransformer(func(rows [][]string) [][]string { newRows := make([][]string, 0, len(rows)) for _, row := range rows { switch db, cat := row[0], row[1]; { @@ -59,5 +59,5 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { }), } - return ethrawdb.InspectDatabase(db, keyPrefix, keyStart, options...) + return rawdb.InspectDatabase(db, keyPrefix, keyStart, options...) } diff --git a/plugin/evm/customtypes/block_test.go b/plugin/evm/customtypes/block_test.go index a444e23845..bb49783892 100644 --- a/plugin/evm/customtypes/block_test.go +++ b/plugin/evm/customtypes/block_test.go @@ -36,22 +36,21 @@ import ( "github.com/ava-labs/coreth/params" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/common/math" + "github.com/ava-labs/libevm/core/types" "github.com/ava-labs/libevm/crypto" "github.com/ava-labs/libevm/rlp" + // This test file has to be in package types_test to avoid a circular + // dependency when importing `params`. We dot-import the package to mimic + // regular same-package behaviour. . "github.com/ava-labs/coreth/plugin/evm/customtypes" - - // TODO(arr4n) These tests were originally part of the `coreth/core/types` - // package so assume the presence of identifiers. A dot-import reduces PR - // noise during the refactoring. - . "github.com/ava-labs/libevm/core/types" ) // This test has been modified from https://github.com/ethereum/go-ethereum/blob/v1.9.21/core/types/block_test.go#L35 to fit // the modified block format of Coreth func TestBlockEncoding(t *testing.T) { blockEnc := common.FromHex("f90291f90217a04504ee98a94d16dbd70a35370501a3cb00c2965b012672085fbd328a72962902a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940100000000000000000000000000000000000000a00202e12a30c13562445052414c24dce5f1c530bb164e2a50897f0a6a1f78f158a0ecdf3b2c973d4156782b95816451fe9ed66b099cdca22f1168591ae2087765f4a0056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000103837a12008252088460674e8a80a00000000000000000000000000000000000000000000000000000000000000000880000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f872f870808534630b8a00825208941954b772512974978793a809ecd8dce02dc71ba989014d1120d7b160000080830150f4a0beebf298ec38f9f4204f924686c4e5dd00f525fc1979ad224661ed2839ed55fda0267c480d1236c1684bdbad564a422e0a05007d7e8ca1acefe34e790b1d3a450ec08080") - var block Block + var block types.Block if err := rlp.DecodeBytes(blockEnc, &block); err != nil { t.Fatal("decode error: ", err) } @@ -67,7 +66,7 @@ func TestBlockEncoding(t *testing.T) { check("Root", block.Root(), common.HexToHash("0202e12a30c13562445052414c24dce5f1c530bb164e2a50897f0a6a1f78f158")) check("TxHash", block.TxHash(), common.HexToHash("ecdf3b2c973d4156782b95816451fe9ed66b099cdca22f1168591ae2087765f4")) check("ReceiptHash", block.ReceiptHash(), common.HexToHash("056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2")) - check("Bloom", block.Bloom(), BytesToBloom(common.FromHex("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"))) + check("Bloom", block.Bloom(), types.BytesToBloom(common.FromHex("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"))) check("Difficulty", block.Difficulty(), big.NewInt(1)) check("BlockNumber", block.NumberU64(), uint64(3)) check("GasLimit", block.GasLimit(), uint64(8000000)) @@ -98,7 +97,7 @@ func TestBlockEncoding(t *testing.T) { func TestEIP1559BlockEncoding(t *testing.T) { blockEnc := common.FromHex("f9032ef9021fa04504ee98a94d16dbd70a35370501a3cb00c2965b012672085fbd328a72962902a00000000000000000000000000000000000000000000000000000000000000000948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000003832fefd8825208845506eb0780a0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff49888a13a5a8c8f2bb1c4a00000000000000000000000000000000000000000000000000000000000000000843b9aca00f90106f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba09bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094fa08a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1b8a302f8a0018080843b9aca008301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000080a0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0a06de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8c08080") - var block Block + var block types.Block if err := rlp.DecodeBytes(blockEnc, &block); err != nil { t.Fatal("decode error: ", err) } @@ -123,18 +122,18 @@ func TestEIP1559BlockEncoding(t *testing.T) { check("ExtDataGasUsed", BlockExtDataGasUsed(&block), (*big.Int)(nil)) check("BlockGasCost", BlockGasCost(&block), (*big.Int)(nil)) - tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), 50000, big.NewInt(10), nil) - tx1, _ = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b100")) + tx1 := types.NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), 50000, big.NewInt(10), nil) + tx1, _ = tx1.WithSignature(types.HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b100")) addr := common.HexToAddress("0x0000000000000000000000000000000000000001") - accesses := AccessList{AccessTuple{ + accesses := types.AccessList{types.AccessTuple{ Address: addr, StorageKeys: []common.Hash{ {0}, }, }} to := common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87") - txdata := &DynamicFeeTx{ + txdata := &types.DynamicFeeTx{ ChainID: big.NewInt(1), Nonce: 0, To: &to, @@ -144,8 +143,8 @@ func TestEIP1559BlockEncoding(t *testing.T) { AccessList: accesses, Data: []byte{}, } - tx2 := NewTx(txdata) - tx2, err := tx2.WithSignature(LatestSignerForChainID(big.NewInt(1)), common.Hex2Bytes("fe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b06de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a800")) + tx2 := types.NewTx(txdata) + tx2, err := tx2.WithSignature(types.LatestSignerForChainID(big.NewInt(1)), common.Hex2Bytes("fe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b06de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a800")) if err != nil { t.Fatal("invalid signature error: ", err) } @@ -165,7 +164,7 @@ func TestEIP1559BlockEncoding(t *testing.T) { func TestEIP2718BlockEncoding(t *testing.T) { blockEnc := common.FromHex("f9033cf90232a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a0e6e49996c7ec59f7a23d22b83239a60151512c65613bf84a0d7da336399ebc4aa0cafe75574d59780665a97fbfd11365c7545aa8f1abf4e5e12e8243334ef7286bb901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000820200832fefd882a410845506eb0796636f6f6c65737420626c6f636b206f6e20636861696ea0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff49888a13a5a8c8f2bb1c4a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f90101f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba09bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094fa08a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1b89e01f89b01800a8301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000001a03dbacc8d0259f2508625e97fdfc57cd85fdd16e5821bc2c10bdd1a52649e8335a0476e10695b183a87b0aa292a7f4b78ef0c3fbe62aa2c42c84e1d9c3da159ef14c08080") - var block Block + var block types.Block if err := rlp.DecodeBytes(blockEnc, &block); err != nil { t.Fatal("decode error: ", err) } @@ -191,7 +190,7 @@ func TestEIP2718BlockEncoding(t *testing.T) { // Create legacy tx. to := common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87") - tx1 := NewTx(&LegacyTx{ + tx1 := types.NewTx(&types.LegacyTx{ Nonce: 0, To: &to, Value: big.NewInt(10), @@ -199,25 +198,25 @@ func TestEIP2718BlockEncoding(t *testing.T) { GasPrice: big.NewInt(10), }) sig := common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b100") - tx1, _ = tx1.WithSignature(HomesteadSigner{}, sig) + tx1, _ = tx1.WithSignature(types.HomesteadSigner{}, sig) // Create ACL tx. addr := common.HexToAddress("0x0000000000000000000000000000000000000001") - tx2 := NewTx(&AccessListTx{ + tx2 := types.NewTx(&types.AccessListTx{ ChainID: big.NewInt(1), Nonce: 0, To: &to, Gas: 123457, GasPrice: big.NewInt(10), - AccessList: AccessList{{Address: addr, StorageKeys: []common.Hash{{0}}}}, + AccessList: types.AccessList{{Address: addr, StorageKeys: []common.Hash{{0}}}}, }) sig2 := common.Hex2Bytes("3dbacc8d0259f2508625e97fdfc57cd85fdd16e5821bc2c10bdd1a52649e8335476e10695b183a87b0aa292a7f4b78ef0c3fbe62aa2c42c84e1d9c3da159ef1401") - tx2, _ = tx2.WithSignature(NewEIP2930Signer(big.NewInt(1)), sig2) + tx2, _ = tx2.WithSignature(types.NewEIP2930Signer(big.NewInt(1)), sig2) check("len(Transactions)", len(block.Transactions()), 2) check("Transactions[0].Hash", block.Transactions()[0].Hash(), tx1.Hash()) check("Transactions[1].Hash", block.Transactions()[1].Hash(), tx2.Hash()) - check("Transactions[1].Type()", block.Transactions()[1].Type(), uint8(AccessListTxType)) + check("Transactions[1].Type()", block.Transactions()[1].Type(), uint8(types.AccessListTxType)) if !bytes.Equal(BlockExtData(&block), []byte{}) { t.Errorf("Block ExtraData field mismatch, expected empty byte array, but found 0x%x", BlockExtData(&block)) @@ -234,7 +233,7 @@ func TestEIP2718BlockEncoding(t *testing.T) { func TestBlockEncodingWithExtraData(t *testing.T) { blockEnc := common.FromHex("f903f2f90215a02a0d1d68d26eb213cf1c6c1e6abbaf374f0ee9a5428558df334c36d380c6a080a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940100000000000000000000000000000000000000a0c0caa90fe3722cb2e288f7998d54a855a6d40f67e0e77a695d0d65dad22c6290a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000102837a1200808460674e3380a00000000000000000000000000000000000000000000000000000000000000000880000000000000000a0296ff3bfdebf7c4b1fb71f589d69ed03b1c59b278d1780d54dc86ea7cb87cf17c0c080b901d400000000000000003039c85fc1980a77c5da78fe5486233fc09a769bb812bcb2cc548cf9495d046b3f1bd891ad56056d9c01f18f43f58b5c784ad07a4a49cf3d1f11623804b5cba2c6bf000000028a0f7c3e4d840143671a4c4ecacccb4d60fb97dce97a7aa5d60dfd072a7509cf00000001dbcf890f77f49b96857648b72b77f9f82937f28a68704af05da0dc12ba53f2db0000000500002d79883d20000000000100000000e0d5c4edc78f594b79025a56c44933c28e8ba3e51e6e23318727eeaac10eb27d00000001dbcf890f77f49b96857648b72b77f9f82937f28a68704af05da0dc12ba53f2db0000000500002d79883d20000000000100000000000000016dc8ea73dd39ab12fa2ecbc3427abaeb87d56fd800005af3107a4000dbcf890f77f49b96857648b72b77f9f82937f28a68704af05da0dc12ba53f2db0000000200000009000000010d9f115cd63c3ab78b5b82cfbe4339cd6be87f21cda14cf192b269c7a6cb2d03666aa8f8b23ca0a2ceee4050e75c9b05525a17aa1dd0e9ea391a185ce395943f0000000009000000010d9f115cd63c3ab78b5b82cfbe4339cd6be87f21cda14cf192b269c7a6cb2d03666aa8f8b23ca0a2ceee4050e75c9b05525a17aa1dd0e9ea391a185ce395943f00") - var block Block + var block types.Block if err := rlp.DecodeBytes(blockEnc, &block); err != nil { t.Fatal("decode error: ", err) } @@ -250,7 +249,7 @@ func TestBlockEncodingWithExtraData(t *testing.T) { check("Root", block.Root(), common.HexToHash("c0caa90fe3722cb2e288f7998d54a855a6d40f67e0e77a695d0d65dad22c6290")) check("TxHash", block.TxHash(), common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")) check("ReceiptHash", block.ReceiptHash(), common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")) - check("Bloom", block.Bloom(), BytesToBloom(common.FromHex("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"))) + check("Bloom", block.Bloom(), types.BytesToBloom(common.FromHex("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"))) check("Difficulty", block.Difficulty(), big.NewInt(1)) check("BlockNumber", block.NumberU64(), uint64(2)) check("GasLimit", block.GasLimit(), uint64(8000000)) @@ -284,8 +283,8 @@ func TestBlockEncodingWithExtraData(t *testing.T) { } func TestUncleHash(t *testing.T) { - uncles := make([]*Header, 0) - h := CalcUncleHash(uncles) + uncles := make([]*types.Header, 0) + h := types.CalcUncleHash(uncles) exp := common.HexToHash("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347") if h != exp { t.Fatalf("empty uncle hash is wrong, got %x != %x", h, exp) @@ -306,15 +305,15 @@ func BenchmarkEncodeBlock(b *testing.B) { } } -func makeBenchBlock() *Block { +func makeBenchBlock() *types.Block { var ( key, _ = crypto.GenerateKey() - txs = make([]*Transaction, 70) - receipts = make([]*Receipt, len(txs)) - signer = LatestSigner(params.TestChainConfig) - uncles = make([]*Header, 3) + txs = make([]*types.Transaction, 70) + receipts = make([]*types.Receipt, len(txs)) + signer = types.LatestSigner(params.TestChainConfig) + uncles = make([]*types.Header, 3) ) - header := &Header{ + header := &types.Header{ Difficulty: math.BigPow(11, 11), Number: math.BigPow(2, 9), GasLimit: 12345678, @@ -326,16 +325,16 @@ func makeBenchBlock() *Block { amount := math.BigPow(2, int64(i)) price := big.NewInt(300000) data := make([]byte, 100) - tx := NewTransaction(uint64(i), common.Address{}, amount, 123457, price, data) - signedTx, err := SignTx(tx, signer, key) + tx := types.NewTransaction(uint64(i), common.Address{}, amount, 123457, price, data) + signedTx, err := types.SignTx(tx, signer, key) if err != nil { panic(err) } txs[i] = signedTx - receipts[i] = NewReceipt(make([]byte, 32), false, tx.Gas()) + receipts[i] = types.NewReceipt(make([]byte, 32), false, tx.Gas()) } for i := range uncles { - uncles[i] = &Header{ + uncles[i] = &types.Header{ Difficulty: math.BigPow(11, 11), Number: math.BigPow(2, 9), GasLimit: 12345678, @@ -344,12 +343,12 @@ func makeBenchBlock() *Block { Extra: []byte("benchmark uncle"), } } - return NewBlock(header, txs, uncles, receipts, blocktest.NewHasher()) + return types.NewBlock(header, txs, uncles, receipts, blocktest.NewHasher()) } func TestAP4BlockEncoding(t *testing.T) { blockEnc := common.FromHex("f90335f90226a04504ee98a94d16dbd70a35370501a3cb00c2965b012672085fbd328a72962902a00000000000000000000000000000000000000000000000000000000000000000948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000003832fefd8825208845506eb0780a0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff49888a13a5a8c8f2bb1c4a00000000000000000000000000000000000000000000000000000000000000000843b9aca008261a8830f4240f90106f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba09bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094fa08a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1b8a302f8a0018080843b9aca008301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000080a0fe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b0a06de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a8c08080") - var block Block + var block types.Block if err := rlp.DecodeBytes(blockEnc, &block); err != nil { t.Fatal("decode error: ", err) } @@ -375,18 +374,18 @@ func TestAP4BlockEncoding(t *testing.T) { check("ExtDataGasUsed", BlockExtDataGasUsed(&block), big.NewInt(25_000)) check("BlockGasCost", BlockGasCost(&block), big.NewInt(1_000_000)) - tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), 50000, big.NewInt(10), nil) - tx1, _ = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b100")) + tx1 := types.NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), 50000, big.NewInt(10), nil) + tx1, _ = tx1.WithSignature(types.HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b100")) addr := common.HexToAddress("0x0000000000000000000000000000000000000001") - accesses := AccessList{AccessTuple{ + accesses := types.AccessList{types.AccessTuple{ Address: addr, StorageKeys: []common.Hash{ {0}, }, }} to := common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87") - txdata := &DynamicFeeTx{ + txdata := &types.DynamicFeeTx{ ChainID: big.NewInt(1), Nonce: 0, To: &to, @@ -396,8 +395,8 @@ func TestAP4BlockEncoding(t *testing.T) { AccessList: accesses, Data: []byte{}, } - tx2 := NewTx(txdata) - tx2, err := tx2.WithSignature(LatestSignerForChainID(big.NewInt(1)), common.Hex2Bytes("fe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b06de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a800")) + tx2 := types.NewTx(txdata) + tx2, err := tx2.WithSignature(types.LatestSignerForChainID(big.NewInt(1)), common.Hex2Bytes("fe38ca4e44a30002ac54af7cf922a6ac2ba11b7d22f548e8ecb3f51f41cb31b06de6a5cbae13c0c856e33acf021b51819636cfc009d39eafb9f606d546e305a800")) if err != nil { t.Fatal("invalid signature error: ", err) } diff --git a/plugin/evm/header/block_gas_cost.go b/plugin/evm/header/block_gas_cost.go index bb1a8e2701..638adec5b2 100644 --- a/plugin/evm/header/block_gas_cost.go +++ b/plugin/evm/header/block_gas_cost.go @@ -102,9 +102,8 @@ func EstimateRequiredTip( } // totalGasUsed = GasUsed + ExtDataGasUsed - headerExtra := customtypes.GetHeaderExtra(header) totalGasUsed := new(big.Int).SetUint64(header.GasUsed) - totalGasUsed.Add(totalGasUsed, headerExtra.ExtDataGasUsed) + totalGasUsed.Add(totalGasUsed, extra.ExtDataGasUsed) if totalGasUsed.Sign() == 0 { return nil, errNoGasUsed } @@ -114,7 +113,7 @@ func EstimateRequiredTip( // We add totalGasUsed - 1 to ensure that the total required tips // calculation rounds up. totalRequiredTips := new(big.Int) - totalRequiredTips.Mul(headerExtra.BlockGasCost, header.BaseFee) + totalRequiredTips.Mul(extra.BlockGasCost, header.BaseFee) totalRequiredTips.Add(totalRequiredTips, totalGasUsed) totalRequiredTips.Sub(totalRequiredTips, common.Big1) diff --git a/plugin/evm/header/extra.go b/plugin/evm/header/extra.go index 119cf34113..646f5528da 100644 --- a/plugin/evm/header/extra.go +++ b/plugin/evm/header/extra.go @@ -193,8 +193,10 @@ func SetPredicateBytesInExtra(rules extras.AvalancheRules, extra []byte, predica if len(extra) < offset { // pad extra with zeros extra = append(extra, make([]byte, offset-len(extra))...) + } else { + // truncate extra to the offset + extra = extra[:offset] } - extra = extra[:offset] // truncate extra to the offset extra = append(extra, predicateBytes...) return extra } diff --git a/plugin/evm/header/extra_test.go b/plugin/evm/header/extra_test.go index e6a4ec82c2..99fe3abdbe 100644 --- a/plugin/evm/header/extra_test.go +++ b/plugin/evm/header/extra_test.go @@ -753,3 +753,70 @@ func TestSetPredicateBytesInExtra(t *testing.T) { }) } } + +func TestPredicateBytesExtra(t *testing.T) { + tests := []struct { + name string + rules extras.AvalancheRules + extra []byte + predicate []byte + wantExtraWithPredicate []byte + }{ + { + name: "empty_extra_predicate", + extra: nil, + predicate: nil, + wantExtraWithPredicate: make([]byte, ap3.WindowSize), + }, + { + name: "empty_extra_predicate_fortuna", + rules: extras.AvalancheRules{ + IsFortuna: true, + }, + extra: nil, + predicate: nil, + wantExtraWithPredicate: make([]byte, acp176.StateSize), + }, + { + name: "extra_too_short", + extra: []byte{ + 0: 1, + ap3.WindowSize - 1: 0, + }, + predicate: []byte{2}, + wantExtraWithPredicate: []byte{ + 0: 1, + ap3.WindowSize: 2, + }, + }, + { + name: "extra_too_short_fortuna", + rules: extras.AvalancheRules{ + IsFortuna: true, + }, + extra: []byte{ + 0: 1, + acp176.StateSize - 1: 0, + }, + predicate: []byte{2}, + wantExtraWithPredicate: []byte{ + 0: 1, + acp176.StateSize: 2, + }, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + var wantPredicate []byte + if test.predicate != nil { + wantPredicate = make([]byte, len(test.predicate)) + copy(wantPredicate, test.predicate) + } + + gotExtra := SetPredicateBytesInExtra(test.rules, test.extra, test.predicate) + require.Equal(t, test.wantExtraWithPredicate, gotExtra) + gotPredicate := PredicateBytesFromExtra(test.rules, gotExtra) + require.Equal(t, wantPredicate, gotPredicate) + }) + } +} diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 4b5948b1f2..ed93b95e89 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -807,9 +807,8 @@ func (vm *VM) preBatchOnFinalizeAndAssemble(header *types.Header, state *state.S // Note: snapshot is taken inside the loop because you cannot revert to the same snapshot more than // once. snapshot := state.Snapshot() - rules := vm.chainConfig.Rules(header.Number, params.IsMergeTODO, header.Time) - rulesExtra := params.GetRulesExtra(rules) - if err := vm.verifyTx(tx, header.ParentHash, header.BaseFee, state, *rulesExtra); err != nil { + rules := vm.rules(header.Number, header.Time) + if err := vm.verifyTx(tx, header.ParentHash, header.BaseFee, state, rules); err != nil { // Discard the transaction from the mempool on failed verification. log.Debug("discarding tx from mempool on failed verification", "txID", tx.ID(), "err", err) vm.mempool.DiscardCurrentTx(tx.ID()) @@ -826,8 +825,8 @@ func (vm *VM) preBatchOnFinalizeAndAssemble(header *types.Header, state *state.S return nil, nil, nil, fmt.Errorf("failed to marshal atomic transaction %s due to %w", tx.ID(), err) } var contribution, gasUsed *big.Int - if rulesExtra.IsApricotPhase4 { - contribution, gasUsed, err = tx.BlockFeeContribution(rulesExtra.IsApricotPhase5, vm.ctx.AVAXAssetID, header.BaseFee) + if rules.IsApricotPhase4 { + contribution, gasUsed, err = tx.BlockFeeContribution(rules.IsApricotPhase5, vm.ctx.AVAXAssetID, header.BaseFee) if err != nil { return nil, nil, nil, err } @@ -855,8 +854,7 @@ func (vm *VM) postBatchOnFinalizeAndAssemble( batchAtomicUTXOs set.Set[ids.ID] batchContribution *big.Int = new(big.Int).Set(common.Big0) batchGasUsed *big.Int = new(big.Int).Set(common.Big0) - rules = vm.chainConfig.Rules(header.Number, params.IsMergeTODO, header.Time) - rulesExtra = *params.GetRulesExtra(rules) + rules = vm.rules(header.Number, header.Time) size int ) @@ -910,7 +908,7 @@ func (vm *VM) postBatchOnFinalizeAndAssemble( } snapshot := state.Snapshot() - if err := vm.verifyTx(tx, header.ParentHash, header.BaseFee, state, rulesExtra); err != nil { + if err := vm.verifyTx(tx, header.ParentHash, header.BaseFee, state, rules); err != nil { // Discard the transaction from the mempool and reset the state to [snapshot] // if it fails verification here. // Note: prior to this point, we have not modified [state] so there is no need to @@ -972,11 +970,10 @@ func (vm *VM) onExtraStateChange(block *types.Block, parent *types.Header, state batchContribution *big.Int = big.NewInt(0) batchGasUsed *big.Int = big.NewInt(0) header = block.Header() - rules = vm.chainConfig.Rules(header.Number, params.IsMergeTODO, header.Time) - rulesExtra = *params.GetRulesExtra(rules) + rules = vm.rules(header.Number, header.Time) ) - txs, err := atomic.ExtractAtomicTxs(customtypes.BlockExtData(block), rulesExtra.IsApricotPhase5, atomic.Codec) + txs, err := atomic.ExtractAtomicTxs(customtypes.BlockExtData(block), rules.IsApricotPhase5, atomic.Codec) if err != nil { return nil, nil, err } @@ -987,7 +984,7 @@ func (vm *VM) onExtraStateChange(block *types.Block, parent *types.Header, state log.Info("skipping atomic tx verification on bonus block", "block", block.Hash()) } else { // Verify [txs] do not conflict with themselves or ancestor blocks. - if err := vm.verifyTxs(txs, block.ParentHash(), block.BaseFee(), block.NumberU64(), rulesExtra); err != nil { + if err := vm.verifyTxs(txs, block.ParentHash(), block.BaseFee(), block.NumberU64(), rules); err != nil { return nil, nil, err } } @@ -1011,8 +1008,8 @@ func (vm *VM) onExtraStateChange(block *types.Block, parent *types.Header, state return nil, nil, err } // If ApricotPhase4 is enabled, calculate the block fee contribution - if rulesExtra.IsApricotPhase4 { - contribution, gasUsed, err := tx.BlockFeeContribution(rulesExtra.IsApricotPhase5, vm.ctx.AVAXAssetID, block.BaseFee()) + if rules.IsApricotPhase4 { + contribution, gasUsed, err := tx.BlockFeeContribution(rules.IsApricotPhase5, vm.ctx.AVAXAssetID, block.BaseFee()) if err != nil { return nil, nil, err } @@ -1024,7 +1021,7 @@ func (vm *VM) onExtraStateChange(block *types.Block, parent *types.Header, state // If ApricotPhase5 is enabled, enforce that the atomic gas used does not exceed the // atomic gas limit. - if rulesExtra.IsApricotPhase5 { + if rules.IsApricotPhase5 { atomicGasLimit, err := customheader.RemainingAtomicGasCapacity(vm.chainConfigExtra(), parent, header) if err != nil { return nil, nil, err @@ -1748,11 +1745,15 @@ func (vm *VM) chainConfigExtra() *extras.ChainConfig { return params.GetExtra(vm.chainConfig) } +func (vm *VM) rules(number *big.Int, time uint64) extras.Rules { + ethrules := vm.chainConfig.Rules(number, params.IsMergeTODO, time) + return *params.GetRulesExtra(ethrules) +} + // currentRules returns the chain rules for the current block. func (vm *VM) currentRules() extras.Rules { header := vm.eth.APIBackend.CurrentHeader() - rules := vm.chainConfig.Rules(header.Number, params.IsMergeTODO, header.Time) - return *params.GetRulesExtra(rules) + return vm.rules(header.Number, header.Time) } // requirePrimaryNetworkSigners returns true if warp messages from the primary diff --git a/plugin/evm/vm_test.go b/plugin/evm/vm_test.go index a5612b3ea0..4cd681aeff 100644 --- a/plugin/evm/vm_test.go +++ b/plugin/evm/vm_test.go @@ -5,7 +5,6 @@ package evm import ( "context" - "crypto/rand" "encoding/json" "errors" "fmt" @@ -1378,10 +1377,7 @@ func TestSetPreferenceRace(t *testing.T) { } func TestConflictingTransitiveAncestryWithGap(t *testing.T) { - key, err := utils.NewKey(rand.Reader) - if err != nil { - t.Fatal(err) - } + key := utils.NewKey(t) key0 := testKeys[0] addr0 := key0.Address() @@ -3591,10 +3587,7 @@ func TestAtomicTxBuildBlockDropsConflicts(t *testing.T) { testShortIDAddrs[1]: importAmount, testShortIDAddrs[2]: importAmount, }) - conflictKey, err := utils.NewKey(rand.Reader) - if err != nil { - t.Fatal(err) - } + conflictKey := utils.NewKey(t) defer func() { if err := vm.Shutdown(context.Background()); err != nil { t.Fatal(err) diff --git a/plugin/evm/vm_warp_test.go b/plugin/evm/vm_warp_test.go index b478ab147a..a6017bfd59 100644 --- a/plugin/evm/vm_warp_test.go +++ b/plugin/evm/vm_warp_test.go @@ -656,7 +656,6 @@ func testReceiveWarpMessage( ethBlock := block2.(*chain.BlockWrapper).Block.(*Block).ethBlock rules := params.GetExtra(vm.chainConfig).GetAvalancheRules(ethBlock.Time()) headerPredicateResultsBytes := customheader.PredicateBytesFromExtra(rules, ethBlock.Extra()) - require.NotEmpty(headerPredicateResultsBytes) results, err := predicate.ParseResults(headerPredicateResultsBytes) require.NoError(err) diff --git a/precompile/contract/interfaces.go b/precompile/contract/interfaces.go index db3da9f184..188c3a0933 100644 --- a/precompile/contract/interfaces.go +++ b/precompile/contract/interfaces.go @@ -15,21 +15,15 @@ import ( "github.com/holiman/uint256" ) -type Log = ethtypes.Log - // StatefulPrecompiledContract is the interface for executing a precompiled contract type StatefulPrecompiledContract interface { // Run executes the precompiled contract. Run(accessibleState AccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) } -type StateReader interface { - GetState(common.Address, common.Hash) common.Hash -} - // StateDB is the interface for accessing EVM state type StateDB interface { - StateReader + GetState(common.Address, common.Hash) common.Hash SetState(common.Address, common.Hash, common.Hash) SetNonce(common.Address, uint64) @@ -44,8 +38,8 @@ type StateDB interface { CreateAccount(common.Address) Exist(common.Address) bool - AddLog(*Log) - GetLogData() (topics [][]common.Hash, data [][]byte) + AddLog(*ethtypes.Log) + Logs() []*ethtypes.Log GetPredicateStorageSlots(address common.Address, index int) ([]byte, bool) SetPredicateStorageSlots(address common.Address, predicates [][]byte) diff --git a/precompile/contract/mocks.go b/precompile/contract/mocks.go index 812dc2d23f..3964bdb55a 100644 --- a/precompile/contract/mocks.go +++ b/precompile/contract/mocks.go @@ -16,6 +16,7 @@ import ( snow "github.com/ava-labs/avalanchego/snow" precompileconfig "github.com/ava-labs/coreth/precompile/precompileconfig" common "github.com/ava-labs/libevm/common" + types "github.com/ava-labs/libevm/core/types" vm "github.com/ava-labs/libevm/core/vm" uint256 "github.com/holiman/uint256" gomock "go.uber.org/mock/gomock" @@ -70,7 +71,7 @@ func (mr *MockStateDBMockRecorder) AddBalanceMultiCoin(arg0, arg1, arg2 any) *go } // AddLog mocks base method. -func (m *MockStateDB) AddLog(arg0 *Log) { +func (m *MockStateDB) AddLog(arg0 *types.Log) { m.ctrl.T.Helper() m.ctrl.Call(m, "AddLog", arg0) } @@ -135,21 +136,6 @@ func (mr *MockStateDBMockRecorder) GetBalanceMultiCoin(arg0, arg1 any) *gomock.C return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBalanceMultiCoin", reflect.TypeOf((*MockStateDB)(nil).GetBalanceMultiCoin), arg0, arg1) } -// GetLogData mocks base method. -func (m *MockStateDB) GetLogData() ([][]common.Hash, [][]byte) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetLogData") - ret0, _ := ret[0].([][]common.Hash) - ret1, _ := ret[1].([][]byte) - return ret0, ret1 -} - -// GetLogData indicates an expected call of GetLogData. -func (mr *MockStateDBMockRecorder) GetLogData() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLogData", reflect.TypeOf((*MockStateDB)(nil).GetLogData)) -} - // GetNonce mocks base method. func (m *MockStateDB) GetNonce(arg0 common.Address) uint64 { m.ctrl.T.Helper() @@ -207,6 +193,20 @@ func (mr *MockStateDBMockRecorder) GetTxHash() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTxHash", reflect.TypeOf((*MockStateDB)(nil).GetTxHash)) } +// Logs mocks base method. +func (m *MockStateDB) Logs() []*types.Log { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Logs") + ret0, _ := ret[0].([]*types.Log) + return ret0 +} + +// Logs indicates an expected call of Logs. +func (mr *MockStateDBMockRecorder) Logs() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Logs", reflect.TypeOf((*MockStateDB)(nil).Logs)) +} + // RevertToSnapshot mocks base method. func (m *MockStateDB) RevertToSnapshot(arg0 int) { m.ctrl.T.Helper() diff --git a/precompile/contracts/warp/config.go b/precompile/contracts/warp/config.go index 495eeb62e2..07d86c763f 100644 --- a/precompile/contracts/warp/config.go +++ b/precompile/contracts/warp/config.go @@ -84,7 +84,7 @@ func NewDisableConfig(blockTimestamp *uint64) *Config { func (*Config) Key() string { return ConfigKey } // Verify tries to verify Config and returns an error accordingly. -func (c Config) Verify(chainConfig precompileconfig.ChainConfig) error { +func (c *Config) Verify(chainConfig precompileconfig.ChainConfig) error { if c.Timestamp() != nil { // If Warp attempts to activate before Durango, fail verification timestamp := *c.Timestamp() diff --git a/precompile/contracts/warp/contract.go b/precompile/contracts/warp/contract.go index 59e81f341e..bfedbe10c3 100644 --- a/precompile/contracts/warp/contract.go +++ b/precompile/contracts/warp/contract.go @@ -11,6 +11,7 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" "github.com/ava-labs/coreth/accounts/abi" "github.com/ava-labs/coreth/precompile/contract" + "github.com/ava-labs/libevm/core/types" _ "embed" @@ -280,7 +281,7 @@ func sendWarpMessage(accessibleState contract.AccessibleState, caller common.Add if err != nil { return nil, remainingGas, err } - accessibleState.GetStateDB().AddLog(&contract.Log{ + accessibleState.GetStateDB().AddLog(&types.Log{ Address: ContractAddress, Topics: topics, Data: data, diff --git a/precompile/contracts/warp/contract_test.go b/precompile/contracts/warp/contract_test.go index 1ceed2321b..1a248bd05a 100644 --- a/precompile/contracts/warp/contract_test.go +++ b/precompile/contracts/warp/contract_test.go @@ -11,7 +11,6 @@ import ( "github.com/ava-labs/avalanchego/ids" agoUtils "github.com/ava-labs/avalanchego/utils" "github.com/ava-labs/avalanchego/utils/set" - "github.com/ava-labs/avalanchego/vms/platformvm/warp" avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" "github.com/ava-labs/coreth/core/extstate" @@ -147,7 +146,12 @@ func TestSendWarpMessage(t *testing.T) { return bytes }(), AfterHook: func(t testing.TB, state contract.StateDB) { - logsTopics, logsData := state.GetLogData() + var logsTopics [][]common.Hash + var logsData [][]byte + for _, log := range state.Logs() { + logsTopics = append(logsTopics, log.Topics) + logsData = append(logsData, common.CopyBytes(log.Data)) + } require.Len(t, logsTopics, 1) topics := logsTopics[0] require.Len(t, topics, 3) @@ -183,9 +187,9 @@ func TestGetVerifiedWarpMessage(t *testing.T) { packagedPayloadBytes, ) require.NoError(t, err) - unsignedWarpMsg, err := warp.NewUnsignedMessage(networkID, sourceChainID, addressedPayload.Bytes()) + unsignedWarpMsg, err := avalancheWarp.NewUnsignedMessage(networkID, sourceChainID, addressedPayload.Bytes()) require.NoError(t, err) - warpMessage, err := warp.NewMessage(unsignedWarpMsg, &warp.BitSetSignature{}) // Create message with empty signature for testing + warpMessage, err := avalancheWarp.NewMessage(unsignedWarpMsg, &avalancheWarp.BitSetSignature{}) // Create message with empty signature for testing require.NoError(t, err) warpMessagePredicateBytes := predicate.PackPredicate(warpMessage.Bytes()) getVerifiedWarpMsg, err := PackGetVerifiedWarpMessage(0) @@ -407,9 +411,9 @@ func TestGetVerifiedWarpMessage(t *testing.T) { Caller: callerAddr, InputFn: func(t testing.TB) []byte { return getVerifiedWarpMsg }, BeforeHook: func(t testing.TB, state contract.StateDB) { - unsignedMessage, err := warp.NewUnsignedMessage(networkID, sourceChainID, []byte{1, 2, 3}) // Invalid addressed payload + unsignedMessage, err := avalancheWarp.NewUnsignedMessage(networkID, sourceChainID, []byte{1, 2, 3}) // Invalid addressed payload require.NoError(t, err) - warpMessage, err := warp.NewMessage(unsignedMessage, &warp.BitSetSignature{}) + warpMessage, err := avalancheWarp.NewMessage(unsignedMessage, &avalancheWarp.BitSetSignature{}) require.NoError(t, err) state.SetPredicateStorageSlots(ContractAddress, [][]byte{predicate.PackPredicate(warpMessage.Bytes())}) @@ -464,9 +468,9 @@ func TestGetVerifiedWarpBlockHash(t *testing.T) { blockHash := ids.GenerateTestID() blockHashPayload, err := payload.NewHash(blockHash) require.NoError(t, err) - unsignedWarpMsg, err := warp.NewUnsignedMessage(networkID, sourceChainID, blockHashPayload.Bytes()) + unsignedWarpMsg, err := avalancheWarp.NewUnsignedMessage(networkID, sourceChainID, blockHashPayload.Bytes()) require.NoError(t, err) - warpMessage, err := warp.NewMessage(unsignedWarpMsg, &warp.BitSetSignature{}) // Create message with empty signature for testing + warpMessage, err := avalancheWarp.NewMessage(unsignedWarpMsg, &avalancheWarp.BitSetSignature{}) // Create message with empty signature for testing require.NoError(t, err) warpMessagePredicateBytes := predicate.PackPredicate(warpMessage.Bytes()) getVerifiedWarpBlockHash, err := PackGetVerifiedWarpBlockHash(0) @@ -685,9 +689,9 @@ func TestGetVerifiedWarpBlockHash(t *testing.T) { Caller: callerAddr, InputFn: func(t testing.TB) []byte { return getVerifiedWarpBlockHash }, BeforeHook: func(t testing.TB, state contract.StateDB) { - unsignedMessage, err := warp.NewUnsignedMessage(networkID, sourceChainID, []byte{1, 2, 3}) // Invalid block hash payload + unsignedMessage, err := avalancheWarp.NewUnsignedMessage(networkID, sourceChainID, []byte{1, 2, 3}) // Invalid block hash payload require.NoError(t, err) - warpMessage, err := warp.NewMessage(unsignedMessage, &warp.BitSetSignature{}) + warpMessage, err := avalancheWarp.NewMessage(unsignedMessage, &avalancheWarp.BitSetSignature{}) require.NoError(t, err) state.SetPredicateStorageSlots(ContractAddress, [][]byte{predicate.PackPredicate(warpMessage.Bytes())}) diff --git a/precompile/contracts/warp/contract_warp_handler.go b/precompile/contracts/warp/contract_warp_handler.go index 1154e0a4fc..d96f47b65a 100644 --- a/precompile/contracts/warp/contract_warp_handler.go +++ b/precompile/contracts/warp/contract_warp_handler.go @@ -61,8 +61,8 @@ func handleWarpMessage(accessibleState contract.AccessibleState, input []byte, s warpIndex := int(warpIndexInput) // This conversion is safe even if int is 32 bits because we checked above. state := accessibleState.GetStateDB() predicateBytes, exists := state.GetPredicateStorageSlots(ContractAddress, warpIndex) - result := accessibleState.GetBlockContext().GetPredicateResults(state.GetTxHash(), ContractAddress) - valid := exists && !set.BitsFromBytes(result).Contains(warpIndex) + predicateResults := accessibleState.GetBlockContext().GetPredicateResults(state.GetTxHash(), ContractAddress) + valid := exists && !set.BitsFromBytes(predicateResults).Contains(warpIndex) if !valid { return handler.packFailed(), remainingGas, nil } diff --git a/predicate/predicate_bytes.go b/predicate/predicate_bytes.go index f1baa1a610..9d5766b4f3 100644 --- a/predicate/predicate_bytes.go +++ b/predicate/predicate_bytes.go @@ -9,10 +9,6 @@ import ( "github.com/ava-labs/libevm/common" ) -// HeaderFeeWindowSize is defined in the predicate package to avoid a circular dependency. -// After Durango, the extra data past the dynamic fee rollup window represents predicate results. -const HeaderFeeWindowSize = 80 - // EndByte is used as a delimiter for the bytes packed into a precompile predicate. // Precompile predicates are encoded in the Access List of transactions in the access tuples // which means that its length must be a multiple of 32 (common.HashLength). diff --git a/predicate/predicate_results.go b/predicate/predicate_results.go index a79417329c..2d8eeea5ca 100644 --- a/predicate/predicate_results.go +++ b/predicate/predicate_results.go @@ -45,11 +45,11 @@ type Results struct { } func (r Results) GetPredicateResults(txHash common.Hash, address common.Address) []byte { - tx, ok := r.Results[txHash] + results, ok := r.Results[txHash] if !ok { return nil } - return tx[address] + return results[address] } // NewResults returns an empty predicate results. diff --git a/predicate/predicate_slots.go b/predicate/predicate_slots.go index 10ecd0d179..6b9f0e2286 100644 --- a/predicate/predicate_slots.go +++ b/predicate/predicate_slots.go @@ -9,7 +9,7 @@ import ( "github.com/ava-labs/libevm/core/types" ) -type predicaters interface { +type PredicaterExistChecker interface { PredicaterExists(common.Address) bool } @@ -17,7 +17,7 @@ type predicaters interface { // Note: if an address is specified multiple times in the access list, each storage slot for that address is // appended to a slice of byte slices. Each byte slice represents a predicate, making it a slice of predicates // for each access list address, and every predicate in the slice goes through verification. -func PreparePredicateStorageSlots(rules predicaters, list types.AccessList) map[common.Address][][]byte { +func PreparePredicateStorageSlots(rules PredicaterExistChecker, list types.AccessList) map[common.Address][][]byte { predicateStorageSlots := make(map[common.Address][][]byte) for _, el := range list { if !rules.PredicaterExists(el.Address) { diff --git a/rpc/metrics.go b/rpc/metrics.go index bb694de1a3..ee6f1f8f42 100644 --- a/rpc/metrics.go +++ b/rpc/metrics.go @@ -38,10 +38,10 @@ import ( // ====== If resolving merge conflicts ====== // -// All calls to metrics.NewRegistered*() have been replaced with -// metrics.GetOrRegister*() and this package's corresponding libevm package -// imported above. Together these ensure that the metric here is the same as the -// one with the same name in libevm. +// All calls to metrics.NewRegistered*() for metrics also defined in libevm/rpc have +// been replaced with metrics.GetOrRegister*() to get metrics already registered in +// libevm/rpc or register them here otherwise. These replacements ensure the same +// metrics are shared between the two packages. var ( rpcRequestGauge = metrics.GetOrRegisterGauge("rpc/requests", nil) successfulRequestGauge = metrics.GetOrRegisterGauge("rpc/success", nil) diff --git a/sync/syncutils/test_trie.go b/sync/syncutils/test_trie.go index e2f3e57f99..587d3c95e3 100644 --- a/sync/syncutils/test_trie.go +++ b/sync/syncutils/test_trie.go @@ -4,7 +4,6 @@ package syncutils import ( - cryptoRand "crypto/rand" "encoding/binary" "math/rand" "testing" @@ -176,10 +175,7 @@ func FillAccounts( t.Fatalf("failed to rlp encode account: %v", err) } - key, err := utils.NewKey(cryptoRand.Reader) - if err != nil { - t.Fatal(err) - } + key := utils.NewKey(t) tr.MustUpdate(key.Address[:], accBytes) accounts[key] = &acc } diff --git a/triedb/hashdb/database.go b/triedb/hashdb/database.go index 977a88ba88..37947aac89 100644 --- a/triedb/hashdb/database.go +++ b/triedb/hashdb/database.go @@ -57,10 +57,10 @@ const ( // ====== If resolving merge conflicts ====== // -// All calls to metrics.NewRegistered*() have been replaced with -// metrics.GetOrRegister*() and this package's corresponding libevm package -// imported above. Together these ensure that the metric here is the same as the -// one with the same name in libevm. +// All calls to metrics.NewRegistered*() for metrics also defined in libevm/triedb/hashdb +// have been replaced with metrics.GetOrRegister*() to get metrics already registered in +// libevm/triedb/hashdb or register them here otherwise. These replacements ensure the same +// metrics are shared between the two packages. var ( memcacheCleanHitMeter = metrics.GetOrRegisterMeter("hashdb/memcache/clean/hit", nil) memcacheCleanMissMeter = metrics.GetOrRegisterMeter("hashdb/memcache/clean/miss", nil) diff --git a/triedb/pathdb/metrics.go b/triedb/pathdb/metrics.go index b09e9884d7..fbc37c786b 100644 --- a/triedb/pathdb/metrics.go +++ b/triedb/pathdb/metrics.go @@ -35,11 +35,12 @@ import ( // ====== If resolving merge conflicts ====== // -// All calls to metrics.NewRegistered*() have been replaced with -// metrics.GetOrRegister*() and this package's corresponding libevm package -// imported above. Together these ensure that the metric here is the same as the -// one with the same name in libevm. -// nolint: unused +// All calls to metrics.NewRegistered*() for metrics also defined in libevm/triedb/pathdb +// have been replaced with metrics.GetOrRegister*() to get metrics already registered in +// libevm/triedb/pathdb or register them here otherwise. These replacements ensure the same +// metrics are shared between the two packages. +// +//nolint:unused var ( cleanHitMeter = metrics.GetOrRegisterMeter("pathdb/clean/hit", nil) cleanMissMeter = metrics.GetOrRegisterMeter("pathdb/clean/miss", nil) diff --git a/utils/key.go b/utils/key.go index ab4db85b94..cc4efa6751 100644 --- a/utils/key.go +++ b/utils/key.go @@ -1,30 +1,30 @@ -// (c) 2021-2022, Ava Labs, Inc. All rights reserved. +// (c) 2024, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. package utils import ( "crypto/ecdsa" - "io" + "crypto/rand" + "testing" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/crypto" + "github.com/stretchr/testify/require" ) +// Key contains an ecdsa private key field as well as an address field +// obtained from converting the ecdsa public key. type Key struct { Address common.Address PrivateKey *ecdsa.PrivateKey } -func NewKey(rand io.Reader) (*Key, error) { - privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand) - if err != nil { - return nil, err - } - return NewKeyFromECDSA(privateKeyECDSA), nil -} - -func NewKeyFromECDSA(privateKeyECDSA *ecdsa.PrivateKey) *Key { +// NewKey generates a new key pair and returns a pointer to a [Key]. +func NewKey(t *testing.T) *Key { + t.Helper() + privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand.Reader) + require.NoError(t, err) return &Key{ Address: crypto.PubkeyToAddress(privateKeyECDSA.PublicKey), PrivateKey: privateKeyECDSA,