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