@ -20,6 +20,7 @@ package state
import (
import (
"fmt"
"fmt"
"math/big"
"math/big"
"sort"
"sync"
"sync"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common"
@ -40,12 +41,17 @@ var StartingNonce uint64
const (
const (
// Number of past tries to keep. The arbitrarily chosen value here
// Number of past tries to keep. The arbitrarily chosen value here
// is max uncle depth + 1.
// is max uncle depth + 1.
maxJournal Length = 8
maxTrieCache Length = 8
// Number of codehash->size associations to keep.
// Number of codehash->size associations to keep.
codeSizeCacheSize = 100000
codeSizeCacheSize = 100000
)
)
type revision struct {
id int
journalIndex int
}
// StateDBs within the ethereum protocol are used to store anything
// StateDBs within the ethereum protocol are used to store anything
// within the merkle trie. StateDBs take care of caching and storing
// within the merkle trie. StateDBs take care of caching and storing
// nested states. It's the general query interface to retrieve:
// nested states. It's the general query interface to retrieve:
@ -69,6 +75,12 @@ type StateDB struct {
logs map [ common . Hash ] vm . Logs
logs map [ common . Hash ] vm . Logs
logSize uint
logSize uint
// Journal of state modifications. This is the backbone of
// Snapshot and RevertToSnapshot.
journal journal
validRevisions [ ] revision
nextRevisionId int
lock sync . Mutex
lock sync . Mutex
}
}
@ -124,12 +136,12 @@ func (self *StateDB) Reset(root common.Hash) error {
self . trie = tr
self . trie = tr
self . stateObjects = make ( map [ common . Address ] * StateObject )
self . stateObjects = make ( map [ common . Address ] * StateObject )
self . stateObjectsDirty = make ( map [ common . Address ] struct { } )
self . stateObjectsDirty = make ( map [ common . Address ] struct { } )
self . refund = new ( big . Int )
self . thash = common . Hash { }
self . thash = common . Hash { }
self . bhash = common . Hash { }
self . bhash = common . Hash { }
self . txIndex = 0
self . txIndex = 0
self . logs = make ( map [ common . Hash ] vm . Logs )
self . logs = make ( map [ common . Hash ] vm . Logs )
self . logSize = 0
self . logSize = 0
self . clearJournalAndRefund ( )
return nil
return nil
}
}
@ -150,7 +162,7 @@ func (self *StateDB) pushTrie(t *trie.SecureTrie) {
self . lock . Lock ( )
self . lock . Lock ( )
defer self . lock . Unlock ( )
defer self . lock . Unlock ( )
if len ( self . pastTries ) >= maxJournal Length {
if len ( self . pastTries ) >= maxTrieCache Length {
copy ( self . pastTries , self . pastTries [ 1 : ] )
copy ( self . pastTries , self . pastTries [ 1 : ] )
self . pastTries [ len ( self . pastTries ) - 1 ] = t
self . pastTries [ len ( self . pastTries ) - 1 ] = t
} else {
} else {
@ -165,6 +177,8 @@ func (self *StateDB) StartRecord(thash, bhash common.Hash, ti int) {
}
}
func ( self * StateDB ) AddLog ( log * vm . Log ) {
func ( self * StateDB ) AddLog ( log * vm . Log ) {
self . journal = append ( self . journal , addLogChange { txhash : self . thash } )
log . TxHash = self . thash
log . TxHash = self . thash
log . BlockHash = self . bhash
log . BlockHash = self . bhash
log . TxIndex = uint ( self . txIndex )
log . TxIndex = uint ( self . txIndex )
@ -186,13 +200,12 @@ func (self *StateDB) Logs() vm.Logs {
}
}
func ( self * StateDB ) AddRefund ( gas * big . Int ) {
func ( self * StateDB ) AddRefund ( gas * big . Int ) {
self . journal = append ( self . journal , refundChange { prev : new ( big . Int ) . Set ( self . refund ) } )
self . refund . Add ( self . refund , gas )
self . refund . Add ( self . refund , gas )
}
}
func ( self * StateDB ) HasAccount ( addr common . Address ) bool {
// Exist reports whether the given account address exists in the state.
return self . GetStateObject ( addr ) != nil
// Notably this also returns true for suicided accounts.
}
func ( self * StateDB ) Exist ( addr common . Address ) bool {
func ( self * StateDB ) Exist ( addr common . Address ) bool {
return self . GetStateObject ( addr ) != nil
return self . GetStateObject ( addr ) != nil
}
}
@ -207,7 +220,6 @@ func (self *StateDB) GetBalance(addr common.Address) *big.Int {
if stateObject != nil {
if stateObject != nil {
return stateObject . Balance ( )
return stateObject . Balance ( )
}
}
return common . Big0
return common . Big0
}
}
@ -282,6 +294,13 @@ func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) {
}
}
}
}
func ( self * StateDB ) SetBalance ( addr common . Address , amount * big . Int ) {
stateObject := self . GetOrNewStateObject ( addr )
if stateObject != nil {
stateObject . SetBalance ( amount )
}
}
func ( self * StateDB ) SetNonce ( addr common . Address , nonce uint64 ) {
func ( self * StateDB ) SetNonce ( addr common . Address , nonce uint64 ) {
stateObject := self . GetOrNewStateObject ( addr )
stateObject := self . GetOrNewStateObject ( addr )
if stateObject != nil {
if stateObject != nil {
@ -299,27 +318,36 @@ func (self *StateDB) SetCode(addr common.Address, code []byte) {
func ( self * StateDB ) SetState ( addr common . Address , key common . Hash , value common . Hash ) {
func ( self * StateDB ) SetState ( addr common . Address , key common . Hash , value common . Hash ) {
stateObject := self . GetOrNewStateObject ( addr )
stateObject := self . GetOrNewStateObject ( addr )
if stateObject != nil {
if stateObject != nil {
stateObject . SetState ( key , value )
stateObject . SetState ( self . db , key , value )
}
}
}
}
// Delete marks the given account as suicided.
// This clears the account balance.
//
// The account's state object is still available until the state is committed,
// GetStateObject will return a non-nil account after Delete.
func ( self * StateDB ) Delete ( addr common . Address ) bool {
func ( self * StateDB ) Delete ( addr common . Address ) bool {
stateObject := self . GetStateObject ( addr )
stateObject := self . GetStateObject ( addr )
if stateObject != nil {
if stateObject == nil {
stateObject . MarkForDeletion ( )
return false
stateObject . data . Balance = new ( big . Int )
return true
}
}
self . journal = append ( self . journal , deleteAccountChange {
return false
account : & addr ,
prev : stateObject . remove ,
prevbalance : new ( big . Int ) . Set ( stateObject . Balance ( ) ) ,
} )
stateObject . markForDeletion ( )
stateObject . data . Balance = new ( big . Int )
return true
}
}
//
//
// Setting, updating & deleting state object methods
// Setting, updating & deleting state object methods
//
//
// Update the given state object and apply it to state trie
// updateStateObject writes the given object to the trie.
func ( self * StateDB ) U pdateStateObject( stateObject * StateObject ) {
func ( self * StateDB ) u pdateStateObject( stateObject * StateObject ) {
addr := stateObject . Address ( )
addr := stateObject . Address ( )
data , err := rlp . EncodeToBytes ( stateObject )
data , err := rlp . EncodeToBytes ( stateObject )
if err != nil {
if err != nil {
@ -328,10 +356,9 @@ func (self *StateDB) UpdateStateObject(stateObject *StateObject) {
self . trie . Update ( addr [ : ] , data )
self . trie . Update ( addr [ : ] , data )
}
}
// Delete the given state object and delete it from the state trie
// deleteStateObject removes the given object from the state trie.
func ( self * StateDB ) D eleteStateObject( stateObject * StateObject ) {
func ( self * StateDB ) d eleteStateObject( stateObject * StateObject ) {
stateObject . deleted = true
stateObject . deleted = true
addr := stateObject . Address ( )
addr := stateObject . Address ( )
self . trie . Delete ( addr [ : ] )
self . trie . Delete ( addr [ : ] )
}
}
@ -357,12 +384,12 @@ func (self *StateDB) GetStateObject(addr common.Address) (stateObject *StateObje
return nil
return nil
}
}
// Insert into the live set.
// Insert into the live set.
obj := NewObject ( addr , data , self . MarkStateObjectDirty )
obj := newObject ( self , addr , data , self . MarkStateObjectDirty )
self . S etStateObject( obj )
self . s etStateObject( obj )
return obj
return obj
}
}
func ( self * StateDB ) S etStateObject( object * StateObject ) {
func ( self * StateDB ) s etStateObject( object * StateObject ) {
self . stateObjects [ object . Address ( ) ] = object
self . stateObjects [ object . Address ( ) ] = object
}
}
@ -370,52 +397,55 @@ func (self *StateDB) SetStateObject(object *StateObject) {
func ( self * StateDB ) GetOrNewStateObject ( addr common . Address ) * StateObject {
func ( self * StateDB ) GetOrNewStateObject ( addr common . Address ) * StateObject {
stateObject := self . GetStateObject ( addr )
stateObject := self . GetStateObject ( addr )
if stateObject == nil || stateObject . deleted {
if stateObject == nil || stateObject . deleted {
stateObject = self . CreateSt ateObject( addr )
stateObject , _ = self . cre ateObject( addr )
}
}
return stateObject
return stateObject
}
}
// NewStateObject create a state object whether it exist in the trie or not
func ( self * StateDB ) newStateObject ( addr common . Address ) * StateObject {
if glog . V ( logger . Core ) {
glog . Infof ( "(+) %x\n" , addr )
}
obj := NewObject ( addr , Account { } , self . MarkStateObjectDirty )
obj . SetNonce ( StartingNonce ) // sets the object to dirty
self . stateObjects [ addr ] = obj
return obj
}
// MarkStateObjectDirty adds the specified object to the dirty map to avoid costly
// MarkStateObjectDirty adds the specified object to the dirty map to avoid costly
// state object cache iteration to find a handful of modified ones.
// state object cache iteration to find a handful of modified ones.
func ( self * StateDB ) MarkStateObjectDirty ( addr common . Address ) {
func ( self * StateDB ) MarkStateObjectDirty ( addr common . Address ) {
self . stateObjectsDirty [ addr ] = struct { } { }
self . stateObjectsDirty [ addr ] = struct { } { }
}
}
// Creates creates a new state object and takes ownership.
// createObject creates a new state object. If there is an existing account with
func ( self * StateDB ) CreateStateObject ( addr common . Address ) * StateObject {
// the given address, it is overwritten and returned as the second return value.
// Get previous (if any)
func ( self * StateDB ) createObject ( addr common . Address ) ( newobj , prev * StateObject ) {
so := self . GetStateObject ( addr )
prev = self . GetStateObject ( addr )
// Create a new one
newobj = newObject ( self , addr , Account { } , self . MarkStateObjectDirty )
newSo := self . newStateObject ( addr )
newobj . setNonce ( StartingNonce ) // sets the object to dirty
if prev == nil {
// If it existed set the balance to the new account
if glog . V ( logger . Core ) {
if so != nil {
glog . Infof ( "(+) %x\n" , addr )
newSo . data . Balance = so . data . Balance
}
self . journal = append ( self . journal , createObjectChange { account : & addr } )
} else {
self . journal = append ( self . journal , resetObjectChange { prev : prev } )
}
}
self . setStateObject ( newobj )
return newSo
return newobj , prev
}
func ( self * StateDB ) CreateAccount ( addr common . Address ) vm . Account {
return self . CreateStateObject ( addr )
}
}
// CreateAccount explicitly creates a state object. If a state object with the address
// already exists the balance is carried over to the new account.
//
// CreateAccount is called during the EVM CREATE operation. The situation might arise that
// a contract does the following:
//
//
// Setting, copying of the state methods
// 1. sends funds to sha(account ++ (nonce + 1))
// 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 ( self * StateDB ) CreateAccount ( addr common . Address ) vm . Account {
new , prev := self . createObject ( addr )
if prev != nil {
new . setBalance ( prev . data . Balance )
}
return new
}
// Copy creates a deep, independent copy of the state.
// Snapshots of the copied state cannot be applied to the copy.
func ( self * StateDB ) Copy ( ) * StateDB {
func ( self * StateDB ) Copy ( ) * StateDB {
self . lock . Lock ( )
self . lock . Lock ( )
defer self . lock . Unlock ( )
defer self . lock . Unlock ( )
@ -434,7 +464,7 @@ func (self *StateDB) Copy() *StateDB {
}
}
// Copy the dirty states and logs
// Copy the dirty states and logs
for addr , _ := range self . stateObjectsDirty {
for addr , _ := range self . stateObjectsDirty {
state . stateObjects [ addr ] = self . stateObjects [ addr ] . Copy ( self . db , state . MarkStateObjectDirty )
state . stateObjects [ addr ] = self . stateObjects [ addr ] . deep Copy( state , state . MarkStateObjectDirty )
state . stateObjectsDirty [ addr ] = struct { } { }
state . stateObjectsDirty [ addr ] = struct { } { }
}
}
for hash , logs := range self . logs {
for hash , logs := range self . logs {
@ -444,21 +474,38 @@ func (self *StateDB) Copy() *StateDB {
return state
return state
}
}
func ( self * StateDB ) Set ( state * StateDB ) {
// Snapshot returns an identifier for the current revision of the state.
self . lock . Lock ( )
func ( self * StateDB ) Snapshot ( ) int {
defer self . lock . Unlock ( )
id := self . nextRevisionId
self . nextRevisionId ++
self . validRevisions = append ( self . validRevisions , revision { id , len ( self . journal ) } )
return id
}
// RevertToSnapshot reverts all state changes made since the given revision.
func ( self * StateDB ) RevertToSnapshot ( revid int ) {
// Find the snapshot in the stack of valid snapshots.
idx := sort . Search ( len ( self . validRevisions ) , func ( i int ) bool {
return self . validRevisions [ i ] . id >= revid
} )
if idx == len ( self . validRevisions ) || self . validRevisions [ idx ] . id != revid {
panic ( fmt . Errorf ( "revision id %v cannot be reverted" , revid ) )
}
snapshot := self . validRevisions [ idx ] . journalIndex
// Replay the journal to undo changes.
for i := len ( self . journal ) - 1 ; i >= snapshot ; i -- {
self . journal [ i ] . undo ( self )
}
self . journal = self . journal [ : snapshot ]
self . db = state . db
// Remove invalidated snapshots from the stack.
self . trie = state . trie
self . validRevisions = self . validRevisions [ : idx ]
self . pastTries = state . pastTries
self . stateObjects = state . stateObjects
self . stateObjectsDirty = state . stateObjectsDirty
self . codeSizeCache = state . codeSizeCache
self . refund = state . refund
self . logs = state . logs
self . logSize = state . logSize
}
}
// GetRefund returns the current value of the refund counter.
// The return value must not be modified by the caller and will become
// invalid at the next call to AddRefund.
func ( self * StateDB ) GetRefund ( ) * big . Int {
func ( self * StateDB ) GetRefund ( ) * big . Int {
return self . refund
return self . refund
}
}
@ -467,16 +514,17 @@ func (self *StateDB) GetRefund() *big.Int {
// It is called in between transactions to get the root hash that
// It is called in between transactions to get the root hash that
// goes into transaction receipts.
// goes into transaction receipts.
func ( s * StateDB ) IntermediateRoot ( ) common . Hash {
func ( s * StateDB ) IntermediateRoot ( ) common . Hash {
s . refund = new ( big . Int )
for addr , _ := range s . stateObjectsDirty {
for addr , _ := range s . stateObjectsDirty {
stateObject := s . stateObjects [ addr ]
stateObject := s . stateObjects [ addr ]
if stateObject . remove {
if stateObject . remove {
s . D eleteStateObject( stateObject )
s . d eleteStateObject( stateObject )
} else {
} else {
stateObject . U pdateRoot( s . db )
stateObject . u pdateRoot( s . db )
s . U pdateStateObject( stateObject )
s . u pdateStateObject( stateObject )
}
}
}
}
// Invalidate journal because reverting across transactions is not allowed.
s . clearJournalAndRefund ( )
return s . trie . Hash ( )
return s . trie . Hash ( )
}
}
@ -486,9 +534,9 @@ func (s *StateDB) IntermediateRoot() common.Hash {
// DeleteSuicides should not be used for consensus related updates
// DeleteSuicides should not be used for consensus related updates
// under any circumstances.
// under any circumstances.
func ( s * StateDB ) DeleteSuicides ( ) {
func ( s * StateDB ) DeleteSuicides ( ) {
// Reset refund so that any used-gas calculations can use
// Reset refund so that any used-gas calculations can use this method.
// this method.
s . clearJournalAndRefund ( )
s . refund = new ( big . Int )
for addr , _ := range s . stateObjectsDirty {
for addr , _ := range s . stateObjectsDirty {
stateObject := s . stateObjects [ addr ]
stateObject := s . stateObjects [ addr ]
@ -516,15 +564,21 @@ func (s *StateDB) CommitBatch() (root common.Hash, batch ethdb.Batch) {
return root , batch
return root , batch
}
}
func ( s * StateDB ) commit ( dbw trie . DatabaseWriter ) ( root common . Hash , err error ) {
func ( s * StateDB ) clearJournalAndRefund ( ) {
s . journal = nil
s . validRevisions = s . validRevisions [ : 0 ]
s . refund = new ( big . Int )
s . refund = new ( big . Int )
}
func ( s * StateDB ) commit ( dbw trie . DatabaseWriter ) ( root common . Hash , err error ) {
defer s . clearJournalAndRefund ( )
// Commit objects to the trie.
// Commit objects to the trie.
for addr , stateObject := range s . stateObjects {
for addr , stateObject := range s . stateObjects {
if stateObject . remove {
if stateObject . remove {
// If the object has been removed, don't bother syncing it
// If the object has been removed, don't bother syncing it
// and just mark it for deletion in the trie.
// and just mark it for deletion in the trie.
s . D eleteStateObject( stateObject )
s . d eleteStateObject( stateObject )
} else if _ , ok := s . stateObjectsDirty [ addr ] ; ok {
} else if _ , ok := s . stateObjectsDirty [ addr ] ; ok {
// Write any contract code associated with the state object
// Write any contract code associated with the state object
if stateObject . code != nil && stateObject . dirtyCode {
if stateObject . code != nil && stateObject . dirtyCode {
@ -538,7 +592,7 @@ func (s *StateDB) commit(dbw trie.DatabaseWriter) (root common.Hash, err error)
return common . Hash { } , err
return common . Hash { } , err
}
}
// Update the object in the main account trie.
// Update the object in the main account trie.
s . U pdateStateObject( stateObject )
s . u pdateStateObject( stateObject )
}
}
delete ( s . stateObjectsDirty , addr )
delete ( s . stateObjectsDirty , addr )
}
}
@ -549,7 +603,3 @@ func (s *StateDB) commit(dbw trie.DatabaseWriter) (root common.Hash, err error)
}
}
return root , err
return root , err
}
}
func ( self * StateDB ) Refunds ( ) * big . Int {
return self . refund
}