github.com/bcnmy/go-ethereum@v1.10.27/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  )
    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 the case of an execution
    37  // exception or request for reversal.
    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 creates 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  		prevdestruct bool
    95  	}
    96  	suicideChange struct {
    97  		account     *common.Address
    98  		prev        bool // whether account had already suicided
    99  		prevbalance *big.Int
   100  	}
   101  
   102  	// Changes to individual accounts.
   103  	balanceChange struct {
   104  		account *common.Address
   105  		prev    *big.Int
   106  	}
   107  	nonceChange struct {
   108  		account *common.Address
   109  		prev    uint64
   110  	}
   111  	storageChange struct {
   112  		account       *common.Address
   113  		key, prevalue common.Hash
   114  	}
   115  	codeChange struct {
   116  		account            *common.Address
   117  		prevcode, prevhash []byte
   118  	}
   119  
   120  	// Changes to other state values.
   121  	refundChange struct {
   122  		prev uint64
   123  	}
   124  	addLogChange struct {
   125  		txhash common.Hash
   126  	}
   127  	addPreimageChange struct {
   128  		hash common.Hash
   129  	}
   130  	touchChange struct {
   131  		account *common.Address
   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  	if !ch.prevdestruct && s.snap != nil {
   155  		delete(s.snapDestructs, ch.prev.addrHash)
   156  	}
   157  }
   158  
   159  func (ch resetObjectChange) dirtied() *common.Address {
   160  	return nil
   161  }
   162  
   163  func (ch suicideChange) revert(s *StateDB) {
   164  	obj := s.getStateObject(*ch.account)
   165  	if obj != nil {
   166  		obj.suicided = ch.prev
   167  		obj.setBalance(ch.prevbalance)
   168  	}
   169  }
   170  
   171  func (ch suicideChange) dirtied() *common.Address {
   172  	return ch.account
   173  }
   174  
   175  var ripemd = common.HexToAddress("0000000000000000000000000000000000000003")
   176  
   177  func (ch touchChange) revert(s *StateDB) {
   178  }
   179  
   180  func (ch touchChange) dirtied() *common.Address {
   181  	return ch.account
   182  }
   183  
   184  func (ch balanceChange) revert(s *StateDB) {
   185  	s.getStateObject(*ch.account).setBalance(ch.prev)
   186  }
   187  
   188  func (ch balanceChange) dirtied() *common.Address {
   189  	return ch.account
   190  }
   191  
   192  func (ch nonceChange) revert(s *StateDB) {
   193  	s.getStateObject(*ch.account).setNonce(ch.prev)
   194  }
   195  
   196  func (ch nonceChange) dirtied() *common.Address {
   197  	return ch.account
   198  }
   199  
   200  func (ch codeChange) revert(s *StateDB) {
   201  	s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode)
   202  }
   203  
   204  func (ch codeChange) dirtied() *common.Address {
   205  	return ch.account
   206  }
   207  
   208  func (ch storageChange) revert(s *StateDB) {
   209  	s.getStateObject(*ch.account).setState(ch.key, ch.prevalue)
   210  }
   211  
   212  func (ch storageChange) dirtied() *common.Address {
   213  	return ch.account
   214  }
   215  
   216  func (ch refundChange) revert(s *StateDB) {
   217  	s.refund = ch.prev
   218  }
   219  
   220  func (ch refundChange) dirtied() *common.Address {
   221  	return nil
   222  }
   223  
   224  func (ch addLogChange) revert(s *StateDB) {
   225  	logs := s.logs[ch.txhash]
   226  	if len(logs) == 1 {
   227  		delete(s.logs, ch.txhash)
   228  	} else {
   229  		s.logs[ch.txhash] = logs[:len(logs)-1]
   230  	}
   231  	s.logSize--
   232  }
   233  
   234  func (ch addLogChange) dirtied() *common.Address {
   235  	return nil
   236  }
   237  
   238  func (ch addPreimageChange) revert(s *StateDB) {
   239  	delete(s.preimages, ch.hash)
   240  }
   241  
   242  func (ch addPreimageChange) dirtied() *common.Address {
   243  	return nil
   244  }
   245  
   246  func (ch accessListAddAccountChange) revert(s *StateDB) {
   247  	/*
   248  		One important invariant here, is that whenever a (addr, slot) is added, if the
   249  		addr is not already present, the add causes two journal entries:
   250  		- one for the address,
   251  		- one for the (address,slot)
   252  		Therefore, when unrolling the change, we can always blindly delete the
   253  		(addr) at this point, since no storage adds can remain when come upon
   254  		a single (addr) change.
   255  	*/
   256  	s.accessList.DeleteAddress(*ch.address)
   257  }
   258  
   259  func (ch accessListAddAccountChange) dirtied() *common.Address {
   260  	return nil
   261  }
   262  
   263  func (ch accessListAddSlotChange) revert(s *StateDB) {
   264  	s.accessList.DeleteSlot(*ch.address, *ch.slot)
   265  }
   266  
   267  func (ch accessListAddSlotChange) dirtied() *common.Address {
   268  	return nil
   269  }