github.com/ethereum-optimism/optimism/l2geth@v0.0.0-20230612200230-50b04ade19e3/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-optimism/optimism/l2geth/common"
    23  )
    24  
    25  // journalEntry is a modification entry in the state change journal that can be
    26  // reverted on demand.
    27  type journalEntry interface {
    28  	// revert undoes the changes introduced by this journal entry.
    29  	revert(*StateDB)
    30  
    31  	// dirtied returns the Ethereum address modified by this journal entry.
    32  	dirtied() *common.Address
    33  }
    34  
    35  // journal contains the list of state modifications applied since the last state
    36  // commit. These are tracked to be able to be reverted in case of an execution
    37  // exception or revertal request.
    38  type journal struct {
    39  	entries []journalEntry         // Current changes tracked by the journal
    40  	dirties map[common.Address]int // Dirty accounts and the number of changes
    41  }
    42  
    43  // newJournal create a new initialized journal.
    44  func newJournal() *journal {
    45  	return &journal{
    46  		dirties: make(map[common.Address]int),
    47  	}
    48  }
    49  
    50  // append inserts a new modification entry to the end of the change journal.
    51  func (j *journal) append(entry journalEntry) {
    52  	j.entries = append(j.entries, entry)
    53  	if addr := entry.dirtied(); addr != nil {
    54  		j.dirties[*addr]++
    55  	}
    56  }
    57  
    58  // revert undoes a batch of journalled modifications along with any reverted
    59  // dirty handling too.
    60  func (j *journal) revert(statedb *StateDB, snapshot int) {
    61  	for i := len(j.entries) - 1; i >= snapshot; i-- {
    62  		// Undo the changes made by the operation
    63  		j.entries[i].revert(statedb)
    64  
    65  		// Drop any dirty tracking induced by the change
    66  		if addr := j.entries[i].dirtied(); addr != nil {
    67  			if j.dirties[*addr]--; j.dirties[*addr] == 0 {
    68  				delete(j.dirties, *addr)
    69  			}
    70  		}
    71  	}
    72  	j.entries = j.entries[:snapshot]
    73  }
    74  
    75  // dirty explicitly sets an address to dirty, even if the change entries would
    76  // otherwise suggest it as clean. This method is an ugly hack to handle the RIPEMD
    77  // precompile consensus exception.
    78  func (j *journal) dirty(addr common.Address) {
    79  	j.dirties[addr]++
    80  }
    81  
    82  // length returns the current number of entries in the journal.
    83  func (j *journal) length() int {
    84  	return len(j.entries)
    85  }
    86  
    87  type (
    88  	// Changes to the account trie.
    89  	createObjectChange struct {
    90  		account *common.Address
    91  	}
    92  	resetObjectChange struct {
    93  		prev *stateObject
    94  	}
    95  	suicideChange struct {
    96  		account     *common.Address
    97  		prev        bool // whether account had already suicided
    98  		prevbalance *big.Int
    99  	}
   100  
   101  	// Changes to individual accounts.
   102  	balanceChange struct {
   103  		account *common.Address
   104  		prev    *big.Int
   105  	}
   106  	nonceChange struct {
   107  		account *common.Address
   108  		prev    uint64
   109  	}
   110  	storageChange struct {
   111  		account       *common.Address
   112  		key, prevalue common.Hash
   113  	}
   114  	codeChange struct {
   115  		account            *common.Address
   116  		prevcode, prevhash []byte
   117  	}
   118  
   119  	// Changes to other state values.
   120  	refundChange struct {
   121  		prev uint64
   122  	}
   123  	addLogChange struct {
   124  		txhash common.Hash
   125  	}
   126  	addPreimageChange struct {
   127  		hash common.Hash
   128  	}
   129  	touchChange struct {
   130  		account *common.Address
   131  	}
   132  
   133  	// Changes to the access list
   134  	accessListAddAccountChange struct {
   135  		address *common.Address
   136  	}
   137  	accessListAddSlotChange struct {
   138  		address *common.Address
   139  		slot    *common.Hash
   140  	}
   141  )
   142  
   143  func (ch createObjectChange) revert(s *StateDB) {
   144  	delete(s.stateObjects, *ch.account)
   145  	delete(s.stateObjectsDirty, *ch.account)
   146  }
   147  
   148  func (ch createObjectChange) dirtied() *common.Address {
   149  	return ch.account
   150  }
   151  
   152  func (ch resetObjectChange) revert(s *StateDB) {
   153  	s.setStateObject(ch.prev)
   154  }
   155  
   156  func (ch resetObjectChange) dirtied() *common.Address {
   157  	return nil
   158  }
   159  
   160  func (ch suicideChange) revert(s *StateDB) {
   161  	obj := s.getStateObject(*ch.account)
   162  	if obj != nil {
   163  		obj.suicided = ch.prev
   164  		obj.setBalance(ch.prevbalance)
   165  	}
   166  }
   167  
   168  func (ch suicideChange) dirtied() *common.Address {
   169  	return ch.account
   170  }
   171  
   172  var ripemd = common.HexToAddress("0000000000000000000000000000000000000003")
   173  
   174  func (ch touchChange) revert(s *StateDB) {
   175  }
   176  
   177  func (ch touchChange) dirtied() *common.Address {
   178  	return ch.account
   179  }
   180  
   181  func (ch balanceChange) revert(s *StateDB) {
   182  	s.getStateObject(*ch.account).setBalance(ch.prev)
   183  }
   184  
   185  func (ch balanceChange) dirtied() *common.Address {
   186  	return ch.account
   187  }
   188  
   189  func (ch nonceChange) revert(s *StateDB) {
   190  	s.getStateObject(*ch.account).setNonce(ch.prev)
   191  }
   192  
   193  func (ch nonceChange) dirtied() *common.Address {
   194  	return ch.account
   195  }
   196  
   197  func (ch codeChange) revert(s *StateDB) {
   198  	s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode)
   199  }
   200  
   201  func (ch codeChange) dirtied() *common.Address {
   202  	return ch.account
   203  }
   204  
   205  func (ch storageChange) revert(s *StateDB) {
   206  	s.getStateObject(*ch.account).setState(ch.key, ch.prevalue)
   207  }
   208  
   209  func (ch storageChange) dirtied() *common.Address {
   210  	return ch.account
   211  }
   212  
   213  func (ch refundChange) revert(s *StateDB) {
   214  	s.refund = ch.prev
   215  }
   216  
   217  func (ch refundChange) dirtied() *common.Address {
   218  	return nil
   219  }
   220  
   221  func (ch addLogChange) revert(s *StateDB) {
   222  	logs := s.logs[ch.txhash]
   223  	if len(logs) == 1 {
   224  		delete(s.logs, ch.txhash)
   225  	} else {
   226  		s.logs[ch.txhash] = logs[:len(logs)-1]
   227  	}
   228  	s.logSize--
   229  }
   230  
   231  func (ch addLogChange) dirtied() *common.Address {
   232  	return nil
   233  }
   234  
   235  func (ch addPreimageChange) revert(s *StateDB) {
   236  	delete(s.preimages, ch.hash)
   237  }
   238  
   239  func (ch addPreimageChange) dirtied() *common.Address {
   240  	return nil
   241  }
   242  
   243  func (ch accessListAddAccountChange) revert(s *StateDB) {
   244  	/*
   245  		One important invariant here, is that whenever a (addr, slot) is added, if the
   246  		addr is not already present, the add causes two journal entries:
   247  		- one for the address,
   248  		- one for the (address,slot)
   249  		Therefore, when unrolling the change, we can always blindly delete the
   250  		(addr) at this point, since no storage adds can remain when come upon
   251  		a single (addr) change.
   252  	*/
   253  	s.accessList.DeleteAddress(*ch.address)
   254  }
   255  
   256  func (ch accessListAddAccountChange) dirtied() *common.Address {
   257  	return nil
   258  }
   259  
   260  func (ch accessListAddSlotChange) revert(s *StateDB) {
   261  	s.accessList.DeleteSlot(*ch.address, *ch.slot)
   262  }
   263  
   264  func (ch accessListAddSlotChange) dirtied() *common.Address {
   265  	return nil
   266  }