From 5399f493b9910e168b38aca4defcb02caf37ed5e Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Fri, 21 Jan 2022 15:24:47 -0600 Subject: [PATCH 1/2] Track total balance delta in StateDB --- core/state/statedb.go | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index e3541339eaa5..a6c0cb1bd519 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -38,6 +38,8 @@ import ( type revision struct { id int journalIndex int + // Arbitrum: track the total balance change across all accounts + totalBalanceDelta *big.Int } var ( @@ -62,6 +64,9 @@ func (n *proofList) Delete(key []byte) error { // * Contracts // * Accounts type StateDB struct { + // Arbitrum: track the total balance change across all accounts + totalBalanceDelta *big.Int + db Database prefetcher *triePrefetcher originalRoot common.Hash // The pre-state root, before any changes were made @@ -131,6 +136,7 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) return nil, err } sdb := &StateDB{ + totalBalanceDelta: new(big.Int), db: db, trie: tr, originalRoot: root, @@ -378,6 +384,7 @@ func (s *StateDB) HasSuicided(addr common.Address) bool { func (s *StateDB) AddBalance(addr common.Address, amount *big.Int) { stateObject := s.GetOrNewStateObject(addr) if stateObject != nil { + s.totalBalanceDelta.Add(s.totalBalanceDelta, amount) stateObject.AddBalance(amount) } } @@ -386,6 +393,7 @@ func (s *StateDB) AddBalance(addr common.Address, amount *big.Int) { func (s *StateDB) SubBalance(addr common.Address, amount *big.Int) { stateObject := s.GetOrNewStateObject(addr) if stateObject != nil { + s.totalBalanceDelta.Sub(s.totalBalanceDelta, amount) stateObject.SubBalance(amount) } } @@ -393,6 +401,10 @@ func (s *StateDB) SubBalance(addr common.Address, amount *big.Int) { func (s *StateDB) SetBalance(addr common.Address, amount *big.Int) { stateObject := s.GetOrNewStateObject(addr) if stateObject != nil { + prevBalance := stateObject.Balance() + s.totalBalanceDelta.Add(s.totalBalanceDelta, amount) + s.totalBalanceDelta.Sub(s.totalBalanceDelta, prevBalance) + stateObject.SetBalance(amount) } } @@ -443,6 +455,7 @@ func (s *StateDB) Suicide(addr common.Address) bool { prevbalance: new(big.Int).Set(stateObject.Balance()), }) stateObject.markSuicided() + s.totalBalanceDelta.Sub(s.totalBalanceDelta, stateObject.data.Balance) stateObject.data.Balance = new(big.Int) return true @@ -647,6 +660,7 @@ func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common func (s *StateDB) Copy() *StateDB { // Copy all the basic fields, initialize the memory ones state := &StateDB{ + totalBalanceDelta: new(big.Int).Set(s.totalBalanceDelta), db: s.db, trie: s.db.CopyTrie(s.trie), stateObjects: make(map[common.Address]*stateObject, len(s.journal.dirties)), @@ -746,7 +760,7 @@ func (s *StateDB) Copy() *StateDB { func (s *StateDB) Snapshot() int { id := s.nextRevisionId s.nextRevisionId++ - s.validRevisions = append(s.validRevisions, revision{id, s.journal.length()}) + s.validRevisions = append(s.validRevisions, revision{id, s.journal.length(), new(big.Int).Set(s.totalBalanceDelta)}) return id } @@ -759,7 +773,9 @@ func (s *StateDB) RevertToSnapshot(revid int) { if idx == len(s.validRevisions) || s.validRevisions[idx].id != revid { panic(fmt.Errorf("revision id %v cannot be reverted", revid)) } - snapshot := s.validRevisions[idx].journalIndex + revision := s.validRevisions[idx] + snapshot := revision.journalIndex + s.totalBalanceDelta = new(big.Int).Set(revision.totalBalanceDelta) // Replay the journal to undo changes and remove invalidated snapshots s.journal.revert(s, snapshot) @@ -771,6 +787,11 @@ func (s *StateDB) GetRefund() uint64 { return s.refund } +// GetTotalBalanceDelta returns the total change in balances since the last commit to the database +func (s *StateDB) GetTotalBalanceDelta() *big.Int { + return new(big.Int).Set(s.totalBalanceDelta) +} + // Finalise finalises the state by removing the s destructed objects and clears // the journal as well as the refunds. Finalise, however, will not push any updates // into the tries just yet. Only IntermediateRoot or Commit will do that. @@ -982,6 +1003,9 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { } s.snap, s.snapDestructs, s.snapAccounts, s.snapStorage = nil, nil, nil, nil } + if err == nil { + s.totalBalanceDelta.Set(new(big.Int)) + } return root, err } From 7e62cd0e10adf28c764ac467eb402750d9586e22 Mon Sep 17 00:00:00 2001 From: Lee Bousfield Date: Sat, 22 Jan 2022 12:56:38 -0600 Subject: [PATCH 2/2] Split EndTxHook success up into transition and evm success --- core/state_transition.go | 4 +++- core/vm/evm_arbitrum.go | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index f29592311ce7..a02ac01433e1 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -374,7 +374,9 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { } res, err := st.transitionDbImpl() + transitionSuccess := true if err != nil && !errors.Is(err, ErrNonceTooLow) && !errors.Is(err, ErrNonceTooHigh) { + transitionSuccess = false res = &ExecutionResult{ UsedGas: st.gasUsed(), Err: err, @@ -384,7 +386,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { } if err == nil { - st.evm.ProcessingHook.EndTxHook(st.gas, res.Err == nil) + st.evm.ProcessingHook.EndTxHook(st.gas, transitionSuccess, res.Err == nil) } return res, err } diff --git a/core/vm/evm_arbitrum.go b/core/vm/evm_arbitrum.go index 2b8d145ac5e4..565f62daa91f 100644 --- a/core/vm/evm_arbitrum.go +++ b/core/vm/evm_arbitrum.go @@ -28,7 +28,7 @@ func (evm *EVM) Depth() int { type TxProcessingHook interface { StartTxHook() (bool, uint64, error, []byte) // return 4-tuple rather than *struct to avoid an import cycle GasChargingHook(gasRemaining *uint64) error - EndTxHook(totalGasUsed uint64, success bool) + EndTxHook(totalGasUsed uint64, transitionSuccess bool, evmSuccess bool) NonrefundableGas() uint64 PushCaller(addr common.Address) PopCaller() @@ -46,7 +46,7 @@ func (p DefaultTxProcessor) GasChargingHook(gasRemaining *uint64) error { return nil } -func (p DefaultTxProcessor) EndTxHook(totalGasUsed uint64, success bool) { +func (p DefaultTxProcessor) EndTxHook(totalGasUsed uint64, transitionSuccess bool, evmSuccess bool) { return }