github.com/ethereum/go-ethereum@v1.14.3/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  	"maps"
    21  
    22  	"github.com/ethereum/go-ethereum/common"
    23  	"github.com/holiman/uint256"
    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  	// copy returns a deep-copied journal entry.
    36  	copy() journalEntry
    37  }
    38  
    39  // journal contains the list of state modifications applied since the last state
    40  // commit. These are tracked to be able to be reverted in the case of an execution
    41  // exception or request for reversal.
    42  type journal struct {
    43  	entries []journalEntry         // Current changes tracked by the journal
    44  	dirties map[common.Address]int // Dirty accounts and the number of changes
    45  }
    46  
    47  // newJournal creates a new initialized journal.
    48  func newJournal() *journal {
    49  	return &journal{
    50  		dirties: make(map[common.Address]int),
    51  	}
    52  }
    53  
    54  // append inserts a new modification entry to the end of the change journal.
    55  func (j *journal) append(entry journalEntry) {
    56  	j.entries = append(j.entries, entry)
    57  	if addr := entry.dirtied(); addr != nil {
    58  		j.dirties[*addr]++
    59  	}
    60  }
    61  
    62  // revert undoes a batch of journalled modifications along with any reverted
    63  // dirty handling too.
    64  func (j *journal) revert(statedb *StateDB, snapshot int) {
    65  	for i := len(j.entries) - 1; i >= snapshot; i-- {
    66  		// Undo the changes made by the operation
    67  		j.entries[i].revert(statedb)
    68  
    69  		// Drop any dirty tracking induced by the change
    70  		if addr := j.entries[i].dirtied(); addr != nil {
    71  			if j.dirties[*addr]--; j.dirties[*addr] == 0 {
    72  				delete(j.dirties, *addr)
    73  			}
    74  		}
    75  	}
    76  	j.entries = j.entries[:snapshot]
    77  }
    78  
    79  // dirty explicitly sets an address to dirty, even if the change entries would
    80  // otherwise suggest it as clean. This method is an ugly hack to handle the RIPEMD
    81  // precompile consensus exception.
    82  func (j *journal) dirty(addr common.Address) {
    83  	j.dirties[addr]++
    84  }
    85  
    86  // length returns the current number of entries in the journal.
    87  func (j *journal) length() int {
    88  	return len(j.entries)
    89  }
    90  
    91  // copy returns a deep-copied journal.
    92  func (j *journal) copy() *journal {
    93  	entries := make([]journalEntry, 0, j.length())
    94  	for i := 0; i < j.length(); i++ {
    95  		entries = append(entries, j.entries[i].copy())
    96  	}
    97  	return &journal{
    98  		entries: entries,
    99  		dirties: maps.Clone(j.dirties),
   100  	}
   101  }
   102  
   103  type (
   104  	// Changes to the account trie.
   105  	createObjectChange struct {
   106  		account *common.Address
   107  	}
   108  
   109  	// createContractChange represents an account becoming a contract-account.
   110  	// This event happens prior to executing initcode. The journal-event simply
   111  	// manages the created-flag, in order to allow same-tx destruction.
   112  	createContractChange struct {
   113  		account common.Address
   114  	}
   115  
   116  	selfDestructChange struct {
   117  		account     *common.Address
   118  		prev        bool // whether account had already self-destructed
   119  		prevbalance *uint256.Int
   120  	}
   121  
   122  	// Changes to individual accounts.
   123  	balanceChange struct {
   124  		account *common.Address
   125  		prev    *uint256.Int
   126  	}
   127  	nonceChange struct {
   128  		account *common.Address
   129  		prev    uint64
   130  	}
   131  	storageChange struct {
   132  		account   *common.Address
   133  		key       common.Hash
   134  		prevvalue *common.Hash
   135  	}
   136  	codeChange struct {
   137  		account            *common.Address
   138  		prevcode, prevhash []byte
   139  	}
   140  
   141  	// Changes to other state values.
   142  	refundChange struct {
   143  		prev uint64
   144  	}
   145  	addLogChange struct {
   146  		txhash common.Hash
   147  	}
   148  	addPreimageChange struct {
   149  		hash common.Hash
   150  	}
   151  	touchChange struct {
   152  		account *common.Address
   153  	}
   154  
   155  	// Changes to the access list
   156  	accessListAddAccountChange struct {
   157  		address *common.Address
   158  	}
   159  	accessListAddSlotChange struct {
   160  		address *common.Address
   161  		slot    *common.Hash
   162  	}
   163  
   164  	// Changes to transient storage
   165  	transientStorageChange struct {
   166  		account       *common.Address
   167  		key, prevalue common.Hash
   168  	}
   169  )
   170  
   171  func (ch createObjectChange) revert(s *StateDB) {
   172  	delete(s.stateObjects, *ch.account)
   173  }
   174  
   175  func (ch createObjectChange) dirtied() *common.Address {
   176  	return ch.account
   177  }
   178  
   179  func (ch createObjectChange) copy() journalEntry {
   180  	return createObjectChange{
   181  		account: ch.account,
   182  	}
   183  }
   184  
   185  func (ch createContractChange) revert(s *StateDB) {
   186  	s.getStateObject(ch.account).newContract = false
   187  }
   188  
   189  func (ch createContractChange) dirtied() *common.Address {
   190  	return nil
   191  }
   192  
   193  func (ch createContractChange) copy() journalEntry {
   194  	return createContractChange{
   195  		account: ch.account,
   196  	}
   197  }
   198  
   199  func (ch selfDestructChange) revert(s *StateDB) {
   200  	obj := s.getStateObject(*ch.account)
   201  	if obj != nil {
   202  		obj.selfDestructed = ch.prev
   203  		obj.setBalance(ch.prevbalance)
   204  	}
   205  }
   206  
   207  func (ch selfDestructChange) dirtied() *common.Address {
   208  	return ch.account
   209  }
   210  
   211  func (ch selfDestructChange) copy() journalEntry {
   212  	return selfDestructChange{
   213  		account:     ch.account,
   214  		prev:        ch.prev,
   215  		prevbalance: new(uint256.Int).Set(ch.prevbalance),
   216  	}
   217  }
   218  
   219  var ripemd = common.HexToAddress("0000000000000000000000000000000000000003")
   220  
   221  func (ch touchChange) revert(s *StateDB) {
   222  }
   223  
   224  func (ch touchChange) dirtied() *common.Address {
   225  	return ch.account
   226  }
   227  
   228  func (ch touchChange) copy() journalEntry {
   229  	return touchChange{
   230  		account: ch.account,
   231  	}
   232  }
   233  
   234  func (ch balanceChange) revert(s *StateDB) {
   235  	s.getStateObject(*ch.account).setBalance(ch.prev)
   236  }
   237  
   238  func (ch balanceChange) dirtied() *common.Address {
   239  	return ch.account
   240  }
   241  
   242  func (ch balanceChange) copy() journalEntry {
   243  	return balanceChange{
   244  		account: ch.account,
   245  		prev:    new(uint256.Int).Set(ch.prev),
   246  	}
   247  }
   248  
   249  func (ch nonceChange) revert(s *StateDB) {
   250  	s.getStateObject(*ch.account).setNonce(ch.prev)
   251  }
   252  
   253  func (ch nonceChange) dirtied() *common.Address {
   254  	return ch.account
   255  }
   256  
   257  func (ch nonceChange) copy() journalEntry {
   258  	return nonceChange{
   259  		account: ch.account,
   260  		prev:    ch.prev,
   261  	}
   262  }
   263  
   264  func (ch codeChange) revert(s *StateDB) {
   265  	s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode)
   266  }
   267  
   268  func (ch codeChange) dirtied() *common.Address {
   269  	return ch.account
   270  }
   271  
   272  func (ch codeChange) copy() journalEntry {
   273  	return codeChange{
   274  		account:  ch.account,
   275  		prevhash: common.CopyBytes(ch.prevhash),
   276  		prevcode: common.CopyBytes(ch.prevcode),
   277  	}
   278  }
   279  
   280  func (ch storageChange) revert(s *StateDB) {
   281  	s.getStateObject(*ch.account).setState(ch.key, ch.prevvalue)
   282  }
   283  
   284  func (ch storageChange) dirtied() *common.Address {
   285  	return ch.account
   286  }
   287  
   288  func (ch storageChange) copy() journalEntry {
   289  	return storageChange{
   290  		account:   ch.account,
   291  		key:       ch.key,
   292  		prevvalue: ch.prevvalue,
   293  	}
   294  }
   295  
   296  func (ch transientStorageChange) revert(s *StateDB) {
   297  	s.setTransientState(*ch.account, ch.key, ch.prevalue)
   298  }
   299  
   300  func (ch transientStorageChange) dirtied() *common.Address {
   301  	return nil
   302  }
   303  
   304  func (ch transientStorageChange) copy() journalEntry {
   305  	return transientStorageChange{
   306  		account:  ch.account,
   307  		key:      ch.key,
   308  		prevalue: ch.prevalue,
   309  	}
   310  }
   311  
   312  func (ch refundChange) revert(s *StateDB) {
   313  	s.refund = ch.prev
   314  }
   315  
   316  func (ch refundChange) dirtied() *common.Address {
   317  	return nil
   318  }
   319  
   320  func (ch refundChange) copy() journalEntry {
   321  	return refundChange{
   322  		prev: ch.prev,
   323  	}
   324  }
   325  
   326  func (ch addLogChange) revert(s *StateDB) {
   327  	logs := s.logs[ch.txhash]
   328  	if len(logs) == 1 {
   329  		delete(s.logs, ch.txhash)
   330  	} else {
   331  		s.logs[ch.txhash] = logs[:len(logs)-1]
   332  	}
   333  	s.logSize--
   334  }
   335  
   336  func (ch addLogChange) dirtied() *common.Address {
   337  	return nil
   338  }
   339  
   340  func (ch addLogChange) copy() journalEntry {
   341  	return addLogChange{
   342  		txhash: ch.txhash,
   343  	}
   344  }
   345  
   346  func (ch addPreimageChange) revert(s *StateDB) {
   347  	delete(s.preimages, ch.hash)
   348  }
   349  
   350  func (ch addPreimageChange) dirtied() *common.Address {
   351  	return nil
   352  }
   353  
   354  func (ch addPreimageChange) copy() journalEntry {
   355  	return addPreimageChange{
   356  		hash: ch.hash,
   357  	}
   358  }
   359  
   360  func (ch accessListAddAccountChange) revert(s *StateDB) {
   361  	/*
   362  		One important invariant here, is that whenever a (addr, slot) is added, if the
   363  		addr is not already present, the add causes two journal entries:
   364  		- one for the address,
   365  		- one for the (address,slot)
   366  		Therefore, when unrolling the change, we can always blindly delete the
   367  		(addr) at this point, since no storage adds can remain when come upon
   368  		a single (addr) change.
   369  	*/
   370  	s.accessList.DeleteAddress(*ch.address)
   371  }
   372  
   373  func (ch accessListAddAccountChange) dirtied() *common.Address {
   374  	return nil
   375  }
   376  
   377  func (ch accessListAddAccountChange) copy() journalEntry {
   378  	return accessListAddAccountChange{
   379  		address: ch.address,
   380  	}
   381  }
   382  
   383  func (ch accessListAddSlotChange) revert(s *StateDB) {
   384  	s.accessList.DeleteSlot(*ch.address, *ch.slot)
   385  }
   386  
   387  func (ch accessListAddSlotChange) dirtied() *common.Address {
   388  	return nil
   389  }
   390  
   391  func (ch accessListAddSlotChange) copy() journalEntry {
   392  	return accessListAddSlotChange{
   393  		address: ch.address,
   394  		slot:    ch.slot,
   395  	}
   396  }