@ -22,7 +22,6 @@ import (
"fmt"
"math/big"
"sort"
"sync"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
@ -87,8 +86,6 @@ type DB struct {
journal * journal
validRevisions [ ] revision
nextRevisionID int
lock sync . Mutex
}
// New creates a new state from a given trie.
@ -109,118 +106,118 @@ func New(root common.Hash, db Database) (*DB, error) {
}
// setError remembers the first non-nil error it is called with.
func ( stateDB * DB ) setError ( err error ) {
if stateDB . dbErr == nil {
stateDB . dbErr = err
func ( db * DB ) setError ( err error ) {
if db . dbErr == nil {
db . dbErr = err
}
}
func ( stateDB * DB ) Error ( ) error {
return stateDB . dbErr
func ( db * DB ) Error ( ) error {
return db . dbErr
}
// Reset clears out all ephemeral state objects from the state db, but keeps
// the underlying state trie to avoid reloading data for the next operations.
func ( stateDB * DB ) Reset ( root common . Hash ) error {
tr , err := stateDB . db . OpenTrie ( root )
func ( db * DB ) Reset ( root common . Hash ) error {
tr , err := db . db . OpenTrie ( root )
if err != nil {
return err
}
stateDB . trie = tr
stateDB . stateObjects = make ( map [ common . Address ] * Object )
stateDB . stateObjectsDirty = make ( map [ common . Address ] struct { } )
stateDB . thash = common . Hash { }
stateDB . bhash = common . Hash { }
stateDB . txIndex = 0
stateDB . logs = make ( map [ common . Hash ] [ ] * types . Log )
stateDB . logSize = 0
stateDB . preimages = make ( map [ common . Hash ] [ ] byte )
stateDB . clearJournalAndRefund ( )
db . trie = tr
db . stateObjects = make ( map [ common . Address ] * Object )
db . stateObjectsDirty = make ( map [ common . Address ] struct { } )
db . thash = common . Hash { }
db . bhash = common . Hash { }
db . txIndex = 0
db . logs = make ( map [ common . Hash ] [ ] * types . Log )
db . logSize = 0
db . preimages = make ( map [ common . Hash ] [ ] byte )
db . clearJournalAndRefund ( )
return nil
}
// AddLog adds logs into stateDB
func ( stateDB * DB ) AddLog ( log * types . Log ) {
stateDB . journal . append ( addLogChange { txhash : stateDB . thash } )
// AddLog ...
func ( db * DB ) AddLog ( log * types . Log ) {
db . journal . append ( addLogChange { txhash : db . thash } )
log . TxHash = stateDB . thash
log . BlockHash = stateDB . bhash
log . TxIndex = uint ( stateDB . txIndex )
log . Index = stateDB . logSize
stateDB . logs [ stateDB . thash ] = append ( stateDB . logs [ stateDB . thash ] , log )
stateDB . logSize ++
log . TxHash = db . thash
log . BlockHash = db . bhash
log . TxIndex = uint ( db . txIndex )
log . Index = db . logSize
db . logs [ db . thash ] = append ( db . logs [ db . thash ] , log )
db . logSize ++
}
// GetLogs gets logs from stateDB given a hash
func ( stateDB * DB ) GetLogs ( hash common . Hash ) [ ] * types . Log {
return stateDB . logs [ hash ]
// GetLogs ...
func ( db * DB ) GetLogs ( hash common . Hash ) [ ] * types . Log {
return db . logs [ hash ]
}
// Logs returns a list of Log .
func ( stateDB * DB ) Logs ( ) [ ] * types . Log {
// Logs .. .
func ( db * DB ) Logs ( ) [ ] * types . Log {
var logs [ ] * types . Log
for _ , lgs := range stateDB . logs {
for _ , lgs := range db . logs {
logs = append ( logs , lgs ... )
}
return logs
}
// AddPreimage records a SHA3 preimage seen by the VM.
func ( stateDB * DB ) AddPreimage ( hash common . Hash , preimage [ ] byte ) {
if _ , ok := stateDB . preimages [ hash ] ; ! ok {
stateDB . journal . append ( addPreimageChange { hash : hash } )
func ( db * DB ) AddPreimage ( hash common . Hash , preimage [ ] byte ) {
if _ , ok := db . preimages [ hash ] ; ! ok {
db . journal . append ( addPreimageChange { hash : hash } )
pi := make ( [ ] byte , len ( preimage ) )
copy ( pi , preimage )
stateDB . preimages [ hash ] = pi
db . preimages [ hash ] = pi
}
}
// Preimages returns a list of SHA3 preimages that have been submitted.
func ( stateDB * DB ) Preimages ( ) map [ common . Hash ] [ ] byte {
return stateDB . preimages
func ( db * DB ) Preimages ( ) map [ common . Hash ] [ ] byte {
return db . preimages
}
// AddRefund adds gas to the refund counter
func ( stateDB * DB ) AddRefund ( gas uint64 ) {
stateDB . journal . append ( refundChange { prev : stateDB . refund } )
stateDB . refund += gas
func ( db * DB ) AddRefund ( gas uint64 ) {
db . journal . append ( refundChange { prev : db . refund } )
db . refund += gas
}
// SubRefund removes gas from the refund counter.
// This method will panic if the refund counter goes below zero
func ( stateDB * DB ) SubRefund ( gas uint64 ) {
stateDB . journal . append ( refundChange { prev : stateDB . refund } )
if gas > stateDB . refund {
func ( db * DB ) SubRefund ( gas uint64 ) {
db . journal . append ( refundChange { prev : db . refund } )
if gas > db . refund {
panic ( "Refund counter below zero" )
}
stateDB . refund -= gas
db . refund -= gas
}
// Exist reports whether the given account address exists in the state.
// Notably this also returns true for suicided accounts.
func ( stateDB * DB ) Exist ( addr common . Address ) bool {
return stateDB . getStateObject ( addr ) != nil
func ( db * DB ) Exist ( addr common . Address ) bool {
return db . getStateObject ( addr ) != nil
}
// Empty returns whether the state object is either non-existent
// or empty according to the EIP161 specification (balance = nonce = code = 0)
func ( stateDB * DB ) Empty ( addr common . Address ) bool {
so := stateDB . getStateObject ( addr )
func ( db * DB ) Empty ( addr common . Address ) bool {
so := db . getStateObject ( addr )
return so == nil || so . empty ( )
}
// GetBalance retrieves the balance from the given address or 0 if object not found
func ( stateDB * DB ) GetBalance ( addr common . Address ) * big . Int {
stateObject := stateDB . getStateObject ( addr )
func ( db * DB ) GetBalance ( addr common . Address ) * big . Int {
stateObject := db . getStateObject ( addr )
if stateObject != nil {
return stateObject . Balance ( )
}
return common . Big0
}
// GetNonce returns the nonce of the given address .
func ( stateDB * DB ) GetNonce ( addr common . Address ) uint64 {
stateObject := stateDB . getStateObject ( addr )
// GetNonce .. .
func ( db * DB ) GetNonce ( addr common . Address ) uint64 {
stateObject := db . getStateObject ( addr )
if stateObject != nil {
return stateObject . Nonce ( )
}
@ -228,34 +225,34 @@ func (stateDB *DB) GetNonce(addr common.Address) uint64 {
return 0
}
// GetCode returns code of a given address .
func ( stateDB * DB ) GetCode ( addr common . Address ) [ ] byte {
stateObject := stateDB . getStateObject ( addr )
// GetCode .. .
func ( db * DB ) GetCode ( addr common . Address ) [ ] byte {
stateObject := db . getStateObject ( addr )
if stateObject != nil {
return stateObject . Code ( stateDB . db )
return stateObject . Code ( db . db )
}
return nil
}
// GetCodeSize returns code size of a given address in stateDB .
func ( stateDB * DB ) GetCodeSize ( addr common . Address ) int {
stateObject := stateDB . getStateObject ( addr )
// GetCodeSize .. .
func ( db * DB ) GetCodeSize ( addr common . Address ) int {
stateObject := db . getStateObject ( addr )
if stateObject == nil {
return 0
}
if stateObject . code != nil {
return len ( stateObject . code )
}
size , err := stateDB . db . ContractCodeSize ( stateObject . addrHash , common . BytesToHash ( stateObject . CodeHash ( ) ) )
size , err := db . db . ContractCodeSize ( stateObject . addrHash , common . BytesToHash ( stateObject . CodeHash ( ) ) )
if err != nil {
stateDB . setError ( err )
db . setError ( err )
}
return size
}
// GetCodeHash returns code hash of a given address .
func ( stateDB * DB ) GetCodeHash ( addr common . Address ) common . Hash {
stateObject := stateDB . getStateObject ( addr )
// GetCodeHash .. .
func ( db * DB ) GetCodeHash ( addr common . Address ) common . Hash {
stateObject := db . getStateObject ( addr )
if stateObject == nil {
return common . Hash { }
}
@ -263,25 +260,25 @@ func (stateDB *DB) GetCodeHash(addr common.Address) common.Hash {
}
// GetState retrieves a value from the given account's storage trie.
func ( stateDB * DB ) GetState ( addr common . Address , hash common . Hash ) common . Hash {
stateObject := stateDB . getStateObject ( addr )
func ( db * DB ) GetState ( addr common . Address , hash common . Hash ) common . Hash {
stateObject := db . getStateObject ( addr )
if stateObject != nil {
return stateObject . GetState ( stateDB . db , hash )
return stateObject . GetState ( db . db , hash )
}
return common . Hash { }
}
// GetProof returns the MerkleProof for a given Account
func ( stateDB * DB ) GetProof ( a common . Address ) ( [ ] [ ] byte , error ) {
func ( db * DB ) GetProof ( a common . Address ) ( [ ] [ ] byte , error ) {
var proof proofList
err := stateDB . trie . Prove ( crypto . Keccak256 ( a . Bytes ( ) ) , 0 , & proof )
err := db . trie . Prove ( crypto . Keccak256 ( a . Bytes ( ) ) , 0 , & proof )
return [ ] [ ] byte ( proof ) , err
}
// GetStorageProof returns the StorageProof for given key
func ( stateDB * DB ) GetStorageProof ( a common . Address , key common . Hash ) ( [ ] [ ] byte , error ) {
func ( db * DB ) GetStorageProof ( a common . Address , key common . Hash ) ( [ ] [ ] byte , error ) {
var proof proofList
trie := stateDB . StorageTrie ( a )
trie := db . StorageTrie ( a )
if trie == nil {
return proof , errors . New ( "storage trie for requested address does not exist" )
}
@ -290,33 +287,33 @@ func (stateDB *DB) GetStorageProof(a common.Address, key common.Hash) ([][]byte,
}
// GetCommittedState retrieves a value from the given account's committed storage trie.
func ( stateDB * DB ) GetCommittedState ( addr common . Address , hash common . Hash ) common . Hash {
stateObject := stateDB . getStateObject ( addr )
func ( db * DB ) GetCommittedState ( addr common . Address , hash common . Hash ) common . Hash {
stateObject := db . getStateObject ( addr )
if stateObject != nil {
return stateObject . GetCommittedState ( stateDB . db , hash )
return stateObject . GetCommittedState ( db . db , hash )
}
return common . Hash { }
}
// Database retrieves the low level database supporting the lower level trie ops.
func ( stateDB * DB ) Database ( ) Database {
return stateDB . db
func ( db * DB ) Database ( ) Database {
return db . db
}
// StorageTrie returns the storage trie of an account.
// The return value is a copy and is nil for non-existent accounts.
func ( stateDB * DB ) StorageTrie ( addr common . Address ) Trie {
stateObject := stateDB . getStateObject ( addr )
func ( db * DB ) StorageTrie ( addr common . Address ) Trie {
stateObject := db . getStateObject ( addr )
if stateObject == nil {
return nil
}
cpy := stateObject . deepCopy ( stateDB )
return cpy . updateTrie ( stateDB . db )
cpy := stateObject . deepCopy ( db )
return cpy . updateTrie ( db . db )
}
// HasSuicided checks if the state object of the given addr is suicided .
func ( stateDB * DB ) HasSuicided ( addr common . Address ) bool {
stateObject := stateDB . getStateObject ( addr )
// HasSuicided .. .
func ( db * DB ) HasSuicided ( addr common . Address ) bool {
stateObject := db . getStateObject ( addr )
if stateObject != nil {
return stateObject . suicided
}
@ -328,50 +325,50 @@ func (stateDB *DB) HasSuicided(addr common.Address) bool {
* /
// AddBalance adds amount to the account associated with addr.
func ( stateDB * DB ) AddBalance ( addr common . Address , amount * big . Int ) {
stateObject := stateDB . GetOrNewStateObject ( addr )
func ( db * DB ) AddBalance ( addr common . Address , amount * big . Int ) {
stateObject := db . GetOrNewStateObject ( addr )
if stateObject != nil {
stateObject . AddBalance ( amount )
}
}
// SubBalance subtracts amount from the account associated with addr.
func ( stateDB * DB ) SubBalance ( addr common . Address , amount * big . Int ) {
stateObject := stateDB . GetOrNewStateObject ( addr )
func ( db * DB ) SubBalance ( addr common . Address , amount * big . Int ) {
stateObject := db . GetOrNewStateObject ( addr )
if stateObject != nil {
stateObject . SubBalance ( amount )
}
}
// SetBalance sets balance of an address .
func ( stateDB * DB ) SetBalance ( addr common . Address , amount * big . Int ) {
stateObject := stateDB . GetOrNewStateObject ( addr )
// SetBalance .. .
func ( db * DB ) SetBalance ( addr common . Address , amount * big . Int ) {
stateObject := db . GetOrNewStateObject ( addr )
if stateObject != nil {
stateObject . SetBalance ( amount )
}
}
// SetNonce sets nonce of a given address .
func ( stateDB * DB ) SetNonce ( addr common . Address , nonce uint64 ) {
stateObject := stateDB . GetOrNewStateObject ( addr )
// SetNonce .. .
func ( db * DB ) SetNonce ( addr common . Address , nonce uint64 ) {
stateObject := db . GetOrNewStateObject ( addr )
if stateObject != nil {
stateObject . SetNonce ( nonce )
}
}
// SetCode sets code of a given address .
func ( stateDB * DB ) SetCode ( addr common . Address , code [ ] byte ) {
stateObject := stateDB . GetOrNewStateObject ( addr )
// SetCode .. .
func ( db * DB ) SetCode ( addr common . Address , code [ ] byte ) {
stateObject := db . GetOrNewStateObject ( addr )
if stateObject != nil {
stateObject . SetCode ( crypto . Keccak256Hash ( code ) , code )
}
}
// SetState sets hash value of a given address .
func ( stateDB * DB ) SetState ( addr common . Address , key , value common . Hash ) {
stateObject := stateDB . GetOrNewStateObject ( addr )
// SetState .. .
func ( db * DB ) SetState ( addr common . Address , key , value common . Hash ) {
stateObject := db . GetOrNewStateObject ( addr )
if stateObject != nil {
stateObject . SetState ( stateDB . db , key , value )
stateObject . SetState ( db . db , key , value )
}
}
@ -380,12 +377,12 @@ func (stateDB *DB) SetState(addr common.Address, key, value common.Hash) {
//
// The account's state object is still available until the state is committed,
// getStateObject will return a non-nil account after Suicide.
func ( stateDB * DB ) Suicide ( addr common . Address ) bool {
stateObject := stateDB . getStateObject ( addr )
func ( db * DB ) Suicide ( addr common . Address ) bool {
stateObject := db . getStateObject ( addr )
if stateObject == nil {
return false
}
stateDB . journal . append ( suicideChange {
db . journal . append ( suicideChange {
account : & addr ,
prev : stateObject . suicided ,
prevbalance : new ( big . Int ) . Set ( stateObject . Balance ( ) ) ,
@ -401,26 +398,26 @@ func (stateDB *DB) Suicide(addr common.Address) bool {
//
// updateStateObject writes the given object to the trie.
func ( stateDB * DB ) updateStateObject ( stateObject * Object ) {
func ( db * DB ) updateStateObject ( stateObject * Object ) {
addr := stateObject . Address ( )
data , err := rlp . EncodeToBytes ( stateObject )
if err != nil {
panic ( fmt . Errorf ( "can't encode object at %x: %v" , addr [ : ] , err ) )
}
stateDB . setError ( stateDB . trie . TryUpdate ( addr [ : ] , data ) )
db . setError ( db . trie . TryUpdate ( addr [ : ] , data ) )
}
// deleteStateObject removes the given object from the state trie.
func ( stateDB * DB ) deleteStateObject ( stateObject * Object ) {
func ( db * DB ) deleteStateObject ( stateObject * Object ) {
stateObject . deleted = true
addr := stateObject . Address ( )
stateDB . setError ( stateDB . trie . TryDelete ( addr [ : ] ) )
db . setError ( db . trie . TryDelete ( addr [ : ] ) )
}
// Retrieve a state object given by the address. Returns nil if not found.
func ( stateDB * DB ) getStateObject ( addr common . Address ) ( stateObject * Object ) {
func ( db * DB ) getStateObject ( addr common . Address ) ( stateObject * Object ) {
// Prefer 'live' objects.
if obj := stateDB . stateObjects [ addr ] ; obj != nil {
if obj := db . stateObjects [ addr ] ; obj != nil {
if obj . deleted {
return nil
}
@ -428,9 +425,9 @@ func (stateDB *DB) getStateObject(addr common.Address) (stateObject *Object) {
}
// Load the object from the database.
enc , err := stateDB . trie . TryGet ( addr [ : ] )
enc , err := db . trie . TryGet ( addr [ : ] )
if len ( enc ) == 0 {
stateDB . setError ( err )
db . setError ( err )
return nil
}
var data Account
@ -439,36 +436,36 @@ func (stateDB *DB) getStateObject(addr common.Address) (stateObject *Object) {
return nil
}
// Insert into the live set.
obj := newObject ( stateDB , addr , data )
stateDB . setStateObject ( obj )
obj := newObject ( db , addr , data )
db . setStateObject ( obj )
return obj
}
func ( stateDB * DB ) setStateObject ( object * Object ) {
stateDB . stateObjects [ object . Address ( ) ] = object
func ( db * DB ) setStateObject ( object * Object ) {
db . stateObjects [ object . Address ( ) ] = object
}
// GetOrNewStateObject retrieves a state object or create a new state object if nil.
func ( stateDB * DB ) GetOrNewStateObject ( addr common . Address ) * Object {
stateObject := stateDB . getStateObject ( addr )
func ( db * DB ) GetOrNewStateObject ( addr common . Address ) * Object {
stateObject := db . getStateObject ( addr )
if stateObject == nil || stateObject . deleted {
stateObject , _ = stateDB . createObject ( addr )
stateObject , _ = db . createObject ( addr )
}
return stateObject
}
// createObject creates a new state object. If there is an existing account with
// the given address, it is overwritten and returned as the second return value.
func ( stateDB * DB ) createObject ( addr common . Address ) ( newobj , prev * Object ) {
prev = stateDB . getStateObject ( addr )
newobj = newObject ( stateDB , addr , Account { } )
func ( db * DB ) createObject ( addr common . Address ) ( newobj , prev * Object ) {
prev = db . getStateObject ( addr )
newobj = newObject ( db , addr , Account { } )
newobj . setNonce ( 0 ) // sets the object to dirty
if prev == nil {
stateDB . journal . append ( createObjectChange { account : & addr } )
db . journal . append ( createObjectChange { account : & addr } )
} else {
stateDB . journal . append ( resetObjectChange { prev : prev } )
db . journal . append ( resetObjectChange { prev : prev } )
}
stateDB . setStateObject ( newobj )
db . setStateObject ( newobj )
return newobj , prev
}
@ -482,22 +479,22 @@ func (stateDB *DB) createObject(addr common.Address) (newobj, prev *Object) {
// 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1)
//
// Carrying over the balance ensures that Ether doesn't disappear.
func ( stateDB * DB ) CreateAccount ( addr common . Address ) {
new , prev := stateDB . createObject ( addr )
func ( db * DB ) CreateAccount ( addr common . Address ) {
newObj , prev := db . createObject ( addr )
if prev != nil {
new . setBalance ( prev . data . Balance )
newObj . setBalance ( prev . data . Balance )
}
}
// ForEachStorage runs a function on every item in state DB .
func ( stateDB * DB ) ForEachStorage ( addr common . Address , cb func ( key , value common . Hash ) bool ) {
so := stateDB . getStateObject ( addr )
// ForEachStorage .. .
func ( db * DB ) ForEachStorage ( addr common . Address , cb func ( key , value common . Hash ) bool ) {
so := db . getStateObject ( addr )
if so == nil {
return
}
it := trie . NewIterator ( so . getTrie ( stateDB . db ) . NodeIterator ( nil ) )
it := trie . NewIterator ( so . getTrie ( db . db ) . NodeIterator ( nil ) )
for it . Next ( ) {
key := common . BytesToHash ( stateDB . trie . GetKey ( it . Key ) )
key := common . BytesToHash ( db . trie . GetKey ( it . Key ) )
if value , dirty := so . dirtyStorage [ key ] ; dirty {
cb ( key , value )
continue
@ -508,29 +505,26 @@ func (stateDB *DB) ForEachStorage(addr common.Address, cb func(key, value common
// Copy creates a deep, independent copy of the state.
// Snapshots of the copied state cannot be applied to the copy.
func ( stateDB * DB ) Copy ( ) * DB {
stateDB . lock . Lock ( )
defer stateDB . lock . Unlock ( )
func ( db * DB ) Copy ( ) * DB {
// Copy all the basic fields, initialize the memory ones
state := & DB {
db : stateDB . db ,
trie : stateDB . db . CopyTrie ( stateDB . trie ) ,
stateObjects : make ( map [ common . Address ] * Object , len ( stateDB . journal . dirties ) ) ,
stateObjectsDirty : make ( map [ common . Address ] struct { } , len ( stateDB . journal . dirties ) ) ,
refund : stateDB . refund ,
logs : make ( map [ common . Hash ] [ ] * types . Log , len ( stateDB . logs ) ) ,
logSize : stateDB . logSize ,
db : db . db ,
trie : db . db . CopyTrie ( db . trie ) ,
stateObjects : make ( map [ common . Address ] * Object , len ( db . journal . dirties ) ) ,
stateObjectsDirty : make ( map [ common . Address ] struct { } , len ( db . journal . dirties ) ) ,
refund : db . refund ,
logs : make ( map [ common . Hash ] [ ] * types . Log , len ( db . logs ) ) ,
logSize : db . logSize ,
preimages : make ( map [ common . Hash ] [ ] byte ) ,
journal : newJournal ( ) ,
}
// Copy the dirty states, logs, and preimages
for addr := range stateDB . journal . dirties {
for addr := range db . journal . dirties {
// As documented [here](https://github.com/ethereum/go-ethereum/pull/16485#issuecomment-380438527),
// and in the Finalise-method, there is a case where an object is in the journal but not
// in the stateObjects: OOG after touch on ripeMD prior to Byzantium. Thus, we need to check for
// nil
if object , exist := stateDB . stateObjects [ addr ] ; exist {
if object , exist := db . stateObjects [ addr ] ; exist {
state . stateObjects [ addr ] = object . deepCopy ( state )
state . stateObjectsDirty [ addr ] = struct { } { }
}
@ -538,13 +532,13 @@ func (stateDB *DB) Copy() *DB {
// Above, we don't copy the actual journal. This means that if the copy is copied, the
// loop above will be a no-op, since the copy's journal is empty.
// Thus, here we iterate over stateObjects, to enable copies of copies
for addr := range stateDB . stateObjectsDirty {
for addr := range db . stateObjectsDirty {
if _ , exist := state . stateObjects [ addr ] ; ! exist {
state . stateObjects [ addr ] = stateDB . stateObjects [ addr ] . deepCopy ( state )
state . stateObjects [ addr ] = db . stateObjects [ addr ] . deepCopy ( state )
state . stateObjectsDirty [ addr ] = struct { } { }
}
}
for hash , logs := range stateDB . logs {
for hash , logs := range db . logs {
cpy := make ( [ ] * types . Log , len ( logs ) )
for i , l := range logs {
cpy [ i ] = new ( types . Log )
@ -552,132 +546,132 @@ func (stateDB *DB) Copy() *DB {
}
state . logs [ hash ] = cpy
}
for hash , preimage := range stateDB . preimages {
for hash , preimage := range db . preimages {
state . preimages [ hash ] = preimage
}
return state
}
// Snapshot returns an identifier for the current revision of the state.
func ( stateDB * DB ) Snapshot ( ) int {
id := stateDB . nextRevisionID
stateDB . nextRevisionID ++
stateDB . validRevisions = append ( stateDB . validRevisions , revision { id , stateDB . journal . length ( ) } )
func ( db * DB ) Snapshot ( ) int {
id := db . nextRevisionID
db . nextRevisionID ++
db . validRevisions = append ( db . validRevisions , revision { id , db . journal . length ( ) } )
return id
}
// RevertToSnapshot reverts all state changes made since the given revision.
func ( stateDB * DB ) RevertToSnapshot ( revid int ) {
func ( db * DB ) RevertToSnapshot ( revid int ) {
// Find the snapshot in the stack of valid snapshots.
idx := sort . Search ( len ( stateDB . validRevisions ) , func ( i int ) bool {
return stateDB . validRevisions [ i ] . id >= revid
idx := sort . Search ( len ( db . validRevisions ) , func ( i int ) bool {
return db . validRevisions [ i ] . id >= revid
} )
if idx == len ( stateDB . validRevisions ) || stateDB . validRevisions [ idx ] . id != revid {
if idx == len ( db . validRevisions ) || db . validRevisions [ idx ] . id != revid {
panic ( fmt . Errorf ( "revision id %v cannot be reverted" , revid ) )
}
snapshot := stateDB . validRevisions [ idx ] . journalIndex
snapshot := db . validRevisions [ idx ] . journalIndex
// Replay the journal to undo changes and remove invalidated snapshots
stateDB . journal . revert ( stateDB , snapshot )
stateDB . validRevisions = stateDB . validRevisions [ : idx ]
db . journal . revert ( db , snapshot )
db . validRevisions = db . validRevisions [ : idx ]
}
// GetRefund returns the current value of the refund counter.
func ( stateDB * DB ) GetRefund ( ) uint64 {
return stateDB . refund
func ( db * DB ) GetRefund ( ) uint64 {
return db . refund
}
// Finalise finalises the state by removing the self destructed objects
// Finalise finalises the state by removing the db destructed objects
// and clears the journal as well as the refunds.
func ( stateDB * DB ) Finalise ( deleteEmptyObjects bool ) {
for addr := range stateDB . journal . dirties {
stateObject , exist := stateDB . stateObjects [ addr ]
func ( db * DB ) Finalise ( deleteEmptyObjects bool ) {
for addr := range db . journal . dirties {
stateObject , exist := db . stateObjects [ addr ]
if ! exist {
// ripeMD is 'touched' at block 1714175, in tx 0x1237f737031e40bcde4a8b7e717b2d15e3ecadfe49bb1bbc71ee9deb09c6fcf2
// That tx goes out of gas, and although the notion of 'touched' does not exist there, the
// touch-event will still be recorded in the journal. Since ripeMD is a special snowflake,
// it will persist in the journal even though the journal is reverted. In this special circumstance,
// it may exist in `s.journal.dirties` but not in `s .stateObjects`.
// it may exist in `db.journal.dirties` but not in `db .stateObjects`.
// Thus, we can safely ignore it here
continue
}
if stateObject . suicided || ( deleteEmptyObjects && stateObject . empty ( ) ) {
stateDB . deleteStateObject ( stateObject )
db . deleteStateObject ( stateObject )
} else {
stateObject . updateRoot ( stateDB . db )
stateDB . updateStateObject ( stateObject )
stateObject . updateRoot ( db . db )
db . updateStateObject ( stateObject )
}
stateDB . stateObjectsDirty [ addr ] = struct { } { }
db . stateObjectsDirty [ addr ] = struct { } { }
}
// Invalidate journal because reverting across transactions is not allowed.
stateDB . clearJournalAndRefund ( )
db . clearJournalAndRefund ( )
}
// IntermediateRoot computes the current root hash of the state trie.
// It is called in between transactions to get the root hash that
// goes into transaction receipts.
func ( stateDB * DB ) IntermediateRoot ( deleteEmptyObjects bool ) common . Hash {
stateDB . Finalise ( deleteEmptyObjects )
return stateDB . trie . Hash ( )
func ( db * DB ) IntermediateRoot ( deleteEmptyObjects bool ) common . Hash {
db . Finalise ( deleteEmptyObjects )
return db . trie . Hash ( )
}
// Prepare sets the current transaction hash and index and block hash which is
// used when the EVM emits new state logs.
func ( stateDB * DB ) Prepare ( thash , bhash common . Hash , ti int ) {
stateDB . thash = thash
stateDB . bhash = bhash
stateDB . txIndex = ti
func ( db * DB ) Prepare ( thash , bhash common . Hash , ti int ) {
db . thash = thash
db . bhash = bhash
db . txIndex = ti
}
func ( stateDB * DB ) clearJournalAndRefund ( ) {
stateDB . journal = newJournal ( )
stateDB . validRevisions = stateDB . validRevisions [ : 0 ]
stateDB . refund = 0
func ( db * DB ) clearJournalAndRefund ( ) {
db . journal = newJournal ( )
db . validRevisions = db . validRevisions [ : 0 ]
db . refund = 0
}
// Commit writes the state to the underlying in-memory trie database.
func ( stateDB * DB ) Commit ( deleteEmptyObjects bool ) ( root common . Hash , err error ) {
defer stateDB . clearJournalAndRefund ( )
func ( db * DB ) Commit ( deleteEmptyObjects bool ) ( root common . Hash , err error ) {
defer db . clearJournalAndRefund ( )
for addr := range stateDB . journal . dirties {
stateDB . stateObjectsDirty [ addr ] = struct { } { }
for addr := range db . journal . dirties {
db . stateObjectsDirty [ addr ] = struct { } { }
}
// Commit objects to the trie.
for addr , stateObject := range stateDB . stateObjects {
_ , isDirty := stateDB . stateObjectsDirty [ addr ]
for addr , stateObject := range db . stateObjects {
_ , isDirty := db . stateObjectsDirty [ addr ]
switch {
case stateObject . suicided || ( isDirty && deleteEmptyObjects && stateObject . empty ( ) ) :
// If the object has been removed, don't bother syncing it
// and just mark it for deletion in the trie.
stateDB . deleteStateObject ( stateObject )
db . deleteStateObject ( stateObject )
case isDirty :
// Write any contract code associated with the state object
if stateObject . code != nil && stateObject . dirtyCode {
stateDB . db . TrieDB ( ) . InsertBlob ( common . BytesToHash ( stateObject . CodeHash ( ) ) , stateObject . code )
db . db . TrieDB ( ) . InsertBlob ( common . BytesToHash ( stateObject . CodeHash ( ) ) , stateObject . code )
stateObject . dirtyCode = false
}
// Write any storage changes in the state object to its storage trie.
if err := stateObject . CommitTrie ( stateDB . db ) ; err != nil {
if err := stateObject . CommitTrie ( db . db ) ; err != nil {
return common . Hash { } , err
}
// Update the object in the main account trie.
stateDB . updateStateObject ( stateObject )
db . updateStateObject ( stateObject )
}
delete ( stateDB . stateObjectsDirty , addr )
delete ( db . stateObjectsDirty , addr )
}
// Write trie changes.
root , err = stateDB . trie . Commit ( func ( leaf [ ] byte , parent common . Hash ) error {
root , err = db . trie . Commit ( func ( leaf [ ] byte , parent common . Hash ) error {
var account Account
if err := rlp . DecodeBytes ( leaf , & account ) ; err != nil {
return nil
}
if account . Root != emptyState {
stateDB . db . TrieDB ( ) . Reference ( account . Root , parent )
db . db . TrieDB ( ) . Reference ( account . Root , parent )
}
code := common . BytesToHash ( account . CodeHash )
if code != emptyCode {
stateDB . db . TrieDB ( ) . Reference ( code , parent )
db . db . TrieDB ( ) . Reference ( code , parent )
}
return nil
} )