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.
This commit is contained in:
Matthieu Vachon 2024-02-05 12:01:21 -05:00
parent 8767058368
commit a46903cf0c
19 changed files with 95 additions and 88 deletions

View file

@ -318,15 +318,15 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
reward.Sub(reward, new(big.Int).SetUint64(ommer.Delta)) reward.Sub(reward, new(big.Int).SetUint64(ommer.Delta))
reward.Mul(reward, blockReward) reward.Mul(reward, blockReward)
reward.Div(reward, big.NewInt(8)) 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 // Apply withdrawals
for _, w := range pre.Env.Withdrawals { for _, w := range pre.Env.Withdrawals {
// Amount is in gwei, turn into wei // Amount is in gwei, turn into wei
amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei)) 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 // Commit block
root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber)) root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber))

View file

@ -358,7 +358,7 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.
// Convert amount from gwei to wei. // Convert amount from gwei to wei.
amount := new(uint256.Int).SetUint64(w.Amount) amount := new(uint256.Int).SetUint64(w.Amount)
amount = amount.Mul(amount, uint256.NewInt(params.GWei)) 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. // No block reward which is issued by consensus layer instead.
} }

View file

@ -589,10 +589,10 @@ func accumulateRewards(config *params.ChainConfig, stateDB *state.StateDB, heade
r.Sub(r, hNum) r.Sub(r, hNum)
r.Mul(r, blockReward) r.Mul(r, blockReward)
r.Div(r, u256_8) 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) r.Div(blockReward, u256_32)
reward.Add(reward, r) reward.Add(reward, r)
} }
stateDB.AddBalance(header.Coinbase, reward, false, state.BalanceIncreaseRewardMineBlock) stateDB.AddBalance(header.Coinbase, reward, state.BalanceIncreaseRewardMineBlock)
} }

View file

@ -81,7 +81,7 @@ func ApplyDAOHardFork(statedb *state.StateDB) {
// Move every DAO account and extra-balance account funds into the refund contract // Move every DAO account and extra-balance account funds into the refund contract
for _, addr := range params.DAODrainList() { 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) statedb.SetBalance(addr, new(uint256.Int), state.BalanceDecreaseDaoAccount)
} }
} }

View file

@ -194,7 +194,7 @@ type BlockchainLogger interface {
// `td` is the total difficulty prior to `block`. // `td` is the total difficulty prior to `block`.
OnBlockStart(block *types.Block, td *big.Int, finalized *types.Header, safe *types.Header, chainConfig *params.ChainConfig) OnBlockStart(block *types.Block, td *big.Int, finalized *types.Header, safe *types.Header, chainConfig *params.ChainConfig)
OnBlockEnd(err error) OnBlockEnd(err error)
OnGenesisBlock(genesis *types.Block, alloc GenesisAlloc) OnGenesisBlock(genesis *types.Block, alloc GenesisAlloc, chainConfig *params.ChainConfig)
OnBeaconBlockRootStart(root common.Hash) OnBeaconBlockRootStart(root common.Hash)
OnBeaconBlockRootEnd() 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") 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)
} }
} }

View file

@ -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 // 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) { func Transfer(db vm.StateDB, sender, recipient common.Address, amount *uint256.Int) {
db.SubBalance(sender, amount, state.BalanceChangeTransfer) db.SubBalance(sender, amount, state.BalanceChangeTransfer)
db.AddBalance(recipient, amount, false, state.BalanceChangeTransfer) db.AddBalance(recipient, amount, state.BalanceChangeTransfer)
} }

View file

@ -143,7 +143,7 @@ func (ga *GenesisAlloc) hash(isVerkle bool) (common.Hash, error) {
} }
for addr, account := range *ga { for addr, account := range *ga {
if account.Balance != nil { 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.SetCode(addr, account.Code)
statedb.SetNonce(addr, account.Nonce) statedb.SetNonce(addr, account.Nonce)
@ -166,7 +166,7 @@ func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhas
if account.Balance != nil { if account.Balance != nil {
// This is not actually logged via tracer because OnGenesisBlock // This is not actually logged via tracer because OnGenesisBlock
// already captures the allocations. // 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.SetCode(addr, account.Code)
statedb.SetNonce(addr, account.Nonce) statedb.SetNonce(addr, account.Nonce)

View file

@ -405,8 +405,8 @@ func (s *StateDB) HasSelfDestructed(addr common.Address) bool {
*/ */
// AddBalance adds amount to the account associated with addr. // AddBalance adds amount to the account associated with addr.
func (s *StateDB) AddBalance(addr common.Address, amount *uint256.Int, checkPrecompile bool, reason BalanceChangeReason) { func (s *StateDB) AddBalance(addr common.Address, amount *uint256.Int, reason BalanceChangeReason) {
stateObject := s.getOrNewStateObjectWithCheckPrecompiles(addr, checkPrecompile) stateObject := s.getOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
stateObject.AddBalance(amount, reason) 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. // getOrNewStateObject retrieves a state object or create a new state object if nil.
func (s *StateDB) getOrNewStateObject(addr common.Address) *stateObject { func (s *StateDB) getOrNewStateObject(addr common.Address) *stateObject {
return s.getOrNewStateObjectWithCheckPrecompiles(addr, false)
}
func (s *StateDB) getOrNewStateObjectWithCheckPrecompiles(addr common.Address, checkPrecompile bool) *stateObject {
stateObject := s.getStateObject(addr) stateObject := s.getStateObject(addr)
if stateObject == nil { if stateObject == nil {
stateObject, _ = s.createObject(addr, checkPrecompile) stateObject, _ = s.createObject(addr)
} }
return stateObject return stateObject
} }
// createObject creates a new state object. If there is an existing account with // 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. // 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! prev = s.getDeletedStateObject(addr) // Note, prev might have been deleted, we need that!
newobj = newObject(s, addr, nil) newobj = newObject(s, addr, nil)
if s.logger != nil { if s.logger != nil {
if checkPrecompile { s.logger.OnNewAccount(addr, prev != 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, prev != nil)
}
} else {
s.logger.OnNewAccount(addr, prev != nil)
}
} }
if prev == nil { if prev == nil {
s.journal.append(createObjectChange{account: &addr}) 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. // Carrying over the balance ensures that Ether doesn't disappear.
func (s *StateDB) CreateAccount(addr common.Address) { func (s *StateDB) CreateAccount(addr common.Address) {
newObj, prev := s.createObject(addr, false) newObj, prev := s.createObject(addr)
if prev != nil { if prev != nil {
newObj.setBalance(prev.data.Balance) newObj.setBalance(prev.data.Balance)
} }

View file

@ -55,7 +55,7 @@ func TestUpdateLeaks(t *testing.T) {
// Update it with some accounts // Update it with some accounts
for i := byte(0); i < 255; i++ { for i := byte(0); i < 255; i++ {
addr := common.BytesToAddress([]byte{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)) state.SetNonce(addr, uint64(42*i))
if i%2 == 0 { if i%2 == 0 {
state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i})) 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", name: "AddBalance",
fn: func(a testAction, s *StateDB) { 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), args: make([]int64, 1),
}, },
@ -535,7 +535,7 @@ func TestTouchDelete(t *testing.T) {
s.state, _ = New(root, s.state.db, s.state.snaps) s.state, _ = New(root, s.state.db, s.state.snaps)
snapshot := s.state.Snapshot() 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 { if len(s.state.journal.dirties) != 1 {
t.Fatal("expected one dirty state object") t.Fatal("expected one dirty state object")

View file

@ -461,7 +461,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
} else { } else {
fee := new(uint256.Int).SetUint64(st.gasUsed()) fee := new(uint256.Int).SetUint64(st.gasUsed())
fee.Mul(fee, effectiveTipU256) 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{ return &ExecutionResult{
@ -488,7 +488,7 @@ func (st *StateTransition) refundGas(refundQuotient uint64) uint64 {
// Return ETH for remaining gas, exchanged at the original rate. // Return ETH for remaining gas, exchanged at the original rate.
remaining := uint256.NewInt(st.gasRemaining) remaining := uint256.NewInt(st.gasRemaining)
remaining = remaining.Mul(remaining, uint256.MustFromBig(st.msg.GasPrice)) 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 { if st.evm.Config.Tracer != nil && st.gasRemaining > 0 {
st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, vm.GasChangeTxLeftOverReturned) st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, vm.GasChangeTxLeftOverReturned)

View file

@ -500,17 +500,17 @@ func TestOpenDrops(t *testing.T) {
// Create a blob pool out of the pre-seeded data // Create a blob pool out of the pre-seeded data
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) 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(gapper.PublicKey), uint256.NewInt(1000000), state.BalanceChangeUnspecified)
statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), uint256.NewInt(1000000), false, state.BalanceChangeUnspecified) statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), uint256.NewInt(1000000), state.BalanceChangeUnspecified)
statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), uint256.NewInt(1000000), false, state.BalanceChangeUnspecified) statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), uint256.NewInt(1000000), state.BalanceChangeUnspecified)
statedb.SetNonce(crypto.PubkeyToAddress(filler.PublicKey), 3) 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.SetNonce(crypto.PubkeyToAddress(overlapper.PublicKey), 2)
statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), uint256.NewInt(1000000), false, state.BalanceChangeUnspecified) statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), uint256.NewInt(1000000), state.BalanceChangeUnspecified)
statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), uint256.NewInt(1000000), false, state.BalanceChangeUnspecified) statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), uint256.NewInt(1000000), state.BalanceChangeUnspecified)
statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), uint256.NewInt(1000000), false, state.BalanceChangeUnspecified) statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), uint256.NewInt(1000000), state.BalanceChangeUnspecified)
statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), uint256.NewInt(1000000), false, state.BalanceChangeUnspecified) statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), uint256.NewInt(1000000), state.BalanceChangeUnspecified)
statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), uint256.NewInt(10000000), false, state.BalanceChangeUnspecified) statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), uint256.NewInt(10000000), state.BalanceChangeUnspecified)
statedb.Commit(0, true) statedb.Commit(0, true)
chain := &testBlockChain{ chain := &testBlockChain{
@ -625,7 +625,7 @@ func TestOpenIndex(t *testing.T) {
// Create a blob pool out of the pre-seeded data // Create a blob pool out of the pre-seeded data
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) 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) statedb.Commit(0, true)
chain := &testBlockChain{ chain := &testBlockChain{
@ -725,9 +725,9 @@ func TestOpenHeap(t *testing.T) {
// Create a blob pool out of the pre-seeded data // Create a blob pool out of the pre-seeded data
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) 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(addr1, uint256.NewInt(1_000_000_000), state.BalanceChangeUnspecified)
statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), false, state.BalanceChangeUnspecified) statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), state.BalanceChangeUnspecified)
statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), false, state.BalanceChangeUnspecified) statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), state.BalanceChangeUnspecified)
statedb.Commit(0, true) statedb.Commit(0, true)
chain := &testBlockChain{ chain := &testBlockChain{
@ -805,9 +805,9 @@ func TestOpenCap(t *testing.T) {
for _, datacap := range []uint64{2 * (txAvgSize + blobSize), 100 * (txAvgSize + blobSize)} { 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 // 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, _ := 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(addr1, uint256.NewInt(1_000_000_000), state.BalanceChangeUnspecified)
statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), false, state.BalanceChangeUnspecified) statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), state.BalanceChangeUnspecified)
statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), false, state.BalanceChangeUnspecified) statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), state.BalanceChangeUnspecified)
statedb.Commit(0, true) statedb.Commit(0, true)
chain := &testBlockChain{ chain := &testBlockChain{
@ -1198,7 +1198,7 @@ func TestAdd(t *testing.T) {
addrs[acc] = crypto.PubkeyToAddress(keys[acc].PublicKey) addrs[acc] = crypto.PubkeyToAddress(keys[acc].PublicKey)
// Seed the state database with this acocunt // 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) statedb.SetNonce(addrs[acc], seed.nonce)
// Sign the seed transactions and store them in the data store // Sign the seed transactions and store them in the data store

View file

@ -50,7 +50,7 @@ func fillPool(t testing.TB, pool *LegacyPool) {
nonExecutableTxs := types.Transactions{} nonExecutableTxs := types.Transactions{}
for i := 0; i < 384; i++ { for i := 0; i < 384; i++ {
key, _ := crypto.GenerateKey() 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 // Add executable ones
for j := 0; j < int(pool.config.AccountSlots); j++ { for j := 0; j < int(pool.config.AccountSlots); j++ {
executableTxs = append(executableTxs, pricedTransaction(uint64(j), 100000, big.NewInt(300), key)) 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 // Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops
{ {
key, _ := crypto.GenerateKey() 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{} futureTxs := types.Transactions{}
for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ { for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ {
futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 100000, big.NewInt(500), key)) 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 // Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops
{ {
key, _ := crypto.GenerateKey() 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{} futureTxs := types.Transactions{}
for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ { 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)) 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++ { for j := 0; j < int(pool.config.GlobalQueue); j++ {
futureTxs := types.Transactions{} futureTxs := types.Transactions{}
key, _ := crypto.GenerateKey() 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)) futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 21000, big.NewInt(500), key))
pool.addRemotesSync(futureTxs) pool.addRemotesSync(futureTxs)
} }
@ -191,7 +191,7 @@ func TestTransactionZAttack(t *testing.T) {
overDraftTxs := types.Transactions{} overDraftTxs := types.Transactions{}
{ {
key, _ := crypto.GenerateKey() 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++ { for j := 0; j < int(pool.config.GlobalSlots); j++ {
overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 600000000000, 21000, big.NewInt(500), key)) overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 600000000000, 21000, big.NewInt(500), key))
} }
@ -228,7 +228,7 @@ func BenchmarkFutureAttack(b *testing.B) {
fillPool(b, pool) fillPool(b, pool)
key, _ := crypto.GenerateKey() 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{} futureTxs := types.Transactions{}
for n := 0; n < b.N; n++ { for n := 0; n < b.N; n++ {

View file

@ -310,7 +310,7 @@ func TestStateChangeDuringReset(t *testing.T) {
func testAddBalance(pool *LegacyPool, addr common.Address, amount *big.Int) { func testAddBalance(pool *LegacyPool, addr common.Address, amount *big.Int) {
pool.mu.Lock() 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() pool.mu.Unlock()
} }
@ -471,7 +471,7 @@ func TestChainFork(t *testing.T) {
addr := crypto.PubkeyToAddress(key.PublicKey) addr := crypto.PubkeyToAddress(key.PublicKey)
resetState := func() { resetState := func() {
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) 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.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed))
<-pool.requestReset(nil, nil) <-pool.requestReset(nil, nil)
@ -500,7 +500,7 @@ func TestDoubleNonce(t *testing.T) {
addr := crypto.PubkeyToAddress(key.PublicKey) addr := crypto.PubkeyToAddress(key.PublicKey)
resetState := func() { resetState := func() {
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) 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.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed))
<-pool.requestReset(nil, nil) <-pool.requestReset(nil, nil)
@ -2663,7 +2663,7 @@ func BenchmarkMultiAccountBatchInsert(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
account := crypto.PubkeyToAddress(key.PublicKey) 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) tx := transaction(uint64(0), 100000, key)
batches[i] = tx batches[i] = tx
} }

View file

@ -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, // 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 // but is the correct thing to do and matters on other networks, in tests, and potential
// future scenarios // 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 { if p, isPrecompile := evm.precompile(addr); isPrecompile {
ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer)

View file

@ -835,7 +835,7 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
} }
beneficiary := scope.Stack.pop() beneficiary := scope.Stack.pop()
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) 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()) interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address())
if tracer := interpreter.evm.Config.Tracer; tracer != nil { if tracer := interpreter.evm.Config.Tracer; tracer != nil {
tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig()) 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() beneficiary := scope.Stack.pop()
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
interpreter.evm.StateDB.SubBalance(scope.Contract.Address(), balance, state.BalanceDecreaseSelfdestruct) 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()) interpreter.evm.StateDB.Selfdestruct6780(scope.Contract.Address())
if tracer := interpreter.evm.Config.Tracer; tracer != nil { if tracer := interpreter.evm.Config.Tracer; tracer != nil {
tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig()) tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig())

View file

@ -31,7 +31,7 @@ type StateDB interface {
CreateAccount(common.Address) CreateAccount(common.Address)
SubBalance(common.Address, *uint256.Int, state.BalanceChangeReason) 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 GetBalance(common.Address) *uint256.Int
GetNonce(common.Address) uint64 GetNonce(common.Address) uint64

View file

@ -64,13 +64,14 @@ type Firehose struct {
blockBaseFee *big.Int blockBaseFee *big.Int
blockOrdinal *Ordinal blockOrdinal *Ordinal
blockFinality *FinalityStatus blockFinality *FinalityStatus
blockRules params.Rules
// Transaction state // Transaction state
evm *vm.EVM evm *vm.EVM
transaction *pbeth.TransactionTrace transaction *pbeth.TransactionTrace
transactionLogIndex uint32 transactionLogIndex uint32
inSystemCall bool inSystemCall bool
isPrecompiledAddr func(addr common.Address) bool blockIsPrecompiledAddr func(addr common.Address) bool
// Call state // Call state
callStack *CallStack callStack *CallStack
@ -106,6 +107,8 @@ func (f *Firehose) resetBlock() {
f.blockBaseFee = nil f.blockBaseFee = nil
f.blockOrdinal.Reset() f.blockOrdinal.Reset()
f.blockFinality.Reset() f.blockFinality.Reset()
f.blockIsPrecompiledAddr = nil
f.blockRules = params.Rules{}
} }
// resetTransaction resets the transaction state and the call state in one shot // resetTransaction resets the transaction state and the call state in one shot
@ -114,7 +117,6 @@ func (f *Firehose) resetTransaction() {
f.evm = nil f.evm = nil
f.transactionLogIndex = 0 f.transactionLogIndex = 0
f.inSystemCall = false f.inSystemCall = false
f.isPrecompiledAddr = nil
f.callStack.Reset() f.callStack.Reset()
f.latestCallStartSuicided = false 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) { 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()) 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{ f.block = &pbeth.Block{
Hash: b.Hash().Bytes(), 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) 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) { func (f *Firehose) OnBlockEnd(err error) {
firehoseDebug("block ending err=%s", errorView(err)) 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() to = *tx.To()
} }
isBeforeHomestead := !evm.ChainConfig().IsHomestead(big.NewInt(int64(f.block.Number))) f.captureTxStart(tx, tx.Hash(), from, to)
f.captureTxStart(tx, tx.Hash(), from, to, evm.IsPrecompileAddr, isBeforeHomestead)
} }
// captureTxStart is used internally a two places, in the normal "tracer" and in the "OnGenesisBlock", // 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 // we manually pass some override to the `tx` because genesis block has a different way of creating
// the transaction that wraps the genesis block. // 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) { func (f *Firehose) captureTxStart(tx *types.Transaction, hash common.Hash, from, to common.Address) {
f.isPrecompiledAddr = isPrecompiledAddr
v, r, s := tx.RawSignatureValues() v, r, s := tx.RawSignatureValues()
var blobGas *uint64 var blobGas *uint64
@ -492,8 +505,7 @@ func (f *Firehose) callStart(source string, callType pbeth.CallType, from common
GasLimit: gas, GasLimit: gas,
} }
precompile := f.isPrecompiledAddr(common.BytesToAddress(call.Address)) call.ExecutedCode = f.getExecutedCode(f.evm, call)
call.ExecutedCode = getExecutedCode(f.evm, precompile, call)
// Known Firehose issue: The BeginOrdinal of the genesis block root call is never actually // Known Firehose issue: The BeginOrdinal of the genesis block root call is never actually
// incremented and it's always 0. // 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) 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 != nil && call.CallType == pbeth.CallType_CALL {
if !evm.StateDB.Exist(common.BytesToAddress(call.Address)) && 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) { (call.Value == nil || call.Value.Native().Sign() == 0) {
firehoseDebug("executed code IsSpuriousDragon callTyp=%s inputLength=%d", call.CallType.String(), len(call.Input) > 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 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 activeCall.KeccakPreimages[hex.EncodeToString(hash.Bytes())] = encodedData
} }
func (f *Firehose) OnGenesisBlock(b *types.Block, alloc core.GenesisAlloc) { func (f *Firehose) OnGenesisBlock(b *types.Block, alloc core.GenesisAlloc, chainConfig *params.ChainConfig) {
f.OnBlockStart(b, big.NewInt(0), nil, nil, nil) f.OnBlockStart(b, big.NewInt(0), nil, nil, chainConfig)
f.captureTxStart(types.NewTx(&types.LegacyTx{}), emptyCommonHash, emptyCommonAddress, emptyCommonAddress, func(common.Address) bool { return false }, false) f.captureTxStart(types.NewTx(&types.LegacyTx{}), emptyCommonHash, emptyCommonAddress, emptyCommonAddress)
f.CaptureStart(emptyCommonAddress, emptyCommonAddress, false, nil, 0, nil) f.CaptureStart(emptyCommonAddress, emptyCommonAddress, false, nil, 0, nil)
for _, addr := range sortedKeys(alloc) { 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. // exists in the past. For now, do nothing and keep the legacy behavior.
_ = previousDataExists _ = 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{ accountCreation := &pbeth.AccountCreation{
Account: a.Bytes(), Account: a.Bytes(),
Ordinal: f.blockOrdinal.Next(), Ordinal: f.blockOrdinal.Next(),

View file

@ -96,7 +96,7 @@ func (p *Printer) OnBlockEnd(err error) {
fmt.Printf("OnBlockEnd: err=%v\n", err) 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)) fmt.Printf("OnGenesisBlock: b=%v, allocLength=%d\n", b.NumberU64(), len(alloc))
} }

View file

@ -316,7 +316,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
// - the coinbase self-destructed, or // - the coinbase self-destructed, or
// - there are only 'bad' transactions, which aren't executed. In those cases, // - 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 // 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. // Commit state mutations into database.
root, _ := statedb.Commit(block.NumberU64(), config.IsEIP158(block.Number())) root, _ := statedb.Commit(block.NumberU64(), config.IsEIP158(block.Number()))