From a46903cf0cad829479ded66b369017914bf82314 Mon Sep 17 00:00:00 2001 From: Matthieu Vachon Date: Mon, 5 Feb 2024 12:01:21 -0500 Subject: [PATCH] Reduce amount of changes to Geth Live Tracer to keep Firehose backward compatibility We removed the `precompile` check on `OnNewAccount` and moved it to the Firehose tracer directly. This way, we can remove our custom logic that toggle the check at the tracing code level and we can instead move the logic of backward compatibility back `FirehoseTracer`. Refactored a bit also how precompiles are check. We moved the precompiles checker up to the block level now that `chainConfig` is available on `OnBlockStart` meaning we can extract the list of active precompiles. However, to make it work, we had to modify `OnGenesisBlock` to also receive `chainConfig` parameter, I've ask to add it to the geth codebase directly. --- cmd/evm/internal/t8ntool/execution.go | 6 +-- consensus/beacon/consensus.go | 2 +- consensus/ethash/consensus.go | 4 +- consensus/misc/dao.go | 2 +- core/blockchain.go | 4 +- core/evm.go | 2 +- core/genesis.go | 4 +- core/state/statedb.go | 24 +++------ core/state/statedb_test.go | 6 +-- core/state_transition.go | 4 +- core/txpool/blobpool/blobpool_test.go | 34 ++++++------- core/txpool/legacypool/legacypool2_test.go | 12 ++--- core/txpool/legacypool/legacypool_test.go | 8 +-- core/vm/evm.go | 2 +- core/vm/instructions.go | 4 +- core/vm/interface.go | 2 +- eth/tracers/firehose.go | 59 ++++++++++++++-------- eth/tracers/live/printer.go | 2 +- tests/state_test_util.go | 2 +- 19 files changed, 95 insertions(+), 88 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 2a48dd4579..18a4fb836c 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -318,15 +318,15 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, reward.Sub(reward, new(big.Int).SetUint64(ommer.Delta)) reward.Mul(reward, blockReward) reward.Div(reward, big.NewInt(8)) - statedb.AddBalance(ommer.Address, uint256.MustFromBig(reward), false, state.BalanceIncreaseRewardMineUncle) + statedb.AddBalance(ommer.Address, uint256.MustFromBig(reward), state.BalanceIncreaseRewardMineUncle) } - statedb.AddBalance(pre.Env.Coinbase, uint256.MustFromBig(minerReward), false, state.BalanceIncreaseRewardMineBlock) + statedb.AddBalance(pre.Env.Coinbase, uint256.MustFromBig(minerReward), state.BalanceIncreaseRewardMineBlock) } // Apply withdrawals for _, w := range pre.Env.Withdrawals { // Amount is in gwei, turn into wei amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei)) - statedb.AddBalance(w.Address, uint256.MustFromBig(amount), false, state.BalanceIncreaseWithdrawal) + statedb.AddBalance(w.Address, uint256.MustFromBig(amount), state.BalanceIncreaseWithdrawal) } // Commit block root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber)) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 7868aa50dd..9d84e7d934 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -358,7 +358,7 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types. // Convert amount from gwei to wei. amount := new(uint256.Int).SetUint64(w.Amount) amount = amount.Mul(amount, uint256.NewInt(params.GWei)) - stateDB.AddBalance(w.Address, amount, false, state.BalanceIncreaseWithdrawal) + stateDB.AddBalance(w.Address, amount, state.BalanceIncreaseWithdrawal) } // No block reward which is issued by consensus layer instead. } diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 3298273b11..d254ec38cf 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -589,10 +589,10 @@ func accumulateRewards(config *params.ChainConfig, stateDB *state.StateDB, heade r.Sub(r, hNum) r.Mul(r, blockReward) r.Div(r, u256_8) - stateDB.AddBalance(uncle.Coinbase, r, false, state.BalanceIncreaseRewardMineUncle) + stateDB.AddBalance(uncle.Coinbase, r, state.BalanceIncreaseRewardMineUncle) r.Div(blockReward, u256_32) reward.Add(reward, r) } - stateDB.AddBalance(header.Coinbase, reward, false, state.BalanceIncreaseRewardMineBlock) + stateDB.AddBalance(header.Coinbase, reward, state.BalanceIncreaseRewardMineBlock) } diff --git a/consensus/misc/dao.go b/consensus/misc/dao.go index ac1fc80872..803b577ea2 100644 --- a/consensus/misc/dao.go +++ b/consensus/misc/dao.go @@ -81,7 +81,7 @@ func ApplyDAOHardFork(statedb *state.StateDB) { // Move every DAO account and extra-balance account funds into the refund contract for _, addr := range params.DAODrainList() { - statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr), false, state.BalanceIncreaseDaoContract) + statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr), state.BalanceIncreaseDaoContract) statedb.SetBalance(addr, new(uint256.Int), state.BalanceDecreaseDaoAccount) } } diff --git a/core/blockchain.go b/core/blockchain.go index 180f74fc11..f6d40fe1c1 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -194,7 +194,7 @@ type BlockchainLogger interface { // `td` is the total difficulty prior to `block`. OnBlockStart(block *types.Block, td *big.Int, finalized *types.Header, safe *types.Header, chainConfig *params.ChainConfig) OnBlockEnd(err error) - OnGenesisBlock(genesis *types.Block, alloc GenesisAlloc) + OnGenesisBlock(genesis *types.Block, alloc GenesisAlloc, chainConfig *params.ChainConfig) OnBeaconBlockRootStart(root common.Hash) OnBeaconBlockRootEnd() } @@ -462,7 +462,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis return nil, fmt.Errorf("live blockchain tracer requires genesis alloc to be set") } - bc.logger.OnGenesisBlock(bc.genesisBlock, alloc) + bc.logger.OnGenesisBlock(bc.genesisBlock, alloc, bc.chainConfig) } } diff --git a/core/evm.go b/core/evm.go index 7244802c7d..1479a55780 100644 --- a/core/evm.go +++ b/core/evm.go @@ -138,5 +138,5 @@ func CanTransfer(db vm.StateDB, addr common.Address, amount *uint256.Int) bool { // Transfer subtracts amount from sender and adds amount to recipient using the given Db func Transfer(db vm.StateDB, sender, recipient common.Address, amount *uint256.Int) { db.SubBalance(sender, amount, state.BalanceChangeTransfer) - db.AddBalance(recipient, amount, false, state.BalanceChangeTransfer) + db.AddBalance(recipient, amount, state.BalanceChangeTransfer) } diff --git a/core/genesis.go b/core/genesis.go index 01c2fe7313..504251b445 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -143,7 +143,7 @@ func (ga *GenesisAlloc) hash(isVerkle bool) (common.Hash, error) { } for addr, account := range *ga { if account.Balance != nil { - statedb.AddBalance(addr, uint256.MustFromBig(account.Balance), false, state.BalanceIncreaseGenesisBalance) + statedb.AddBalance(addr, uint256.MustFromBig(account.Balance), state.BalanceIncreaseGenesisBalance) } statedb.SetCode(addr, account.Code) statedb.SetNonce(addr, account.Nonce) @@ -166,7 +166,7 @@ func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhas if account.Balance != nil { // This is not actually logged via tracer because OnGenesisBlock // already captures the allocations. - statedb.AddBalance(addr, uint256.MustFromBig(account.Balance), false, state.BalanceIncreaseGenesisBalance) + statedb.AddBalance(addr, uint256.MustFromBig(account.Balance), state.BalanceIncreaseGenesisBalance) } statedb.SetCode(addr, account.Code) statedb.SetNonce(addr, account.Nonce) diff --git a/core/state/statedb.go b/core/state/statedb.go index 3ac0e2330d..587a4bd477 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -405,8 +405,8 @@ func (s *StateDB) HasSelfDestructed(addr common.Address) bool { */ // AddBalance adds amount to the account associated with addr. -func (s *StateDB) AddBalance(addr common.Address, amount *uint256.Int, checkPrecompile bool, reason BalanceChangeReason) { - stateObject := s.getOrNewStateObjectWithCheckPrecompiles(addr, checkPrecompile) +func (s *StateDB) AddBalance(addr common.Address, amount *uint256.Int, reason BalanceChangeReason) { + stateObject := s.getOrNewStateObject(addr) if stateObject != nil { stateObject.AddBalance(amount, reason) } @@ -655,32 +655,20 @@ func (s *StateDB) setStateObject(object *stateObject) { // getOrNewStateObject retrieves a state object or create a new state object if nil. func (s *StateDB) getOrNewStateObject(addr common.Address) *stateObject { - return s.getOrNewStateObjectWithCheckPrecompiles(addr, false) -} - -func (s *StateDB) getOrNewStateObjectWithCheckPrecompiles(addr common.Address, checkPrecompile bool) *stateObject { stateObject := s.getStateObject(addr) if stateObject == nil { - stateObject, _ = s.createObject(addr, checkPrecompile) + stateObject, _ = s.createObject(addr) } return stateObject } // createObject creates a new state object. If there is an existing account with // the given address, it is overwritten and returned as the second return value. -func (s *StateDB) createObject(addr common.Address, checkPrecompile bool) (newobj, prev *stateObject) { +func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) { prev = s.getDeletedStateObject(addr) // Note, prev might have been deleted, we need that! newobj = newObject(s, addr, nil) if s.logger != nil { - if checkPrecompile { - // Precompiled contracts are touched during a call. - // Make sure we avoid emitting a new account event for them. - if _, ok := s.precompiles[addr]; !ok { - s.logger.OnNewAccount(addr, prev != nil) - } - } else { - s.logger.OnNewAccount(addr, prev != nil) - } + s.logger.OnNewAccount(addr, prev != nil) } if prev == nil { s.journal.append(createObjectChange{account: &addr}) @@ -731,7 +719,7 @@ func (s *StateDB) createObject(addr common.Address, checkPrecompile bool) (newob // // Carrying over the balance ensures that Ether doesn't disappear. func (s *StateDB) CreateAccount(addr common.Address) { - newObj, prev := s.createObject(addr, false) + newObj, prev := s.createObject(addr) if prev != nil { newObj.setBalance(prev.data.Balance) } diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 3fd558694d..2bb24acec8 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -55,7 +55,7 @@ func TestUpdateLeaks(t *testing.T) { // Update it with some accounts for i := byte(0); i < 255; i++ { addr := common.BytesToAddress([]byte{i}) - state.AddBalance(addr, uint256.NewInt(uint64(11*i)), false, BalanceChangeUnspecified) + state.AddBalance(addr, uint256.NewInt(uint64(11*i)), BalanceChangeUnspecified) state.SetNonce(addr, uint64(42*i)) if i%2 == 0 { state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i})) @@ -272,7 +272,7 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction { { name: "AddBalance", fn: func(a testAction, s *StateDB) { - s.AddBalance(addr, uint256.NewInt(uint64(a.args[0])), false, BalanceChangeUnspecified) + s.AddBalance(addr, uint256.NewInt(uint64(a.args[0])), BalanceChangeUnspecified) }, args: make([]int64, 1), }, @@ -535,7 +535,7 @@ func TestTouchDelete(t *testing.T) { s.state, _ = New(root, s.state.db, s.state.snaps) snapshot := s.state.Snapshot() - s.state.AddBalance(common.Address{}, new(uint256.Int), false, BalanceChangeUnspecified) + s.state.AddBalance(common.Address{}, new(uint256.Int), BalanceChangeUnspecified) if len(s.state.journal.dirties) != 1 { t.Fatal("expected one dirty state object") diff --git a/core/state_transition.go b/core/state_transition.go index 7b887816ed..5e3b018f82 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -461,7 +461,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { } else { fee := new(uint256.Int).SetUint64(st.gasUsed()) fee.Mul(fee, effectiveTipU256) - st.state.AddBalance(st.evm.Context.Coinbase, fee, false, state.BalanceIncreaseRewardTransactionFee) + st.state.AddBalance(st.evm.Context.Coinbase, fee, state.BalanceIncreaseRewardTransactionFee) } return &ExecutionResult{ @@ -488,7 +488,7 @@ func (st *StateTransition) refundGas(refundQuotient uint64) uint64 { // Return ETH for remaining gas, exchanged at the original rate. remaining := uint256.NewInt(st.gasRemaining) remaining = remaining.Mul(remaining, uint256.MustFromBig(st.msg.GasPrice)) - st.state.AddBalance(st.msg.From, remaining, false, state.BalanceIncreaseGasReturn) + st.state.AddBalance(st.msg.From, remaining, state.BalanceIncreaseGasReturn) if st.evm.Config.Tracer != nil && st.gasRemaining > 0 { st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, vm.GasChangeTxLeftOverReturned) diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index bf6bbb815b..c340a8c7ba 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -500,17 +500,17 @@ func TestOpenDrops(t *testing.T) { // Create a blob pool out of the pre-seeded data statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) - statedb.AddBalance(crypto.PubkeyToAddress(gapper.PublicKey), uint256.NewInt(1000000), false, state.BalanceChangeUnspecified) - statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), uint256.NewInt(1000000), false, state.BalanceChangeUnspecified) - statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), uint256.NewInt(1000000), false, state.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(gapper.PublicKey), uint256.NewInt(1000000), state.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), uint256.NewInt(1000000), state.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), uint256.NewInt(1000000), state.BalanceChangeUnspecified) statedb.SetNonce(crypto.PubkeyToAddress(filler.PublicKey), 3) - statedb.AddBalance(crypto.PubkeyToAddress(overlapper.PublicKey), uint256.NewInt(1000000), false, state.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(overlapper.PublicKey), uint256.NewInt(1000000), state.BalanceChangeUnspecified) statedb.SetNonce(crypto.PubkeyToAddress(overlapper.PublicKey), 2) - statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), uint256.NewInt(1000000), false, state.BalanceChangeUnspecified) - statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), uint256.NewInt(1000000), false, state.BalanceChangeUnspecified) - statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), uint256.NewInt(1000000), false, state.BalanceChangeUnspecified) - statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), uint256.NewInt(1000000), false, state.BalanceChangeUnspecified) - statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), uint256.NewInt(10000000), false, state.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), uint256.NewInt(1000000), state.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), uint256.NewInt(1000000), state.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), uint256.NewInt(1000000), state.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), uint256.NewInt(1000000), state.BalanceChangeUnspecified) + statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), uint256.NewInt(10000000), state.BalanceChangeUnspecified) statedb.Commit(0, true) chain := &testBlockChain{ @@ -625,7 +625,7 @@ func TestOpenIndex(t *testing.T) { // Create a blob pool out of the pre-seeded data statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) - statedb.AddBalance(addr, uint256.NewInt(1_000_000_000), false, state.BalanceChangeUnspecified) + statedb.AddBalance(addr, uint256.NewInt(1_000_000_000), state.BalanceChangeUnspecified) statedb.Commit(0, true) chain := &testBlockChain{ @@ -725,9 +725,9 @@ func TestOpenHeap(t *testing.T) { // Create a blob pool out of the pre-seeded data statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) - statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), false, state.BalanceChangeUnspecified) - statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), false, state.BalanceChangeUnspecified) - statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), false, state.BalanceChangeUnspecified) + statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), state.BalanceChangeUnspecified) + statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), state.BalanceChangeUnspecified) + statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), state.BalanceChangeUnspecified) statedb.Commit(0, true) chain := &testBlockChain{ @@ -805,9 +805,9 @@ func TestOpenCap(t *testing.T) { for _, datacap := range []uint64{2 * (txAvgSize + blobSize), 100 * (txAvgSize + blobSize)} { // Create a blob pool out of the pre-seeded data, but cap it to 2 blob transaction statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) - statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), false, state.BalanceChangeUnspecified) - statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), false, state.BalanceChangeUnspecified) - statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), false, state.BalanceChangeUnspecified) + statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), state.BalanceChangeUnspecified) + statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), state.BalanceChangeUnspecified) + statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), state.BalanceChangeUnspecified) statedb.Commit(0, true) chain := &testBlockChain{ @@ -1198,7 +1198,7 @@ func TestAdd(t *testing.T) { addrs[acc] = crypto.PubkeyToAddress(keys[acc].PublicKey) // Seed the state database with this acocunt - statedb.AddBalance(addrs[acc], new(uint256.Int).SetUint64(seed.balance), false, state.BalanceChangeUnspecified) + statedb.AddBalance(addrs[acc], new(uint256.Int).SetUint64(seed.balance), state.BalanceChangeUnspecified) statedb.SetNonce(addrs[acc], seed.nonce) // Sign the seed transactions and store them in the data store diff --git a/core/txpool/legacypool/legacypool2_test.go b/core/txpool/legacypool/legacypool2_test.go index e9eada23cc..0a31d625c1 100644 --- a/core/txpool/legacypool/legacypool2_test.go +++ b/core/txpool/legacypool/legacypool2_test.go @@ -50,7 +50,7 @@ func fillPool(t testing.TB, pool *LegacyPool) { nonExecutableTxs := types.Transactions{} for i := 0; i < 384; i++ { key, _ := crypto.GenerateKey() - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(10000000000), false, state.BalanceChangeUnspecified) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(10000000000), state.BalanceChangeUnspecified) // Add executable ones for j := 0; j < int(pool.config.AccountSlots); j++ { executableTxs = append(executableTxs, pricedTransaction(uint64(j), 100000, big.NewInt(300), key)) @@ -92,7 +92,7 @@ func TestTransactionFutureAttack(t *testing.T) { // Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops { key, _ := crypto.GenerateKey() - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), false, state.BalanceChangeUnspecified) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), state.BalanceChangeUnspecified) futureTxs := types.Transactions{} for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ { futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 100000, big.NewInt(500), key)) @@ -129,7 +129,7 @@ func TestTransactionFuture1559(t *testing.T) { // Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops { key, _ := crypto.GenerateKey() - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), false, state.BalanceChangeUnspecified) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), state.BalanceChangeUnspecified) futureTxs := types.Transactions{} for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ { futureTxs = append(futureTxs, dynamicFeeTx(1000+uint64(j), 100000, big.NewInt(200), big.NewInt(101), key)) @@ -183,7 +183,7 @@ func TestTransactionZAttack(t *testing.T) { for j := 0; j < int(pool.config.GlobalQueue); j++ { futureTxs := types.Transactions{} key, _ := crypto.GenerateKey() - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), false, state.BalanceChangeUnspecified) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), state.BalanceChangeUnspecified) futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 21000, big.NewInt(500), key)) pool.addRemotesSync(futureTxs) } @@ -191,7 +191,7 @@ func TestTransactionZAttack(t *testing.T) { overDraftTxs := types.Transactions{} { key, _ := crypto.GenerateKey() - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), false, state.BalanceChangeUnspecified) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), state.BalanceChangeUnspecified) for j := 0; j < int(pool.config.GlobalSlots); j++ { overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 600000000000, 21000, big.NewInt(500), key)) } @@ -228,7 +228,7 @@ func BenchmarkFutureAttack(b *testing.B) { fillPool(b, pool) key, _ := crypto.GenerateKey() - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), false, state.BalanceChangeUnspecified) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), state.BalanceChangeUnspecified) futureTxs := types.Transactions{} for n := 0; n < b.N; n++ { diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index e5156c91dc..56bf205927 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -310,7 +310,7 @@ func TestStateChangeDuringReset(t *testing.T) { func testAddBalance(pool *LegacyPool, addr common.Address, amount *big.Int) { pool.mu.Lock() - pool.currentState.AddBalance(addr, uint256.MustFromBig(amount), false, state.BalanceChangeUnspecified) + pool.currentState.AddBalance(addr, uint256.MustFromBig(amount), state.BalanceChangeUnspecified) pool.mu.Unlock() } @@ -471,7 +471,7 @@ func TestChainFork(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - statedb.AddBalance(addr, uint256.NewInt(100000000000000), false, state.BalanceChangeUnspecified) + statedb.AddBalance(addr, uint256.NewInt(100000000000000), state.BalanceChangeUnspecified) pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed)) <-pool.requestReset(nil, nil) @@ -500,7 +500,7 @@ func TestDoubleNonce(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - statedb.AddBalance(addr, uint256.NewInt(100000000000000), false, state.BalanceChangeUnspecified) + statedb.AddBalance(addr, uint256.NewInt(100000000000000), state.BalanceChangeUnspecified) pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed)) <-pool.requestReset(nil, nil) @@ -2663,7 +2663,7 @@ func BenchmarkMultiAccountBatchInsert(b *testing.B) { for i := 0; i < b.N; i++ { key, _ := crypto.GenerateKey() account := crypto.PubkeyToAddress(key.PublicKey) - pool.currentState.AddBalance(account, uint256.NewInt(1000000), false, state.BalanceChangeUnspecified) + pool.currentState.AddBalance(account, uint256.NewInt(1000000), state.BalanceChangeUnspecified) tx := transaction(uint64(0), 100000, key) batches[i] = tx } diff --git a/core/vm/evm.go b/core/vm/evm.go index c2173a75df..2c0b4e1e9f 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -374,7 +374,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte // This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium, // but is the correct thing to do and matters on other networks, in tests, and potential // future scenarios - evm.StateDB.AddBalance(addr, new(uint256.Int), true, state.BalanceChangeTouchAccount) + evm.StateDB.AddBalance(addr, new(uint256.Int), state.BalanceChangeTouchAccount) if p, isPrecompile := evm.precompile(addr); isPrecompile { ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 17385d89a9..31c9b18328 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -835,7 +835,7 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext } beneficiary := scope.Stack.pop() balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) - interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, false, state.BalanceIncreaseSelfdestruct) + interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, state.BalanceIncreaseSelfdestruct) interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address()) if tracer := interpreter.evm.Config.Tracer; tracer != nil { tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig()) @@ -851,7 +851,7 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon beneficiary := scope.Stack.pop() balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) interpreter.evm.StateDB.SubBalance(scope.Contract.Address(), balance, state.BalanceDecreaseSelfdestruct) - interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, false, state.BalanceIncreaseSelfdestruct) + interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, state.BalanceIncreaseSelfdestruct) interpreter.evm.StateDB.Selfdestruct6780(scope.Contract.Address()) if tracer := interpreter.evm.Config.Tracer; tracer != nil { tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig()) diff --git a/core/vm/interface.go b/core/vm/interface.go index 9fc3c4f35e..9d11bf3b72 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -31,7 +31,7 @@ type StateDB interface { CreateAccount(common.Address) SubBalance(common.Address, *uint256.Int, state.BalanceChangeReason) - AddBalance(common.Address, *uint256.Int, bool, state.BalanceChangeReason) + AddBalance(common.Address, *uint256.Int, state.BalanceChangeReason) GetBalance(common.Address) *uint256.Int GetNonce(common.Address) uint64 diff --git a/eth/tracers/firehose.go b/eth/tracers/firehose.go index 0c2821dd95..80e98dd1bf 100644 --- a/eth/tracers/firehose.go +++ b/eth/tracers/firehose.go @@ -64,13 +64,14 @@ type Firehose struct { blockBaseFee *big.Int blockOrdinal *Ordinal blockFinality *FinalityStatus + blockRules params.Rules // Transaction state - evm *vm.EVM - transaction *pbeth.TransactionTrace - transactionLogIndex uint32 - inSystemCall bool - isPrecompiledAddr func(addr common.Address) bool + evm *vm.EVM + transaction *pbeth.TransactionTrace + transactionLogIndex uint32 + inSystemCall bool + blockIsPrecompiledAddr func(addr common.Address) bool // Call state callStack *CallStack @@ -106,6 +107,8 @@ func (f *Firehose) resetBlock() { f.blockBaseFee = nil f.blockOrdinal.Reset() f.blockFinality.Reset() + f.blockIsPrecompiledAddr = nil + f.blockRules = params.Rules{} } // resetTransaction resets the transaction state and the call state in one shot @@ -114,7 +117,6 @@ func (f *Firehose) resetTransaction() { f.evm = nil f.transactionLogIndex = 0 f.inSystemCall = false - f.isPrecompiledAddr = nil f.callStack.Reset() f.latestCallStartSuicided = false @@ -124,7 +126,8 @@ func (f *Firehose) resetTransaction() { func (f *Firehose) OnBlockStart(b *types.Block, td *big.Int, finalized *types.Header, safe *types.Header, chainConfig *params.ChainConfig) { firehoseDebug("block start number=%d hash=%s", b.NumberU64(), b.Hash()) - f.ensureNotInBlock() + f.blockRules = chainConfig.Rules(b.Number(), chainConfig.TerminalTotalDifficultyPassed, b.Time()) + f.blockIsPrecompiledAddr = getActivePrecompilesChecker(f.blockRules) f.block = &pbeth.Block{ Hash: b.Hash().Bytes(), @@ -147,6 +150,20 @@ func (f *Firehose) OnBlockStart(b *types.Block, td *big.Int, finalized *types.He f.blockFinality.populateFromChain(finalized) } +func getActivePrecompilesChecker(rules params.Rules) func(addr common.Address) bool { + activePrecompiles := vm.ActivePrecompiles(rules) + + activePrecompilesMap := make(map[common.Address]bool, len(activePrecompiles)) + for _, addr := range activePrecompiles { + activePrecompilesMap[addr] = true + } + + return func(addr common.Address) bool { + _, found := activePrecompilesMap[addr] + return found + } +} + func (f *Firehose) OnBlockEnd(err error) { firehoseDebug("block ending err=%s", errorView(err)) @@ -194,17 +211,13 @@ func (f *Firehose) CaptureTxStart(evm *vm.EVM, tx *types.Transaction, from commo to = *tx.To() } - isBeforeHomestead := !evm.ChainConfig().IsHomestead(big.NewInt(int64(f.block.Number))) - - f.captureTxStart(tx, tx.Hash(), from, to, evm.IsPrecompileAddr, isBeforeHomestead) + f.captureTxStart(tx, tx.Hash(), from, to) } // captureTxStart is used internally a two places, in the normal "tracer" and in the "OnGenesisBlock", // we manually pass some override to the `tx` because genesis block has a different way of creating // the transaction that wraps the genesis block. -func (f *Firehose) captureTxStart(tx *types.Transaction, hash common.Hash, from, to common.Address, isPrecompiledAddr func(common.Address) bool, isBeforeHomestead bool) { - f.isPrecompiledAddr = isPrecompiledAddr - +func (f *Firehose) captureTxStart(tx *types.Transaction, hash common.Hash, from, to common.Address) { v, r, s := tx.RawSignatureValues() var blobGas *uint64 @@ -492,8 +505,7 @@ func (f *Firehose) callStart(source string, callType pbeth.CallType, from common GasLimit: gas, } - precompile := f.isPrecompiledAddr(common.BytesToAddress(call.Address)) - call.ExecutedCode = getExecutedCode(f.evm, precompile, call) + call.ExecutedCode = f.getExecutedCode(f.evm, call) // Known Firehose issue: The BeginOrdinal of the genesis block root call is never actually // incremented and it's always 0. @@ -521,10 +533,12 @@ func (f *Firehose) callStart(source string, callType pbeth.CallType, from common f.callStack.Push(call) } -func getExecutedCode(evm *vm.EVM, precompile bool, call *pbeth.Call) bool { +func (f *Firehose) getExecutedCode(evm *vm.EVM, call *pbeth.Call) bool { + precompile := f.blockIsPrecompiledAddr(common.BytesToAddress(call.Address)) + if evm != nil && call.CallType == pbeth.CallType_CALL { if !evm.StateDB.Exist(common.BytesToAddress(call.Address)) && - !precompile && evm.ChainConfig().Rules(evm.Context.BlockNumber, evm.Context.Random != nil, evm.Context.Time).IsEIP158 && + !precompile && f.blockRules.IsEIP158 && (call.Value == nil || call.Value.Native().Sign() == 0) { firehoseDebug("executed code IsSpuriousDragon callTyp=%s inputLength=%d", call.CallType.String(), len(call.Input) > 0) return call.CallType != pbeth.CallType_CREATE && len(call.Input) > 0 @@ -660,9 +674,9 @@ func (f *Firehose) CaptureKeccakPreimage(hash common.Hash, data []byte) { activeCall.KeccakPreimages[hex.EncodeToString(hash.Bytes())] = encodedData } -func (f *Firehose) OnGenesisBlock(b *types.Block, alloc core.GenesisAlloc) { - f.OnBlockStart(b, big.NewInt(0), nil, nil, nil) - f.captureTxStart(types.NewTx(&types.LegacyTx{}), emptyCommonHash, emptyCommonAddress, emptyCommonAddress, func(common.Address) bool { return false }, false) +func (f *Firehose) OnGenesisBlock(b *types.Block, alloc core.GenesisAlloc, chainConfig *params.ChainConfig) { + f.OnBlockStart(b, big.NewInt(0), nil, nil, chainConfig) + f.captureTxStart(types.NewTx(&types.LegacyTx{}), emptyCommonHash, emptyCommonAddress, emptyCommonAddress) f.CaptureStart(emptyCommonAddress, emptyCommonAddress, false, nil, 0, nil) for _, addr := range sortedKeys(alloc) { @@ -860,6 +874,11 @@ func (f *Firehose) OnNewAccount(a common.Address, previousDataExists bool) { // exists in the past. For now, do nothing and keep the legacy behavior. _ = previousDataExists + if call := f.callStack.Peek(); call != nil && call.CallType == pbeth.CallType_STATIC && f.blockIsPrecompiledAddr(common.Address(call.Address)) { + // Old Firehose ignore those, we do the same + return + } + accountCreation := &pbeth.AccountCreation{ Account: a.Bytes(), Ordinal: f.blockOrdinal.Next(), diff --git a/eth/tracers/live/printer.go b/eth/tracers/live/printer.go index c32635fea5..a959c0cac6 100644 --- a/eth/tracers/live/printer.go +++ b/eth/tracers/live/printer.go @@ -96,7 +96,7 @@ func (p *Printer) OnBlockEnd(err error) { fmt.Printf("OnBlockEnd: err=%v\n", err) } -func (p *Printer) OnGenesisBlock(b *types.Block, alloc core.GenesisAlloc) { +func (p *Printer) OnGenesisBlock(b *types.Block, alloc core.GenesisAlloc, chainConfig *params.ChainConfig) { fmt.Printf("OnGenesisBlock: b=%v, allocLength=%d\n", b.NumberU64(), len(alloc)) } diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 346072342a..cd34c9355e 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -316,7 +316,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh // - the coinbase self-destructed, or // - there are only 'bad' transactions, which aren't executed. In those cases, // the coinbase gets no txfee, so isn't created, and thus needs to be touched - statedb.AddBalance(block.Coinbase(), new(uint256.Int), false, state.BalanceChangeUnspecified) + statedb.AddBalance(block.Coinbase(), new(uint256.Int), state.BalanceChangeUnspecified) // Commit state mutations into database. root, _ := statedb.Commit(block.NumberU64(), config.IsEIP158(block.Number()))