github.com/palisadeinc/bor@v0.0.0-20230615125219-ab7196213d15/core/state/journal.go (about)

     1  // Copyright 2016 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package state
    18  
    19  import (
    20  	"math/big"
    21  
    22  	"github.com/ethereum/go-ethereum/common"
    23  	"github.com/ethereum/go-ethereum/core/blockstm"
    24  )
    25  
    26  // journalEntry is a modification entry in the state change journal that can be
    27  // reverted on demand.
    28  type journalEntry interface {
    29  	// revert undoes the changes introduced by this journal entry.
    30  	revert(*StateDB)
    31  
    32  	// dirtied returns the Ethereum address modified by this journal entry.
    33  	dirtied() *common.Address
    34  }
    35  
    36  // journal contains the list of state modifications applied since the last state
    37  // commit. These are tracked to be able to be reverted in the case of an execution
    38  // exception or request for reversal.
    39  type journal struct {
    40  	entries []journalEntry         // Current changes tracked by the journal
    41  	dirties map[common.Address]int // Dirty accounts and the number of changes
    42  }
    43  
    44  // newJournal creates a new initialized journal.
    45  func newJournal() *journal {
    46  	return &journal{
    47  		dirties: make(map[common.Address]int),
    48  	}
    49  }
    50  
    51  // append inserts a new modification entry to the end of the change journal.
    52  func (j *journal) append(entry journalEntry) {
    53  	j.entries = append(j.entries, entry)
    54  	if addr := entry.dirtied(); addr != nil {
    55  		j.dirties[*addr]++
    56  	}
    57  }
    58  
    59  // revert undoes a batch of journalled modifications along with any reverted
    60  // dirty handling too.
    61  func (j *journal) revert(statedb *StateDB, snapshot int) {
    62  	for i := len(j.entries) - 1; i >= snapshot; i-- {
    63  		// Undo the changes made by the operation
    64  		j.entries[i].revert(statedb)
    65  
    66  		// Drop any dirty tracking induced by the change
    67  		if addr := j.entries[i].dirtied(); addr != nil {
    68  			if j.dirties[*addr]--; j.dirties[*addr] == 0 {
    69  				delete(j.dirties, *addr)
    70  			}
    71  		}
    72  	}
    73  	j.entries = j.entries[:snapshot]
    74  }
    75  
    76  // dirty explicitly sets an address to dirty, even if the change entries would
    77  // otherwise suggest it as clean. This method is an ugly hack to handle the RIPEMD
    78  // precompile consensus exception.
    79  func (j *journal) dirty(addr common.Address) {
    80  	j.dirties[addr]++
    81  }
    82  
    83  // length returns the current number of entries in the journal.
    84  func (j *journal) length() int {
    85  	return len(j.entries)
    86  }
    87  
    88  type (
    89  	// Changes to the account trie.
    90  	createObjectChange struct {
    91  		account *common.Address
    92  	}
    93  	resetObjectChange struct {
    94  		prev         *stateObject
    95  		prevdestruct bool
    96  	}
    97  	suicideChange struct {
    98  		account     *common.Address
    99  		prev        bool // whether account had already suicided
   100  		prevbalance *big.Int
   101  	}
   102  
   103  	// Changes to individual accounts.
   104  	balanceChange struct {
   105  		account *common.Address
   106  		prev    *big.Int
   107  	}
   108  	nonceChange struct {
   109  		account *common.Address
   110  		prev    uint64
   111  	}
   112  	storageChange struct {
   113  		account       *common.Address
   114  		key, prevalue common.Hash
   115  	}
   116  	codeChange struct {
   117  		account            *common.Address
   118  		prevcode, prevhash []byte
   119  	}
   120  
   121  	// Changes to other state values.
   122  	refundChange struct {
   123  		prev uint64
   124  	}
   125  	addLogChange struct {
   126  		txhash common.Hash
   127  	}
   128  	addPreimageChange struct {
   129  		hash common.Hash
   130  	}
   131  	touchChange struct {
   132  		account *common.Address
   133  	}
   134  	// Changes to the access list
   135  	accessListAddAccountChange struct {
   136  		address *common.Address
   137  	}
   138  	accessListAddSlotChange struct {
   139  		address *common.Address
   140  		slot    *common.Hash
   141  	}
   142  )
   143  
   144  func (ch createObjectChange) revert(s *StateDB) {
   145  	delete(s.stateObjects, *ch.account)
   146  	delete(s.stateObjectsDirty, *ch.account)
   147  	RevertWrite(s, blockstm.NewAddressKey(*ch.account))
   148  }
   149  
   150  func (ch createObjectChange) dirtied() *common.Address {
   151  	return ch.account
   152  }
   153  
   154  func (ch resetObjectChange) revert(s *StateDB) {
   155  	s.setStateObject(ch.prev)
   156  	RevertWrite(s, blockstm.NewAddressKey(ch.prev.address))
   157  	if !ch.prevdestruct && s.snap != nil {
   158  		delete(s.snapDestructs, ch.prev.addrHash)
   159  	}
   160  }
   161  
   162  func (ch resetObjectChange) dirtied() *common.Address {
   163  	return nil
   164  }
   165  
   166  func (ch suicideChange) revert(s *StateDB) {
   167  	obj := s.getStateObject(*ch.account)
   168  	if obj != nil {
   169  		obj.suicided = ch.prev
   170  		obj.setBalance(ch.prevbalance)
   171  		RevertWrite(s, blockstm.NewSubpathKey(*ch.account, SuicidePath))
   172  	}
   173  }
   174  
   175  func (ch suicideChange) dirtied() *common.Address {
   176  	return ch.account
   177  }
   178  
   179  var ripemd = common.HexToAddress("0000000000000000000000000000000000000003")
   180  
   181  func (ch touchChange) revert(s *StateDB) {
   182  }
   183  
   184  func (ch touchChange) dirtied() *common.Address {
   185  	return ch.account
   186  }
   187  
   188  func (ch balanceChange) revert(s *StateDB) {
   189  	s.getStateObject(*ch.account).setBalance(ch.prev)
   190  }
   191  
   192  func (ch balanceChange) dirtied() *common.Address {
   193  	return ch.account
   194  }
   195  
   196  func (ch nonceChange) revert(s *StateDB) {
   197  	s.getStateObject(*ch.account).setNonce(ch.prev)
   198  }
   199  
   200  func (ch nonceChange) dirtied() *common.Address {
   201  	return ch.account
   202  }
   203  
   204  func (ch codeChange) revert(s *StateDB) {
   205  	s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode)
   206  	RevertWrite(s, blockstm.NewSubpathKey(*ch.account, CodePath))
   207  }
   208  
   209  func (ch codeChange) dirtied() *common.Address {
   210  	return ch.account
   211  }
   212  
   213  func (ch storageChange) revert(s *StateDB) {
   214  	s.getStateObject(*ch.account).setState(ch.key, ch.prevalue)
   215  	RevertWrite(s, blockstm.NewStateKey(*ch.account, ch.key))
   216  }
   217  
   218  func (ch storageChange) dirtied() *common.Address {
   219  	return ch.account
   220  }
   221  
   222  func (ch refundChange) revert(s *StateDB) {
   223  	s.refund = ch.prev
   224  }
   225  
   226  func (ch refundChange) dirtied() *common.Address {
   227  	return nil
   228  }
   229  
   230  func (ch addLogChange) revert(s *StateDB) {
   231  	logs := s.logs[ch.txhash]
   232  	if len(logs) == 1 {
   233  		delete(s.logs, ch.txhash)
   234  	} else {
   235  		s.logs[ch.txhash] = logs[:len(logs)-1]
   236  	}
   237  	s.logSize--
   238  }
   239  
   240  func (ch addLogChange) dirtied() *common.Address {
   241  	return nil
   242  }
   243  
   244  func (ch addPreimageChange) revert(s *StateDB) {
   245  	delete(s.preimages, ch.hash)
   246  }
   247  
   248  func (ch addPreimageChange) dirtied() *common.Address {
   249  	return nil
   250  }
   251  
   252  func (ch accessListAddAccountChange) revert(s *StateDB) {
   253  	/*
   254  		One important invariant here, is that whenever a (addr, slot) is added, if the
   255  		addr is not already present, the add causes two journal entries:
   256  		- one for the address,
   257  		- one for the (address,slot)
   258  		Therefore, when unrolling the change, we can always blindly delete the
   259  		(addr) at this point, since no storage adds can remain when come upon
   260  		a single (addr) change.
   261  	*/
   262  	s.accessList.DeleteAddress(*ch.address)
   263  }
   264  
   265  func (ch accessListAddAccountChange) dirtied() *common.Address {
   266  	return nil
   267  }
   268  
   269  func (ch accessListAddSlotChange) revert(s *StateDB) {
   270  	s.accessList.DeleteSlot(*ch.address, *ch.slot)
   271  }
   272  
   273  func (ch accessListAddSlotChange) dirtied() *common.Address {
   274  	return nil
   275  }