github.com/dim4egster/coreth@v0.10.2/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  	multiCoinEnable struct {
   118  		account *common.Address
   119  	}
   120  	nonceChange struct {
   121  		account *common.Address
   122  		prev    uint64
   123  	}
   124  	storageChange struct {
   125  		account       *common.Address
   126  		key, prevalue common.Hash
   127  	}
   128  	codeChange struct {
   129  		account            *common.Address
   130  		prevcode, prevhash []byte
   131  	}
   132  
   133  	// Changes to other state values.
   134  	refundChange struct {
   135  		prev uint64
   136  	}
   137  	addLogChange struct {
   138  		txhash common.Hash
   139  	}
   140  	addPreimageChange struct {
   141  		hash common.Hash
   142  	}
   143  	touchChange struct {
   144  		account *common.Address
   145  	}
   146  	// Changes to the access list
   147  	accessListAddAccountChange struct {
   148  		address *common.Address
   149  	}
   150  	accessListAddSlotChange struct {
   151  		address *common.Address
   152  		slot    *common.Hash
   153  	}
   154  )
   155  
   156  func (ch createObjectChange) revert(s *StateDB) {
   157  	delete(s.stateObjects, *ch.account)
   158  	delete(s.stateObjectsDirty, *ch.account)
   159  }
   160  
   161  func (ch createObjectChange) dirtied() *common.Address {
   162  	return ch.account
   163  }
   164  
   165  func (ch resetObjectChange) revert(s *StateDB) {
   166  	s.setStateObject(ch.prev)
   167  	if !ch.prevdestruct && s.snap != nil {
   168  		delete(s.snapDestructs, ch.prev.addrHash)
   169  	}
   170  }
   171  
   172  func (ch resetObjectChange) dirtied() *common.Address {
   173  	return nil
   174  }
   175  
   176  func (ch suicideChange) revert(s *StateDB) {
   177  	obj := s.getStateObject(*ch.account)
   178  	if obj != nil {
   179  		obj.suicided = ch.prev
   180  		obj.setBalance(ch.prevbalance)
   181  	}
   182  }
   183  
   184  func (ch suicideChange) dirtied() *common.Address {
   185  	return ch.account
   186  }
   187  
   188  var ripemd = common.HexToAddress("0000000000000000000000000000000000000003")
   189  
   190  func (ch touchChange) revert(s *StateDB) {
   191  }
   192  
   193  func (ch touchChange) dirtied() *common.Address {
   194  	return ch.account
   195  }
   196  
   197  func (ch balanceChange) revert(s *StateDB) {
   198  	s.getStateObject(*ch.account).setBalance(ch.prev)
   199  }
   200  
   201  func (ch balanceChange) dirtied() *common.Address {
   202  	return ch.account
   203  }
   204  
   205  func (ch multiCoinEnable) revert(s *StateDB) {
   206  	s.getStateObject(*ch.account).data.IsMultiCoin = false
   207  }
   208  
   209  func (ch multiCoinEnable) dirtied() *common.Address {
   210  	return ch.account
   211  }
   212  
   213  func (ch nonceChange) revert(s *StateDB) {
   214  	s.getStateObject(*ch.account).setNonce(ch.prev)
   215  }
   216  
   217  func (ch nonceChange) dirtied() *common.Address {
   218  	return ch.account
   219  }
   220  
   221  func (ch codeChange) revert(s *StateDB) {
   222  	s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode)
   223  }
   224  
   225  func (ch codeChange) dirtied() *common.Address {
   226  	return ch.account
   227  }
   228  
   229  func (ch storageChange) revert(s *StateDB) {
   230  	s.getStateObject(*ch.account).setState(ch.key, ch.prevalue)
   231  }
   232  
   233  func (ch storageChange) dirtied() *common.Address {
   234  	return ch.account
   235  }
   236  
   237  func (ch refundChange) revert(s *StateDB) {
   238  	s.refund = ch.prev
   239  }
   240  
   241  func (ch refundChange) dirtied() *common.Address {
   242  	return nil
   243  }
   244  
   245  func (ch addLogChange) revert(s *StateDB) {
   246  	logs := s.logs[ch.txhash]
   247  	if len(logs) == 1 {
   248  		delete(s.logs, ch.txhash)
   249  	} else {
   250  		s.logs[ch.txhash] = logs[:len(logs)-1]
   251  	}
   252  	s.logSize--
   253  }
   254  
   255  func (ch addLogChange) dirtied() *common.Address {
   256  	return nil
   257  }
   258  
   259  func (ch addPreimageChange) revert(s *StateDB) {
   260  	delete(s.preimages, ch.hash)
   261  }
   262  
   263  func (ch addPreimageChange) dirtied() *common.Address {
   264  	return nil
   265  }
   266  
   267  func (ch accessListAddAccountChange) revert(s *StateDB) {
   268  	/*
   269  		One important invariant here, is that whenever a (addr, slot) is added, if the
   270  		addr is not already present, the add causes two journal entries:
   271  		- one for the address,
   272  		- one for the (address,slot)
   273  		Therefore, when unrolling the change, we can always blindly delete the
   274  		(addr) at this point, since no storage adds can remain when come upon
   275  		a single (addr) change.
   276  	*/
   277  	s.accessList.DeleteAddress(*ch.address)
   278  }
   279  
   280  func (ch accessListAddAccountChange) dirtied() *common.Address {
   281  	return nil
   282  }
   283  
   284  func (ch accessListAddSlotChange) revert(s *StateDB) {
   285  	s.accessList.DeleteSlot(*ch.address, *ch.slot)
   286  }
   287  
   288  func (ch accessListAddSlotChange) dirtied() *common.Address {
   289  	return nil
   290  }