diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index c2ef09721eda..151cf21a62de 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -317,15 +317,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, reward, state.BalanceIncreaseRewardMineUncle) + statedb.AddBalance(ommer.Address, reward, false, state.BalanceIncreaseRewardMineUncle) } - statedb.AddBalance(pre.Env.Coinbase, minerReward, state.BalanceIncreaseRewardMineBlock) + statedb.AddBalance(pre.Env.Coinbase, minerReward, false, 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, amount, state.BalanceIncreaseWithdrawal) + statedb.AddBalance(w.Address, amount, false, 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 9ab9026fa8e2..2bd12fda7ecc 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -357,7 +357,7 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types. // Convert amount from gwei to wei. amount := new(big.Int).SetUint64(w.Amount) amount = amount.Mul(amount, big.NewInt(params.GWei)) - stateDB.AddBalance(w.Address, amount, state.BalanceIncreaseWithdrawal) + stateDB.AddBalance(w.Address, amount, false, 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 17346384e1c0..62cd4fbd6e3f 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -586,10 +586,10 @@ func accumulateRewards(config *params.ChainConfig, stateDB *state.StateDB, heade r.Sub(r, header.Number) r.Mul(r, blockReward) r.Div(r, big8) - stateDB.AddBalance(uncle.Coinbase, r, state.BalanceIncreaseRewardMineUncle) + stateDB.AddBalance(uncle.Coinbase, r, false, state.BalanceIncreaseRewardMineUncle) r.Div(blockReward, big32) reward.Add(reward, r) } - stateDB.AddBalance(header.Coinbase, reward, state.BalanceIncreaseRewardMineBlock) + stateDB.AddBalance(header.Coinbase, reward, false, state.BalanceIncreaseRewardMineBlock) } diff --git a/consensus/misc/dao.go b/consensus/misc/dao.go index bc393a9cbced..919497385a3f 100644 --- a/consensus/misc/dao.go +++ b/consensus/misc/dao.go @@ -80,7 +80,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), state.BalanceIncreaseDaoContract) + statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr), false, state.BalanceIncreaseDaoContract) statedb.SetBalance(addr, new(big.Int), state.BalanceDecreaseDaoAccount) } } diff --git a/core/evm.go b/core/evm.go index 8b724ac2cfe2..cd2da5898763 100644 --- a/core/evm.go +++ b/core/evm.go @@ -137,5 +137,5 @@ func CanTransfer(db vm.StateDB, addr common.Address, amount *big.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 *big.Int) { db.SubBalance(sender, amount, state.BalanceChangeTransfer) - db.AddBalance(recipient, amount, state.BalanceChangeTransfer) + db.AddBalance(recipient, amount, false, state.BalanceChangeTransfer) } diff --git a/core/genesis.go b/core/genesis.go index b28d403b222c..a281c4ed4fd4 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -142,7 +142,7 @@ func (ga *GenesisAlloc) hash(isVerkle bool) (common.Hash, error) { } for addr, account := range *ga { if account.Balance != nil { - statedb.AddBalance(addr, account.Balance, state.BalanceIncreaseGenesisBalance) + statedb.AddBalance(addr, account.Balance, false, state.BalanceIncreaseGenesisBalance) } statedb.SetCode(addr, account.Code) statedb.SetNonce(addr, account.Nonce) @@ -165,7 +165,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, account.Balance, state.BalanceIncreaseGenesisBalance) + statedb.AddBalance(addr, account.Balance, false, 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 847812fe89a6..f159944d4dd2 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -402,8 +402,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 *big.Int, reason BalanceChangeReason) { - stateObject := s.GetOrNewStateObject(addr) +func (s *StateDB) AddBalance(addr common.Address, amount *big.Int, checkPrecompile bool, reason BalanceChangeReason) { + stateObject := s.getOrNewStateObject(addr, checkPrecompile) if stateObject != nil { stateObject.AddBalance(amount, reason) } @@ -652,27 +652,24 @@ 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.getOrNewStateObject(addr, false) +} + +func (s *StateDB) getOrNewStateObject(addr common.Address, checkPrecompile bool) *stateObject { stateObject := s.getStateObject(addr) if stateObject == nil { - stateObject, _ = s.createObject(addr) + stateObject, _ = s.createObject(addr, checkPrecompile) } return stateObject } // createObject creates a new state object. If there is an existing account with // the given address, it is overwritten and returned as the second return value. -func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) { +func (s *StateDB) createObject(addr common.Address, checkPrecompile bool) (newobj, prev *stateObject) { prev = s.getDeletedStateObject(addr) // Note, prev might have been deleted, we need that! newobj = newObject(s, addr, nil) if prev == nil { s.journal.append(createObjectChange{account: &addr}) - if s.logger != nil { - // 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) - } - } } else { // The original account should be marked as destructed and all cached // account and storage data should be cleared as well. Note, it must @@ -701,6 +698,19 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) delete(s.accountsOrigin, prev.address) delete(s.storagesOrigin, prev.address) } + + 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) + } + } else { + s.logger.OnNewAccount(addr) + } + } + s.setStateObject(newobj) if prev != nil && !prev.deleted { return newobj, prev @@ -719,7 +729,7 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) // // Carrying over the balance ensures that Ether doesn't disappear. func (s *StateDB) CreateAccount(addr common.Address) { - newObj, prev := s.createObject(addr) + newObj, prev := s.createObject(addr, false) if prev != nil { newObj.setBalance(prev.data.Balance) } diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 74d862e16a0c..40446b610369 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -56,7 +56,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, big.NewInt(int64(11*i)), 0x0) + state.AddBalance(addr, big.NewInt(int64(11*i)), false, 0x0) 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})) @@ -273,7 +273,7 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction { { name: "AddBalance", fn: func(a testAction, s *StateDB) { - s.AddBalance(addr, big.NewInt(a.args[0]), 0x0) + s.AddBalance(addr, big.NewInt(a.args[0]), false, 0x0) }, args: make([]int64, 1), }, @@ -536,7 +536,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(big.Int), 0x0) + s.state.AddBalance(common.Address{}, new(big.Int), false, 0x0) 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 880e7f81fb6e..23b13ad40340 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -445,7 +445,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { } else { fee := new(big.Int).SetUint64(st.gasUsed()) fee.Mul(fee, effectiveTip) - st.state.AddBalance(st.evm.Context.Coinbase, fee, state.BalanceIncreaseRewardTransactionFee) + st.state.AddBalance(st.evm.Context.Coinbase, fee, false, state.BalanceIncreaseRewardTransactionFee) } return &ExecutionResult{ @@ -471,7 +471,7 @@ func (st *StateTransition) refundGas(refundQuotient uint64) uint64 { // Return ETH for remaining gas, exchanged at the original rate. remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gasRemaining), st.msg.GasPrice) - st.state.AddBalance(st.msg.From, remaining, state.BalanceIncreaseGasReturn) + st.state.AddBalance(st.msg.From, remaining, false, 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 570e1536f29b..a644772d6e1c 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -512,17 +512,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), big.NewInt(1000000), 0x0) - statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), big.NewInt(1000000), 0x0) - statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), big.NewInt(1000000), 0x0) + statedb.AddBalance(crypto.PubkeyToAddress(gapper.PublicKey), big.NewInt(1000000), false, 0x0) + statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), big.NewInt(1000000), false, 0x0) + statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), big.NewInt(1000000), false, 0x0) statedb.SetNonce(crypto.PubkeyToAddress(filler.PublicKey), 3) - statedb.AddBalance(crypto.PubkeyToAddress(overlapper.PublicKey), big.NewInt(1000000), 0x0) + statedb.AddBalance(crypto.PubkeyToAddress(overlapper.PublicKey), big.NewInt(1000000), false, 0x0) statedb.SetNonce(crypto.PubkeyToAddress(overlapper.PublicKey), 2) - statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), big.NewInt(1000000), 0x0) - statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), big.NewInt(1000000), 0x0) - statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), big.NewInt(1000000), 0x0) - statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), big.NewInt(1000000), 0x0) - statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), big.NewInt(10000000), 0x0) + statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), big.NewInt(1000000), false, 0x0) + statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), big.NewInt(1000000), false, 0x0) + statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), big.NewInt(1000000), false, 0x0) + statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), big.NewInt(1000000), false, 0x0) + statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), big.NewInt(10000000), false, 0x0) statedb.Commit(0, true) chain := &testBlockChain{ @@ -637,7 +637,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, big.NewInt(1_000_000_000), 0x0) + statedb.AddBalance(addr, big.NewInt(1_000_000_000), false, 0x0) statedb.Commit(0, true) chain := &testBlockChain{ @@ -737,9 +737,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, big.NewInt(1_000_000_000), 0x0) - statedb.AddBalance(addr2, big.NewInt(1_000_000_000), 0x0) - statedb.AddBalance(addr3, big.NewInt(1_000_000_000), 0x0) + statedb.AddBalance(addr1, big.NewInt(1_000_000_000), false, 0x0) + statedb.AddBalance(addr2, big.NewInt(1_000_000_000), false, 0x0) + statedb.AddBalance(addr3, big.NewInt(1_000_000_000), false, 0x0) statedb.Commit(0, true) chain := &testBlockChain{ @@ -817,9 +817,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, big.NewInt(1_000_000_000), 0x0) - statedb.AddBalance(addr2, big.NewInt(1_000_000_000), 0x0) - statedb.AddBalance(addr3, big.NewInt(1_000_000_000), 0x0) + statedb.AddBalance(addr1, big.NewInt(1_000_000_000), false, 0x0) + statedb.AddBalance(addr2, big.NewInt(1_000_000_000), false, 0x0) + statedb.AddBalance(addr3, big.NewInt(1_000_000_000), false, 0x0) statedb.Commit(0, true) chain := &testBlockChain{ @@ -1210,7 +1210,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(big.Int).SetUint64(seed.balance), 0x0) + statedb.AddBalance(addrs[acc], new(big.Int).SetUint64(seed.balance), false, 0x0) 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 a0e6addc1838..0ce944d0cb02 100644 --- a/core/txpool/legacypool/legacypool2_test.go +++ b/core/txpool/legacypool/legacypool2_test.go @@ -49,7 +49,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), big.NewInt(10000000000), 0x0) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(10000000000), false, 0x0) // Add executable ones for j := 0; j < int(pool.config.AccountSlots); j++ { executableTxs = append(executableTxs, pricedTransaction(uint64(j), 100000, big.NewInt(300), key)) @@ -91,7 +91,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), big.NewInt(100000000000), 0x0) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), false, 0x0) 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)) @@ -128,7 +128,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), big.NewInt(100000000000), 0x0) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), false, 0x0) 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)) @@ -182,7 +182,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), big.NewInt(100000000000), 0x0) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), false, 0x0) futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 21000, big.NewInt(500), key)) pool.addRemotesSync(futureTxs) } @@ -190,7 +190,7 @@ func TestTransactionZAttack(t *testing.T) { overDraftTxs := types.Transactions{} { key, _ := crypto.GenerateKey() - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), 0x0) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), false, 0x0) for j := 0; j < int(pool.config.GlobalSlots); j++ { overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 600000000000, 21000, big.NewInt(500), key)) } @@ -227,7 +227,7 @@ func BenchmarkFutureAttack(b *testing.B) { fillPool(b, pool) key, _ := crypto.GenerateKey() - pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), 0x0) + pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), false, 0x0) 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 fbb35f0ada01..0a3d33110c6e 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -309,7 +309,7 @@ func TestStateChangeDuringReset(t *testing.T) { func testAddBalance(pool *LegacyPool, addr common.Address, amount *big.Int) { pool.mu.Lock() - pool.currentState.AddBalance(addr, amount, 0x0) + pool.currentState.AddBalance(addr, amount, false, 0x0) pool.mu.Unlock() } @@ -470,7 +470,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, big.NewInt(100000000000000), 0x0) + statedb.AddBalance(addr, big.NewInt(100000000000000), false, 0x0) pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed)) <-pool.requestReset(nil, nil) @@ -499,7 +499,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, big.NewInt(100000000000000), 0x0) + statedb.AddBalance(addr, big.NewInt(100000000000000), false, 0x0) pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed)) <-pool.requestReset(nil, nil) @@ -2662,7 +2662,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, big.NewInt(1000000), 0x0) + pool.currentState.AddBalance(account, big.NewInt(1000000), false, 0x0) tx := transaction(uint64(0), 100000, key) batches[i] = tx } diff --git a/core/vm/evm.go b/core/vm/evm.go index 8755597c93fb..600a0a0803f3 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -375,7 +375,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, big0, state.BalanceChangeTouchAccount) + evm.StateDB.AddBalance(addr, big0, true, 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 b9c5b153b731..638a1006396b 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -855,7 +855,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, state.BalanceIncreaseSelfdestruct) + interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, false, 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) @@ -871,7 +871,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, state.BalanceIncreaseSelfdestruct) + interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, false, 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) diff --git a/core/vm/interface.go b/core/vm/interface.go index e96e4502fb10..c8555f82a041 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -30,7 +30,7 @@ type StateDB interface { CreateAccount(common.Address) SubBalance(common.Address, *big.Int, state.BalanceChangeReason) - AddBalance(common.Address, *big.Int, state.BalanceChangeReason) + AddBalance(common.Address, *big.Int, bool, state.BalanceChangeReason) GetBalance(common.Address) *big.Int GetNonce(common.Address) uint64 diff --git a/eth/tracers/firehose.go b/eth/tracers/firehose.go index 505c86e99f6f..2341dc67de15 100644 --- a/eth/tracers/firehose.go +++ b/eth/tracers/firehose.go @@ -64,6 +64,7 @@ type Firehose struct { blockFinality *FinalityStatus // Transaction state + evm *vm.EVM transaction *pbeth.TransactionTrace transactionLogIndex uint32 isPrecompiledAddr func(addr common.Address) bool @@ -109,6 +110,7 @@ func (f *Firehose) resetBlock() { // resetTransaction resets the transaction state and the call state in one shot func (f *Firehose) resetTransaction() { f.transaction = nil + f.evm = nil f.transactionLogIndex = 0 f.isPrecompiledAddr = nil @@ -175,6 +177,7 @@ func (f *Firehose) CaptureTxStart(evm *vm.EVM, tx *types.Transaction, from commo f.ensureInBlockAndNotInTrxAndNotInCall() + f.evm = evm var to common.Address if tx.To() == nil { to = crypto.CreateAddress(from, evm.StateDB.GetNonce(from)) @@ -409,9 +412,11 @@ func (f *Firehose) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope } func (f *Firehose) captureInterpreterStep(activeCall *pbeth.Call, pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, rData []byte, depth int, err error) { - if !activeCall.ExecutedCode { - firehoseTrace("setting active call executed code to true") - activeCall.ExecutedCode = true + // for call, we need to process the executed code here + // since in old firehose executed code calculation depends if the code exist + if activeCall.CallType == pbeth.CallType_CALL && !activeCall.ExecutedCode { + firehoseTrace("Intepreter step for callType_CALL") + activeCall.ExecutedCode = len(activeCall.Input) > 0 } } @@ -470,6 +475,9 @@ 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) + // Known Firehose issue: The BeginOrdinal of the genesis block root call is never actually // incremented and it's always 0. // @@ -496,6 +504,31 @@ 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 { + 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 && + (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 + } + } + + if precompile { + firehoseDebug("executed code isprecompile callTyp=%s inputLength=%d", call.CallType.String(), len(call.Input) > 0) + return call.CallType != pbeth.CallType_CREATE && len(call.Input) > 0 + } + + if call.CallType == pbeth.CallType_CALL { + firehoseDebug("executed code callType_CALL") + // calculation for executed code will happen in captureInterpreterStep + return false + } + + firehoseDebug("executed code default callTyp=%s inputLength=%d", call.CallType.String(), len(call.Input) > 0) + return call.CallType != pbeth.CallType_CREATE && len(call.Input) > 0 +} + func (f *Firehose) callEnd(source string, output []byte, gasUsed uint64, err error, reverted bool) { firehoseDebug("call end source=%s index=%d output=%s gasUsed=%d err=%s reverted=%t", source, f.callStack.ActiveIndex(), outputView(output), gasUsed, errorView(err), reverted) @@ -537,19 +570,19 @@ func (f *Firehose) callEnd(source string, output []byte, gasUsed uint64, err err // to false // // For precompiled address however, interpreter does not run so determine there was a bug in Firehose instrumentation where we would - if call.ExecutedCode || f.isPrecompiledAddr(common.BytesToAddress(call.Address)) { - // In this case, we are sure that some code executed. This translates in the old Firehose instrumentation - // that it would have **never** emitted an `account_without_code`. - // - // When no `account_without_code` was executed in the previous Firehose instrumentation, - // the `call.ExecutedCode` defaulted to the condition below - call.ExecutedCode = call.CallType != pbeth.CallType_CREATE && len(call.Input) > 0 - } else { - // In all other cases, we are sure that no code executed. This translates in the old Firehose instrumentation - // that it would have emitted an `account_without_code` and it would have then forced set the `call.ExecutedCode` - // to `false`. - call.ExecutedCode = false - } + // if call.ExecutedCode || f.isPrecompiledAddr(common.BytesToAddress(call.Address)) { + // // In this case, we are sure that some code executed. This translates in the old Firehose instrumentation + // // that it would have **never** emitted an `account_without_code`. + // // + // // When no `account_without_code` was executed in the previous Firehose instrumentation, + // // the `call.ExecutedCode` defaulted to the condition below + // call.ExecutedCode = call.CallType != pbeth.CallType_CREATE && len(call.Input) > 0 + // } else { + // // In all other cases, we are sure that no code executed. This translates in the old Firehose instrumentation + // // that it would have emitted an `account_without_code` and it would have then forced set the `call.ExecutedCode` + // // to `false`. + // call.ExecutedCode = false + // } if reverted { failureReason := "" @@ -805,10 +838,6 @@ func (f *Firehose) OnNewAccount(a common.Address) { return } - if f.isPrecompiledAddr(a) { - return - } - accountCreation := &pbeth.AccountCreation{ Account: a.Bytes(), Ordinal: f.blockOrdinal.Next(), diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 26dbf1abc0f1..c42acc9830ed 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -304,7 +304,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(big.Int), 0) + statedb.AddBalance(block.Coinbase(), new(big.Int), false, 0) // Commit state mutations into database. root, _ := statedb.Commit(block.NumberU64(), config.IsEIP158(block.Number()))