Skip to content

Commit

Permalink
Capture balance reason (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
maoueh authored Jul 26, 2023
1 parent 4370527 commit 5466fa3
Show file tree
Hide file tree
Showing 33 changed files with 142 additions and 112 deletions.
2 changes: 1 addition & 1 deletion accounts/abi/bind/backends/simulated.go
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM

// Set infinite balance to the fake caller account.
from := stateDB.GetOrNewStateObject(call.From)
from.SetBalance(math.MaxBig256)
from.SetBalance(math.MaxBig256, 0x0)

// Execute the call.
msg := &core.Message{
Expand Down
10 changes: 5 additions & 5 deletions cmd/evm/internal/t8ntool/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
)
evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig)

tracer.CaptureTxStart(tx)
tracer.CaptureTxStart(evm, tx)
// (ret []byte, usedGas uint64, failed bool, err error)
msgResult, err := core.ApplyMessage(evm, msg, gaspool)
if err != nil {
Expand Down Expand Up @@ -258,15 +258,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)
statedb.AddBalance(ommer.Address, reward, state.BalanceChangeRewardMineUncle)
}
statedb.AddBalance(pre.Env.Coinbase, minerReward)
statedb.AddBalance(pre.Env.Coinbase, minerReward, state.BalanceChangeRewardMineBlock)
}
// 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)
statedb.AddBalance(w.Address, amount, state.BalanceChangeWithdrawal)
}
// Commit block
root, err := statedb.Commit(chainConfig.IsEIP158(vmContext.BlockNumber))
Expand Down Expand Up @@ -299,7 +299,7 @@ func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB
for addr, a := range accounts {
statedb.SetCode(addr, a.Code)
statedb.SetNonce(addr, a.Nonce)
statedb.SetBalance(addr, a.Balance)
statedb.SetBalance(addr, a.Balance, state.BalanceChangeGenesisBalance)
for k, v := range a.Storage {
statedb.SetState(addr, k, v)
}
Expand Down
6 changes: 3 additions & 3 deletions consensus/beacon/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -340,17 +340,17 @@ func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.H
}

// Finalize implements consensus.Engine and processes withdrawals on top.
func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) {
func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, stateDB *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) {
if !beacon.IsPoSHeader(header) {
beacon.ethone.Finalize(chain, header, state, txs, uncles, nil)
beacon.ethone.Finalize(chain, header, stateDB, txs, uncles, nil)
return
}
// Withdrawals processing.
for _, w := range withdrawals {
// Convert amount from gwei to wei.
amount := new(big.Int).SetUint64(w.Amount)
amount = amount.Mul(amount, big.NewInt(params.GWei))
state.AddBalance(w.Address, amount)
stateDB.AddBalance(w.Address, amount, state.BalanceChangeWithdrawal)
}
// No block reward which is issued by consensus layer instead.
}
Expand Down
6 changes: 3 additions & 3 deletions consensus/ethash/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ var (
// AccumulateRewards credits the coinbase of the given block with the mining
// reward. The total reward consists of the static block reward and rewards for
// included uncles. The coinbase of each uncle block is also rewarded.
func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, uncles []*types.Header) {
func accumulateRewards(config *params.ChainConfig, stateDB *state.StateDB, header *types.Header, uncles []*types.Header) {
// Select the correct block reward based on chain progression
blockReward := FrontierBlockReward
if config.IsByzantium(header.Number) {
Expand All @@ -563,10 +563,10 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header
r.Sub(r, header.Number)
r.Mul(r, blockReward)
r.Div(r, big8)
state.AddBalance(uncle.Coinbase, r)
stateDB.AddBalance(uncle.Coinbase, r, state.BalanceChangeRewardMineUncle)

r.Div(blockReward, big32)
reward.Add(reward, r)
}
state.AddBalance(header.Coinbase, reward)
stateDB.AddBalance(header.Coinbase, reward, state.BalanceChangeRewardMineBlock)
}
4 changes: 2 additions & 2 deletions consensus/misc/dao.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
statedb.SetBalance(addr, new(big.Int))
statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr), state.BalanceChangeDaoRefundContract)
statedb.SetBalance(addr, new(big.Int), state.BalanceChangeDaoAdjustBalance)
}
}
5 changes: 3 additions & 2 deletions core/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
)
Expand Down Expand Up @@ -125,6 +126,6 @@ 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)
db.AddBalance(recipient, amount)
db.SubBalance(sender, amount, state.BalanceChangeTransfer)
db.AddBalance(recipient, amount, state.BalanceChangeTransfer)
}
4 changes: 2 additions & 2 deletions core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ func (ga *GenesisAlloc) deriveHash() (common.Hash, error) {
return common.Hash{}, err
}
for addr, account := range *ga {
statedb.AddBalance(addr, account.Balance)
statedb.AddBalance(addr, account.Balance, state.BalanceChangeGenesisBalance)
statedb.SetCode(addr, account.Code)
statedb.SetNonce(addr, account.Nonce)
for key, value := range account.Storage {
Expand All @@ -145,7 +145,7 @@ func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhas
return err
}
for addr, account := range *ga {
statedb.AddBalance(addr, account.Balance)
statedb.AddBalance(addr, account.Balance, state.BalanceChangeGenesisBalance)
statedb.SetCode(addr, account.Code)
statedb.SetNonce(addr, account.Nonce)
for key, value := range account.Storage {
Expand Down
2 changes: 1 addition & 1 deletion core/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func TestInvalidCliqueConfig(t *testing.T) {
block := DefaultGoerliGenesisBlock()
block.ExtraData = []byte{}
db := rawdb.NewMemoryDatabase()
if _, err := block.Commit(db, trie.NewDatabase(db)); err == nil {
if _, err := block.Commit(db, trie.NewDatabase(db), nil); err == nil {
t.Fatal("Expected error on invalid clique config")
}
}
Expand Down
2 changes: 1 addition & 1 deletion core/headerchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func TestHeaderInsertion(t *testing.T) {
db = rawdb.NewMemoryDatabase()
gspec = &Genesis{BaseFee: big.NewInt(params.InitialBaseFee), Config: params.AllEthashProtocolChanges}
)
gspec.Commit(db, trie.NewDatabase(db))
gspec.Commit(db, trie.NewDatabase(db), nil)
hc, err := NewHeaderChain(db, gspec.Config, ethash.NewFaker(), func() bool { return false })
if err != nil {
t.Fatal(err)
Expand Down
34 changes: 28 additions & 6 deletions core/state/state_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,28 @@ func (s Storage) Copy() Storage {
return cpy
}

// BalanceChangeReason is used to indicate the reason for a balance change, useful
// for tracing and reporting.
type BalanceChangeReason byte

const (
BalanceChangeUnspecified BalanceChangeReason = iota
BalanceChangeRewardMineUncle
BalanceChangeRewardMineBlock
BalanceChangeDaoRefundContract
BalanceChangeDaoAdjustBalance
BalanceChangeTransfer
BalanceChangeGenesisBalance
BalanceChangeGasBuy
BalanceChangeRewardTransactionFee
BalanceChangeGasRefund
BalanceChangeTouchAccount
BalanceChangeSuicideRefund
BalanceChangeSuicideWithdraw
BalanceChangeBurn
BalanceChangeWithdrawal
)

// stateObject represents an Ethereum account which is being modified.
//
// The usage pattern is as follows:
Expand Down Expand Up @@ -376,7 +398,7 @@ func (s *stateObject) commitTrie(db Database) (*trienode.NodeSet, error) {

// AddBalance adds amount to s's balance.
// It is used to add funds to the destination account of a transfer.
func (s *stateObject) AddBalance(amount *big.Int) {
func (s *stateObject) AddBalance(amount *big.Int, reason BalanceChangeReason) {
// EIP161: We must check emptiness for the objects such that the account
// clearing (0,0,0 objects) can take effect.
if amount.Sign() == 0 {
Expand All @@ -385,25 +407,25 @@ func (s *stateObject) AddBalance(amount *big.Int) {
}
return
}
s.SetBalance(new(big.Int).Add(s.Balance(), amount))
s.SetBalance(new(big.Int).Add(s.Balance(), amount), reason)
}

// SubBalance removes amount from s's balance.
// It is used to remove funds from the origin account of a transfer.
func (s *stateObject) SubBalance(amount *big.Int) {
func (s *stateObject) SubBalance(amount *big.Int, reason BalanceChangeReason) {
if amount.Sign() == 0 {
return
}
s.SetBalance(new(big.Int).Sub(s.Balance(), amount))
s.SetBalance(new(big.Int).Sub(s.Balance(), amount), reason)
}

func (s *stateObject) SetBalance(amount *big.Int) {
func (s *stateObject) SetBalance(amount *big.Int, reason BalanceChangeReason) {
s.db.journal.append(balanceChange{
account: &s.address,
prev: new(big.Int).Set(s.data.Balance),
})
if s.db.logger != nil {
s.db.logger.OnBalanceChange(s.address, s.Balance(), amount)
s.db.logger.OnBalanceChange(s.address, s.Balance(), amount, reason)
}
s.setBalance(amount)
}
Expand Down
14 changes: 7 additions & 7 deletions core/state/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ func TestDump(t *testing.T) {

// generate a few entries
obj1 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01}))
obj1.AddBalance(big.NewInt(22))
obj1.AddBalance(big.NewInt(22), 0x0)
obj2 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02}))
obj2.SetCode(crypto.Keccak256Hash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3})
obj3 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x02}))
obj3.SetBalance(big.NewInt(44))
obj3.SetBalance(big.NewInt(44), 0x0)

// write some of them to the trie
s.state.updateStateObject(obj1)
Expand Down Expand Up @@ -100,13 +100,13 @@ func TestIterativeDump(t *testing.T) {

// generate a few entries
obj1 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01}))
obj1.AddBalance(big.NewInt(22))
obj1.AddBalance(big.NewInt(22), 0x0)
obj2 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02}))
obj2.SetCode(crypto.Keccak256Hash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3})
obj3 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x02}))
obj3.SetBalance(big.NewInt(44))
obj3.SetBalance(big.NewInt(44), 0x0)
obj4 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x00}))
obj4.AddBalance(big.NewInt(1337))
obj4.AddBalance(big.NewInt(1337), 0x0)

// write some of them to the trie
s.state.updateStateObject(obj1)
Expand Down Expand Up @@ -201,7 +201,7 @@ func TestSnapshot2(t *testing.T) {

// db, trie are already non-empty values
so0 := state.getStateObject(stateobjaddr0)
so0.SetBalance(big.NewInt(42))
so0.SetBalance(big.NewInt(42), 0x0)
so0.SetNonce(43)
so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'})
so0.suicided = false
Expand All @@ -213,7 +213,7 @@ func TestSnapshot2(t *testing.T) {

// and one with deleted == true
so1 := state.getStateObject(stateobjaddr1)
so1.SetBalance(big.NewInt(52))
so1.SetBalance(big.NewInt(52), 0x0)
so1.SetNonce(53)
so1.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e', '2'}), []byte{'c', 'a', 'f', 'e', '2'})
so1.suicided = true
Expand Down
14 changes: 7 additions & 7 deletions core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func (n *proofList) Delete(key []byte) error {
// Note that reference types are actual VM data structures; make copies
// if you need to retain them beyond the current call.
type StateLogger interface {
OnBalanceChange(addr common.Address, prev, new *big.Int)
OnBalanceChange(addr common.Address, prev, new *big.Int, reason BalanceChangeReason)
OnNonceChange(addr common.Address, prev, new uint64)
OnCodeChange(addr common.Address, prevCodeHash common.Hash, prevCode []byte, codeHash common.Hash, code []byte)
OnStorageChange(addr common.Address, slot common.Hash, prev, new common.Hash)
Expand Down Expand Up @@ -417,25 +417,25 @@ func (s *StateDB) HasSuicided(addr common.Address) bool {
*/

// AddBalance adds amount to the account associated with addr.
func (s *StateDB) AddBalance(addr common.Address, amount *big.Int) {
func (s *StateDB) AddBalance(addr common.Address, amount *big.Int, reason BalanceChangeReason) {
stateObject := s.GetOrNewStateObject(addr)
if stateObject != nil {
stateObject.AddBalance(amount)
stateObject.AddBalance(amount, reason)
}
}

// SubBalance subtracts amount from the account associated with addr.
func (s *StateDB) SubBalance(addr common.Address, amount *big.Int) {
func (s *StateDB) SubBalance(addr common.Address, amount *big.Int, reason BalanceChangeReason) {
stateObject := s.GetOrNewStateObject(addr)
if stateObject != nil {
stateObject.SubBalance(amount)
stateObject.SubBalance(amount, reason)
}
}

func (s *StateDB) SetBalance(addr common.Address, amount *big.Int) {
func (s *StateDB) SetBalance(addr common.Address, amount *big.Int, reason BalanceChangeReason) {
stateObject := s.GetOrNewStateObject(addr)
if stateObject != nil {
stateObject.SetBalance(amount)
stateObject.SetBalance(amount, reason)
}
}

Expand Down
Loading

0 comments on commit 5466fa3

Please sign in to comment.