github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/core/state/journal.go (about)

     1  package state
     2  
     3  import (
     4  	"math/big"
     5  
     6  	"github.com/quickchainproject/quickchain/common"
     7  )
     8  
     9  // journalEntry is a modification entry in the state change journal that can be
    10  // reverted on demand.
    11  type journalEntry interface {
    12  	// revert undoes the changes introduced by this journal entry.
    13  	revert(*StateDB)
    14  
    15  	// dirtied returns the Ethereum address modified by this journal entry.
    16  	dirtied() *common.Address
    17  }
    18  
    19  // journal contains the list of state modifications applied since the last state
    20  // commit. These are tracked to be able to be reverted in case of an execution
    21  // exception or revertal request.
    22  type journal struct {
    23  	entries []journalEntry         // Current changes tracked by the journal
    24  	dirties map[common.Address]int // Dirty accounts and the number of changes
    25  }
    26  
    27  // newJournal create a new initialized journal.
    28  func newJournal() *journal {
    29  	return &journal{
    30  		dirties: make(map[common.Address]int),
    31  	}
    32  }
    33  
    34  // append inserts a new modification entry to the end of the change journal.
    35  func (j *journal) append(entry journalEntry) {
    36  	j.entries = append(j.entries, entry)
    37  	if addr := entry.dirtied(); addr != nil {
    38  		j.dirties[*addr]++
    39  	}
    40  }
    41  
    42  // revert undoes a batch of journalled modifications along with any reverted
    43  // dirty handling too.
    44  func (j *journal) revert(statedb *StateDB, snapshot int) {
    45  	for i := len(j.entries) - 1; i >= snapshot; i-- {
    46  		// Undo the changes made by the operation
    47  		j.entries[i].revert(statedb)
    48  
    49  		// Drop any dirty tracking induced by the change
    50  		if addr := j.entries[i].dirtied(); addr != nil {
    51  			if j.dirties[*addr]--; j.dirties[*addr] == 0 {
    52  				delete(j.dirties, *addr)
    53  			}
    54  		}
    55  	}
    56  	j.entries = j.entries[:snapshot]
    57  }
    58  
    59  // dirty explicitly sets an address to dirty, even if the change entries would
    60  // otherwise suggest it as clean. This method is an ugly hack to handle the RIPEMD
    61  // precompile consensus exception.
    62  func (j *journal) dirty(addr common.Address) {
    63  	j.dirties[addr]++
    64  }
    65  
    66  // length returns the current number of entries in the journal.
    67  func (j *journal) length() int {
    68  	return len(j.entries)
    69  }
    70  
    71  type (
    72  	// Changes to the account trie.
    73  	createObjectChange struct {
    74  		account *common.Address
    75  	}
    76  	resetObjectChange struct {
    77  		prev *stateObject
    78  	}
    79  	suicideChange struct {
    80  		account     *common.Address
    81  		prev        bool // whether account had already suicided
    82  		prevbalance *big.Int
    83  	}
    84  
    85  	// Changes to individual accounts.
    86  	balanceChange struct {
    87  		account *common.Address
    88  		prev    *big.Int
    89  	}
    90  	nonceChange struct {
    91  		account *common.Address
    92  		prev    uint64
    93  	}
    94  	storageChange struct {
    95  		account       *common.Address
    96  		key, prevalue common.Hash
    97  	}
    98  	codeChange struct {
    99  		account            *common.Address
   100  		prevcode, prevhash []byte
   101  	}
   102  
   103  	// Changes to other state values.
   104  	refundChange struct {
   105  		prev uint64
   106  	}
   107  	addLogChange struct {
   108  		txhash common.Hash
   109  	}
   110  	addPreimageChange struct {
   111  		hash common.Hash
   112  	}
   113  	touchChange struct {
   114  		account   *common.Address
   115  		prev      bool
   116  		prevDirty bool
   117  	}
   118  )
   119  
   120  func (ch createObjectChange) revert(s *StateDB) {
   121  	delete(s.stateObjects, *ch.account)
   122  	delete(s.stateObjectsDirty, *ch.account)
   123  }
   124  
   125  func (ch createObjectChange) dirtied() *common.Address {
   126  	return ch.account
   127  }
   128  
   129  func (ch resetObjectChange) revert(s *StateDB) {
   130  	s.setStateObject(ch.prev)
   131  }
   132  
   133  func (ch resetObjectChange) dirtied() *common.Address {
   134  	return nil
   135  }
   136  
   137  func (ch suicideChange) revert(s *StateDB) {
   138  	obj := s.getStateObject(*ch.account)
   139  	if obj != nil {
   140  		obj.suicided = ch.prev
   141  		obj.setBalance(ch.prevbalance)
   142  	}
   143  }
   144  
   145  func (ch suicideChange) dirtied() *common.Address {
   146  	return ch.account
   147  }
   148  
   149  var ripemd = common.HexToAddress("0000000000000000000000000000000000000003")
   150  
   151  func (ch touchChange) revert(s *StateDB) {
   152  }
   153  
   154  func (ch touchChange) dirtied() *common.Address {
   155  	return ch.account
   156  }
   157  
   158  func (ch balanceChange) revert(s *StateDB) {
   159  	s.getStateObject(*ch.account).setBalance(ch.prev)
   160  }
   161  
   162  func (ch balanceChange) dirtied() *common.Address {
   163  	return ch.account
   164  }
   165  
   166  func (ch nonceChange) revert(s *StateDB) {
   167  	s.getStateObject(*ch.account).setNonce(ch.prev)
   168  }
   169  
   170  func (ch nonceChange) dirtied() *common.Address {
   171  	return ch.account
   172  }
   173  
   174  func (ch codeChange) revert(s *StateDB) {
   175  	s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode)
   176  }
   177  
   178  func (ch codeChange) dirtied() *common.Address {
   179  	return ch.account
   180  }
   181  
   182  func (ch storageChange) revert(s *StateDB) {
   183  	s.getStateObject(*ch.account).setState(ch.key, ch.prevalue)
   184  }
   185  
   186  func (ch storageChange) dirtied() *common.Address {
   187  	return ch.account
   188  }
   189  
   190  func (ch refundChange) revert(s *StateDB) {
   191  	s.refund = ch.prev
   192  }
   193  
   194  func (ch refundChange) dirtied() *common.Address {
   195  	return nil
   196  }
   197  
   198  func (ch addLogChange) revert(s *StateDB) {
   199  	logs := s.logs[ch.txhash]
   200  	if len(logs) == 1 {
   201  		delete(s.logs, ch.txhash)
   202  	} else {
   203  		s.logs[ch.txhash] = logs[:len(logs)-1]
   204  	}
   205  	s.logSize--
   206  }
   207  
   208  func (ch addLogChange) dirtied() *common.Address {
   209  	return nil
   210  }
   211  
   212  func (ch addPreimageChange) revert(s *StateDB) {
   213  	delete(s.preimages, ch.hash)
   214  }
   215  
   216  func (ch addPreimageChange) dirtied() *common.Address {
   217  	return nil
   218  }