github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/evm/types/journal.go (about)

     1  package types
     2  
     3  import (
     4  	ethcmn "github.com/ethereum/go-ethereum/common"
     5  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
     6  )
     7  
     8  var ripemd = ethcmn.HexToAddress("0000000000000000000000000000000000000003")
     9  
    10  // journalEntry is a modification entry in the state change journal that can be
    11  // reverted on demand.
    12  type journalEntry interface {
    13  	// revert undoes the changes introduced by this journal entry.
    14  	revert(*CommitStateDB)
    15  
    16  	// dirtied returns the Ethereum address modified by this journal entry.
    17  	dirtied() *ethcmn.Address
    18  }
    19  
    20  // journal contains the list of state modifications applied since the last state
    21  // commit. These are tracked to be able to be reverted in case of an execution
    22  // exception or revertal request.
    23  type journal struct {
    24  	entries []journalEntry         // Current changes tracked by the journal
    25  	dirties map[ethcmn.Address]int // Dirty accounts and the number of changes
    26  }
    27  
    28  // newJournal create a new initialized journal.
    29  func newJournal() *journal {
    30  	return &journal{
    31  		dirties: make(map[ethcmn.Address]int),
    32  	}
    33  }
    34  
    35  // append inserts a new modification entry to the end of the change journal.
    36  func (j *journal) append(entry journalEntry) {
    37  	j.entries = append(j.entries, entry)
    38  	if addr := entry.dirtied(); addr != nil {
    39  		j.dirties[*addr]++
    40  	}
    41  }
    42  
    43  // revert undoes a batch of journalled modifications along with any reverted
    44  // dirty handling too.
    45  func (j *journal) revert(statedb *CommitStateDB, snapshot int) {
    46  	for i := len(j.entries) - 1; i >= snapshot; i-- {
    47  		// Undo the changes made by the operation
    48  		j.entries[i].revert(statedb)
    49  
    50  		// Drop any dirty tracking induced by the change
    51  		if addr := j.entries[i].dirtied(); addr != nil {
    52  			if j.dirties[*addr]--; j.dirties[*addr] == 0 {
    53  				delete(j.dirties, *addr)
    54  			}
    55  		}
    56  	}
    57  	j.entries = j.entries[:snapshot]
    58  }
    59  
    60  // dirty explicitly sets an address to dirty, even if the change entries would
    61  // otherwise suggest it as clean. This method is an ugly hack to handle the RIPEMD
    62  // precompile consensus exception.
    63  func (j *journal) dirty(addr ethcmn.Address) {
    64  	j.dirties[addr]++
    65  }
    66  
    67  // length returns the current number of entries in the journal.
    68  func (j *journal) length() int {
    69  	return len(j.entries)
    70  }
    71  
    72  type (
    73  	// Changes to the account trie.
    74  	createObjectChange struct {
    75  		account *ethcmn.Address
    76  	}
    77  
    78  	resetObjectChange struct {
    79  		prev *stateObject
    80  	}
    81  
    82  	suicideChange struct {
    83  		account     *ethcmn.Address
    84  		prev        bool // whether account had already suicided
    85  		prevBalance sdk.Dec
    86  	}
    87  
    88  	// Changes to individual accounts.
    89  	balanceChange struct {
    90  		account *ethcmn.Address
    91  		prev    sdk.Dec
    92  	}
    93  
    94  	nonceChange struct {
    95  		account *ethcmn.Address
    96  		prev    uint64
    97  	}
    98  
    99  	storageChange struct {
   100  		account        *ethcmn.Address
   101  		key, prevValue ethcmn.Hash
   102  	}
   103  
   104  	codeChange struct {
   105  		account            *ethcmn.Address
   106  		prevCode, prevHash []byte
   107  	}
   108  
   109  	// Changes to other state values.
   110  	refundChange struct {
   111  		prev uint64
   112  	}
   113  
   114  	addLogChange struct {
   115  		txhash ethcmn.Hash
   116  	}
   117  
   118  	addPreimageChange struct {
   119  		hash ethcmn.Hash
   120  	}
   121  
   122  	touchChange struct {
   123  		account *ethcmn.Address
   124  		// prev      bool
   125  		// prevDirty bool
   126  	}
   127  	accessListAddAccountChange struct {
   128  		address *ethcmn.Address
   129  	}
   130  	accessListAddSlotChange struct {
   131  		address *ethcmn.Address
   132  		slot    *ethcmn.Hash
   133  	}
   134  )
   135  
   136  func (ch createObjectChange) revert(s *CommitStateDB) {
   137  	delete(s.stateObjects, *ch.account)
   138  	delete(s.stateObjectsDirty, *ch.account)
   139  }
   140  
   141  func (ch createObjectChange) dirtied() *ethcmn.Address {
   142  	return ch.account
   143  }
   144  
   145  func (ch resetObjectChange) revert(s *CommitStateDB) {
   146  	s.setStateObject(ch.prev)
   147  }
   148  
   149  func (ch resetObjectChange) dirtied() *ethcmn.Address {
   150  	return nil
   151  }
   152  
   153  func (ch suicideChange) revert(s *CommitStateDB) {
   154  	so := s.getStateObject(*ch.account)
   155  	if so != nil {
   156  		so.suicided = ch.prev
   157  		so.setBalance(sdk.DefaultBondDenom, ch.prevBalance)
   158  	}
   159  }
   160  
   161  func (ch suicideChange) dirtied() *ethcmn.Address {
   162  	return ch.account
   163  }
   164  
   165  func (ch touchChange) revert(s *CommitStateDB) {
   166  }
   167  
   168  func (ch touchChange) dirtied() *ethcmn.Address {
   169  	return ch.account
   170  }
   171  
   172  func (ch balanceChange) revert(s *CommitStateDB) {
   173  	s.getStateObject(*ch.account).setBalance(sdk.DefaultBondDenom, ch.prev)
   174  }
   175  
   176  func (ch balanceChange) dirtied() *ethcmn.Address {
   177  	return ch.account
   178  }
   179  
   180  func (ch nonceChange) revert(s *CommitStateDB) {
   181  	s.getStateObject(*ch.account).setNonce(ch.prev)
   182  }
   183  
   184  func (ch nonceChange) dirtied() *ethcmn.Address {
   185  	return ch.account
   186  }
   187  
   188  func (ch codeChange) revert(s *CommitStateDB) {
   189  	s.getStateObject(*ch.account).setCode(ethcmn.BytesToHash(ch.prevHash), ch.prevCode)
   190  }
   191  
   192  func (ch codeChange) dirtied() *ethcmn.Address {
   193  	return ch.account
   194  }
   195  
   196  func (ch storageChange) revert(s *CommitStateDB) {
   197  	s.getStateObject(*ch.account).setState(ch.key, ch.prevValue)
   198  }
   199  
   200  func (ch storageChange) dirtied() *ethcmn.Address {
   201  	return ch.account
   202  }
   203  
   204  func (ch refundChange) revert(s *CommitStateDB) {
   205  	s.refund = ch.prev
   206  }
   207  
   208  func (ch refundChange) dirtied() *ethcmn.Address {
   209  	return nil
   210  }
   211  
   212  func (ch addLogChange) revert(s *CommitStateDB) {
   213  	logs, err := s.GetLogs(ch.txhash)
   214  	if err != nil {
   215  		// panic on unmarshal error
   216  		panic(err)
   217  	}
   218  
   219  	// delete logs if entry is empty or has only one item
   220  	if len(logs) <= 1 {
   221  		s.DeleteLogs(ch.txhash)
   222  	} else if err := s.SetLogs(ch.txhash, logs[:len(logs)-1]); err != nil {
   223  		// panic on marshal error
   224  		panic(err)
   225  	}
   226  
   227  	s.logSize--
   228  }
   229  
   230  func (ch addLogChange) dirtied() *ethcmn.Address {
   231  	return nil
   232  }
   233  
   234  func (ch addPreimageChange) revert(s *CommitStateDB) {
   235  	delete(s.preimages, ch.hash)
   236  }
   237  
   238  func (ch addPreimageChange) dirtied() *ethcmn.Address {
   239  	return nil
   240  }
   241  
   242  func (ch accessListAddAccountChange) revert(s *CommitStateDB) {
   243  	/*
   244  		One important invariant here, is that whenever a (addr, slot) is added, if the
   245  		addr is not already present, the add causes two journal entries:
   246  		- one for the address,
   247  		- one for the (address,slot)
   248  		Therefore, when unrolling the change, we can always blindly delete the
   249  		(addr) at this point, since no storage adds can remain when come upon
   250  		a single (addr) change.
   251  	*/
   252  	s.accessList.DeleteAddress(*ch.address)
   253  }
   254  
   255  func (ch accessListAddAccountChange) dirtied() *ethcmn.Address {
   256  	return nil
   257  }
   258  
   259  func (ch accessListAddSlotChange) revert(s *CommitStateDB) {
   260  	s.accessList.DeleteSlot(*ch.address, *ch.slot)
   261  }
   262  
   263  func (ch accessListAddSlotChange) dirtied() *ethcmn.Address {
   264  	return nil
   265  }