github.com/Unheilbar/quorum@v1.0.0/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  	"sync"
    22  
    23  	"github.com/ethereum/go-ethereum/common"
    24  )
    25  
    26  // journalEntry is a modification entry in the state change journal that can be
    27  // reverted on demand.
    28  type journalEntry interface {
    29  	// revert undoes the changes introduced by this journal entry.
    30  	revert(*StateDB)
    31  
    32  	// dirtied returns the Ethereum address modified by this journal entry.
    33  	dirtied() *common.Address
    34  }
    35  
    36  // journal contains the list of state modifications applied since the last state
    37  // commit. These are tracked to be able to be reverted in case of an execution
    38  // exception or revertal request.
    39  type journal struct {
    40  	entries []journalEntry         // Current changes tracked by the journal
    41  	dirties map[common.Address]int // Dirty accounts and the number of changes
    42  	mutex   sync.Mutex
    43  }
    44  
    45  // newJournal create a new initialized journal.
    46  func newJournal() *journal {
    47  	return &journal{
    48  		dirties: make(map[common.Address]int),
    49  	}
    50  }
    51  
    52  // append inserts a new modification entry to the end of the change journal.
    53  func (j *journal) append(entry journalEntry) {
    54  	defer j.mutex.Unlock()
    55  	j.mutex.Lock()
    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  	defer j.mutex.Unlock()
    66  	j.mutex.Lock()
    67  	for i := len(j.entries) - 1; i >= snapshot; i-- {
    68  		// Undo the changes made by the operation
    69  		j.entries[i].revert(statedb)
    70  
    71  		// Drop any dirty tracking induced by the change
    72  		if addr := j.entries[i].dirtied(); addr != nil {
    73  			if j.dirties[*addr]--; j.dirties[*addr] == 0 {
    74  				delete(j.dirties, *addr)
    75  			}
    76  		}
    77  	}
    78  	j.entries = j.entries[:snapshot]
    79  }
    80  
    81  // dirty explicitly sets an address to dirty, even if the change entries would
    82  // otherwise suggest it as clean. This method is an ugly hack to handle the RIPEMD
    83  // precompile consensus exception.
    84  func (j *journal) dirty(addr common.Address) {
    85  	defer j.mutex.Unlock()
    86  	j.mutex.Lock()
    87  	j.dirties[addr]++
    88  }
    89  
    90  // length returns the current number of entries in the journal.
    91  func (j *journal) length() int {
    92  	return len(j.entries)
    93  }
    94  
    95  type (
    96  	// Changes to the account trie.
    97  	createObjectChange struct {
    98  		account *common.Address
    99  	}
   100  	resetObjectChange struct {
   101  		prev         *stateObject
   102  		prevdestruct bool
   103  	}
   104  	suicideChange struct {
   105  		account     *common.Address
   106  		prev        bool // whether account had already suicided
   107  		prevbalance *big.Int
   108  	}
   109  
   110  	// Changes to individual accounts.
   111  	balanceChange struct {
   112  		account *common.Address
   113  		prev    *big.Int
   114  	}
   115  	nonceChange struct {
   116  		account *common.Address
   117  		prev    uint64
   118  	}
   119  	storageChange struct {
   120  		account       *common.Address
   121  		key, prevalue common.Hash
   122  	}
   123  	codeChange struct {
   124  		account            *common.Address
   125  		prevcode, prevhash []byte
   126  	}
   127  	// Quorum - changes to AccountExtraData
   128  	accountExtraDataChange struct {
   129  		account *common.Address
   130  		prev    *AccountExtraData
   131  	}
   132  	// Changes to other state values.
   133  	refundChange struct {
   134  		prev uint64
   135  	}
   136  	addLogChange struct {
   137  		txhash common.Hash
   138  	}
   139  	addPreimageChange struct {
   140  		hash common.Hash
   141  	}
   142  	touchChange struct {
   143  		account *common.Address
   144  	}
   145  	// Changes to the access list
   146  	accessListAddAccountChange struct {
   147  		address *common.Address
   148  	}
   149  	accessListAddSlotChange struct {
   150  		address *common.Address
   151  		slot    *common.Hash
   152  	}
   153  )
   154  
   155  func (ch createObjectChange) revert(s *StateDB) {
   156  	defer s.mutex.Unlock()
   157  	s.mutex.Lock()
   158  	delete(s.stateObjects, *ch.account)
   159  	delete(s.stateObjectsDirty, *ch.account)
   160  }
   161  
   162  func (ch createObjectChange) dirtied() *common.Address {
   163  	return ch.account
   164  }
   165  
   166  func (ch resetObjectChange) revert(s *StateDB) {
   167  	s.setStateObject(ch.prev)
   168  	if !ch.prevdestruct && s.snap != nil {
   169  		delete(s.snapDestructs, ch.prev.addrHash)
   170  	}
   171  }
   172  
   173  func (ch resetObjectChange) dirtied() *common.Address {
   174  	return nil
   175  }
   176  
   177  func (ch suicideChange) revert(s *StateDB) {
   178  	obj := s.getStateObject(*ch.account)
   179  	if obj != nil {
   180  		obj.suicided = ch.prev
   181  		obj.setBalance(ch.prevbalance)
   182  	}
   183  }
   184  
   185  func (ch suicideChange) dirtied() *common.Address {
   186  	return ch.account
   187  }
   188  
   189  var ripemd = common.HexToAddress("0000000000000000000000000000000000000003")
   190  
   191  func (ch touchChange) revert(s *StateDB) {
   192  }
   193  
   194  func (ch touchChange) dirtied() *common.Address {
   195  	return ch.account
   196  }
   197  
   198  func (ch balanceChange) revert(s *StateDB) {
   199  	s.getStateObject(*ch.account).setBalance(ch.prev)
   200  }
   201  
   202  func (ch balanceChange) dirtied() *common.Address {
   203  	return ch.account
   204  }
   205  
   206  func (ch nonceChange) revert(s *StateDB) {
   207  	s.getStateObject(*ch.account).setNonce(ch.prev)
   208  }
   209  
   210  func (ch nonceChange) dirtied() *common.Address {
   211  	return ch.account
   212  }
   213  
   214  func (ch codeChange) revert(s *StateDB) {
   215  	s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode)
   216  }
   217  
   218  func (ch codeChange) dirtied() *common.Address {
   219  	return ch.account
   220  }
   221  
   222  // Quorum
   223  func (ch accountExtraDataChange) revert(s *StateDB) {
   224  	s.getStateObject(*ch.account).setAccountExtraData(ch.prev)
   225  }
   226  
   227  func (ch accountExtraDataChange) dirtied() *common.Address {
   228  	return ch.account
   229  }
   230  
   231  // End Quorum - Privacy Enhancements
   232  
   233  func (ch storageChange) revert(s *StateDB) {
   234  	s.getStateObject(*ch.account).setState(ch.key, ch.prevalue)
   235  }
   236  
   237  func (ch storageChange) dirtied() *common.Address {
   238  	return ch.account
   239  }
   240  
   241  func (ch refundChange) revert(s *StateDB) {
   242  	s.refund = ch.prev
   243  }
   244  
   245  func (ch refundChange) dirtied() *common.Address {
   246  	return nil
   247  }
   248  
   249  func (ch addLogChange) revert(s *StateDB) {
   250  	logs := s.logs[ch.txhash]
   251  	if len(logs) == 1 {
   252  		delete(s.logs, ch.txhash)
   253  	} else {
   254  		s.logs[ch.txhash] = logs[:len(logs)-1]
   255  	}
   256  	s.logSize--
   257  }
   258  
   259  func (ch addLogChange) dirtied() *common.Address {
   260  	return nil
   261  }
   262  
   263  func (ch addPreimageChange) revert(s *StateDB) {
   264  	delete(s.preimages, ch.hash)
   265  }
   266  
   267  func (ch addPreimageChange) dirtied() *common.Address {
   268  	return nil
   269  }
   270  
   271  func (ch accessListAddAccountChange) revert(s *StateDB) {
   272  	/*
   273  		One important invariant here, is that whenever a (addr, slot) is added, if the
   274  		addr is not already present, the add causes two journal entries:
   275  		- one for the address,
   276  		- one for the (address,slot)
   277  		Therefore, when unrolling the change, we can always blindly delete the
   278  		(addr) at this point, since no storage adds can remain when come upon
   279  		a single (addr) change.
   280  	*/
   281  	s.accessList.DeleteAddress(*ch.address)
   282  }
   283  
   284  func (ch accessListAddAccountChange) dirtied() *common.Address {
   285  	return nil
   286  }
   287  
   288  func (ch accessListAddSlotChange) revert(s *StateDB) {
   289  	s.accessList.DeleteSlot(*ch.address, *ch.slot)
   290  }
   291  
   292  func (ch accessListAddSlotChange) dirtied() *common.Address {
   293  	return nil
   294  }