github.com/amazechain/amc@v0.1.3/modules/state/journal.go (about)

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