github.com/klaytn/klaytn@v1.12.1/blockchain/state/journal.go (about)

     1  // Modifications Copyright 2018 The klaytn Authors
     2  // Copyright 2015 The go-ethereum Authors
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from core/state/journal.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package state
    22  
    23  import (
    24  	"math/big"
    25  
    26  	"github.com/klaytn/klaytn/common"
    27  )
    28  
    29  // journalEntry is a modification entry in the state change journal that can be
    30  // reverted on demand.
    31  type journalEntry interface {
    32  	// revert undoes the changes introduced by this journal entry.
    33  	revert(*StateDB)
    34  
    35  	// dirtied returns the Klaytn address modified by this journal entry.
    36  	dirtied() *common.Address
    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 case of an execution
    41  // exception or revertal request.
    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 create 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  type (
    92  	// Changes to the account trie.
    93  	createObjectChange struct {
    94  		account *common.Address
    95  	}
    96  	resetObjectChange struct {
    97  		prev         *stateObject
    98  		prevdestruct bool
    99  	}
   100  	selfDestructChange struct {
   101  		account     *common.Address
   102  		prev        bool // whether account had already self-destructed
   103  		prevbalance *big.Int
   104  	}
   105  
   106  	// Changes to individual accounts.
   107  	balanceChange struct {
   108  		account *common.Address
   109  		prev    *big.Int
   110  	}
   111  	nonceChange struct {
   112  		account *common.Address
   113  		prev    uint64
   114  	}
   115  	storageChange struct {
   116  		account       *common.Address
   117  		key, prevalue common.Hash
   118  	}
   119  	codeChange struct {
   120  		account            *common.Address
   121  		prevcode, prevhash []byte
   122  	}
   123  
   124  	// Changes to other state values.
   125  	refundChange struct {
   126  		prev uint64
   127  	}
   128  	addLogChange struct {
   129  		txhash common.Hash
   130  	}
   131  	addPreimageChange struct {
   132  		hash common.Hash
   133  	}
   134  	touchChange struct {
   135  		account   *common.Address
   136  		prev      bool
   137  		prevDirty bool
   138  	}
   139  	// Changes to the access list
   140  	accessListAddAccountChange struct {
   141  		address *common.Address
   142  	}
   143  
   144  	accessListAddSlotChange struct {
   145  		address *common.Address
   146  		slot    *common.Hash
   147  	}
   148  	transientStorageChange struct {
   149  		account       *common.Address
   150  		key, prevalue common.Hash
   151  	}
   152  )
   153  
   154  func (ch createObjectChange) revert(s *StateDB) {
   155  	delete(s.stateObjects, *ch.account)
   156  	delete(s.stateObjectsDirty, *ch.account)
   157  }
   158  
   159  func (ch createObjectChange) dirtied() *common.Address {
   160  	return ch.account
   161  }
   162  
   163  func (ch resetObjectChange) revert(s *StateDB) {
   164  	s.setStateObject(ch.prev)
   165  	if !ch.prevdestruct && s.snap != nil {
   166  		delete(s.snapDestructs, ch.prev.addrHash)
   167  	}
   168  }
   169  
   170  func (ch resetObjectChange) dirtied() *common.Address {
   171  	return nil
   172  }
   173  
   174  func (ch selfDestructChange) revert(s *StateDB) {
   175  	obj := s.getStateObject(*ch.account)
   176  	if obj != nil {
   177  		obj.selfDestructed = ch.prev
   178  		obj.setBalance(ch.prevbalance)
   179  	}
   180  }
   181  
   182  func (ch selfDestructChange) dirtied() *common.Address {
   183  	return ch.account
   184  }
   185  
   186  var ripemd = common.HexToAddress("0000000000000000000000000000000000000003")
   187  
   188  func (ch touchChange) revert(s *StateDB) {
   189  }
   190  
   191  func (ch touchChange) dirtied() *common.Address {
   192  	return ch.account
   193  }
   194  
   195  func (ch balanceChange) revert(s *StateDB) {
   196  	s.getStateObject(*ch.account).setBalance(ch.prev)
   197  }
   198  
   199  func (ch balanceChange) dirtied() *common.Address {
   200  	return ch.account
   201  }
   202  
   203  func (ch nonceChange) revert(s *StateDB) {
   204  	s.getStateObject(*ch.account).setNonce(ch.prev)
   205  }
   206  
   207  func (ch nonceChange) dirtied() *common.Address {
   208  	return ch.account
   209  }
   210  
   211  func (ch codeChange) revert(s *StateDB) {
   212  	s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode)
   213  }
   214  
   215  func (ch codeChange) dirtied() *common.Address {
   216  	return ch.account
   217  }
   218  
   219  func (ch storageChange) revert(s *StateDB) {
   220  	s.getStateObject(*ch.account).setState(ch.key, ch.prevalue)
   221  }
   222  
   223  func (ch storageChange) dirtied() *common.Address {
   224  	return ch.account
   225  }
   226  
   227  func (ch transientStorageChange) revert(s *StateDB) {
   228  	s.setTransientState(*ch.account, ch.key, ch.prevalue)
   229  }
   230  
   231  func (ch transientStorageChange) dirtied() *common.Address {
   232  	return nil
   233  }
   234  
   235  func (ch refundChange) revert(s *StateDB) {
   236  	s.refund = ch.prev
   237  }
   238  
   239  func (ch refundChange) dirtied() *common.Address {
   240  	return nil
   241  }
   242  
   243  func (ch addLogChange) revert(s *StateDB) {
   244  	logs := s.logs[ch.txhash]
   245  	if len(logs) == 1 {
   246  		delete(s.logs, ch.txhash)
   247  	} else {
   248  		s.logs[ch.txhash] = logs[:len(logs)-1]
   249  	}
   250  	s.logSize--
   251  }
   252  
   253  func (ch addLogChange) dirtied() *common.Address {
   254  	return nil
   255  }
   256  
   257  func (ch addPreimageChange) revert(s *StateDB) {
   258  	delete(s.preimages, ch.hash)
   259  }
   260  
   261  func (ch addPreimageChange) dirtied() *common.Address {
   262  	return nil
   263  }
   264  
   265  func (ch accessListAddAccountChange) revert(s *StateDB) {
   266  	/*
   267  		One important invariant here, is that whenever a (addr, slot) is added, if the
   268  		addr is not already present, the add causes two journal entries:
   269  		- one for the address,
   270  		- one for the (address,slot)
   271  		Therefore, when unrolling the change, we can always blindly delete the
   272  		(addr) at this point, since no storage adds can remain when come upon
   273  		a single (addr) change.
   274  	*/
   275  	s.accessList.DeleteAddress(*ch.address)
   276  }
   277  
   278  func (ch accessListAddAccountChange) dirtied() *common.Address {
   279  	return nil
   280  }
   281  
   282  func (ch accessListAddSlotChange) revert(s *StateDB) {
   283  	s.accessList.DeleteSlot(*ch.address, *ch.slot)
   284  }
   285  
   286  func (ch accessListAddSlotChange) dirtied() *common.Address {
   287  	return nil
   288  }