github.com/MetalBlockchain/subnet-evm@v0.4.9/core/state/journal.go (about)

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