@ -43,8 +43,14 @@ type StateDB struct {
db ethdb . Database
db ethdb . Database
trie * trie . SecureTrie
trie * trie . SecureTrie
stateObjects map [ string ] * StateObject
// This map caches canon state accounts.
all map [ common . Address ] Account
// This map holds 'live' objects, which will get modified while processing a state transition.
stateObjects map [ common . Address ] * StateObject
stateObjectsDirty map [ common . Address ] struct { }
// The refund counter, also used by state transitioning.
refund * big . Int
refund * big . Int
thash , bhash common . Hash
thash , bhash common . Hash
@ -62,7 +68,9 @@ func New(root common.Hash, db ethdb.Database) (*StateDB, error) {
return & StateDB {
return & StateDB {
db : db ,
db : db ,
trie : tr ,
trie : tr ,
stateObjects : make ( map [ string ] * StateObject ) ,
all : make ( map [ common . Address ] Account ) ,
stateObjects : make ( map [ common . Address ] * StateObject ) ,
stateObjectsDirty : make ( map [ common . Address ] struct { } ) ,
refund : new ( big . Int ) ,
refund : new ( big . Int ) ,
logs : make ( map [ common . Hash ] vm . Logs ) ,
logs : make ( map [ common . Hash ] vm . Logs ) ,
} , nil
} , nil
@ -71,19 +79,21 @@ func New(root common.Hash, db ethdb.Database) (*StateDB, error) {
// Reset clears out all emphemeral state objects from the state db, but keeps
// Reset clears out all emphemeral state objects from the state db, but keeps
// the underlying state trie to avoid reloading data for the next operations.
// the underlying state trie to avoid reloading data for the next operations.
func ( self * StateDB ) Reset ( root common . Hash ) error {
func ( self * StateDB ) Reset ( root common . Hash ) error {
var (
tr , err := trie . NewSecure ( root , self . db )
err error
if err != nil {
tr = self . trie
)
if self . trie . Hash ( ) != root {
if tr , err = trie . NewSecure ( root , self . db ) ; err != nil {
return err
return err
}
}
all := self . all
if self . trie . Hash ( ) != root {
// The root has changed, invalidate canon state.
all = make ( map [ common . Address ] Account )
}
}
* self = StateDB {
* self = StateDB {
db : self . db ,
db : self . db ,
trie : tr ,
trie : tr ,
stateObjects : make ( map [ string ] * StateObject ) ,
all : all ,
stateObjects : make ( map [ common . Address ] * StateObject ) ,
stateObjectsDirty : make ( map [ common . Address ] struct { } ) ,
refund : new ( big . Int ) ,
refund : new ( big . Int ) ,
logs : make ( map [ common . Hash ] vm . Logs ) ,
logs : make ( map [ common . Hash ] vm . Logs ) ,
}
}
@ -137,7 +147,7 @@ func (self *StateDB) GetAccount(addr common.Address) vm.Account {
func ( self * StateDB ) GetBalance ( addr common . Address ) * big . Int {
func ( self * StateDB ) GetBalance ( addr common . Address ) * big . Int {
stateObject := self . GetStateObject ( addr )
stateObject := self . GetStateObject ( addr )
if stateObject != nil {
if stateObject != nil {
return stateObject . balance
return stateObject . Balance ( )
}
}
return common . Big0
return common . Big0
@ -146,7 +156,7 @@ func (self *StateDB) GetBalance(addr common.Address) *big.Int {
func ( self * StateDB ) GetNonce ( addr common . Address ) uint64 {
func ( self * StateDB ) GetNonce ( addr common . Address ) uint64 {
stateObject := self . GetStateObject ( addr )
stateObject := self . GetStateObject ( addr )
if stateObject != nil {
if stateObject != nil {
return stateObject . nonce
return stateObject . Nonce ( )
}
}
return StartingNonce
return StartingNonce
@ -155,18 +165,24 @@ func (self *StateDB) GetNonce(addr common.Address) uint64 {
func ( self * StateDB ) GetCode ( addr common . Address ) [ ] byte {
func ( self * StateDB ) GetCode ( addr common . Address ) [ ] byte {
stateObject := self . GetStateObject ( addr )
stateObject := self . GetStateObject ( addr )
if stateObject != nil {
if stateObject != nil {
return stateObject . code
return stateObject . Code ( self . db )
}
}
return nil
return nil
}
}
func ( self * StateDB ) GetCodeSize ( addr common . Address ) int {
stateObject := self . GetStateObject ( addr )
if stateObject != nil {
return stateObject . CodeSize ( self . db )
}
return 0
}
func ( self * StateDB ) GetState ( a common . Address , b common . Hash ) common . Hash {
func ( self * StateDB ) GetState ( a common . Address , b common . Hash ) common . Hash {
stateObject := self . GetStateObject ( a )
stateObject := self . GetStateObject ( a )
if stateObject != nil {
if stateObject != nil {
return stateObject . GetState ( b )
return stateObject . GetState ( self . db , b )
}
}
return common . Hash { }
return common . Hash { }
}
}
@ -214,8 +230,7 @@ func (self *StateDB) Delete(addr common.Address) bool {
stateObject := self . GetStateObject ( addr )
stateObject := self . GetStateObject ( addr )
if stateObject != nil {
if stateObject != nil {
stateObject . MarkForDeletion ( )
stateObject . MarkForDeletion ( )
stateObject . balance = new ( big . Int )
stateObject . data . Balance = new ( big . Int )
return true
return true
}
}
@ -242,35 +257,47 @@ func (self *StateDB) DeleteStateObject(stateObject *StateObject) {
addr := stateObject . Address ( )
addr := stateObject . Address ( )
self . trie . Delete ( addr [ : ] )
self . trie . Delete ( addr [ : ] )
//delete(self.stateObjects, addr.Str())
}
}
// Retrieve a state object given my the address. Nil if not found
// Retrieve a state object given my the address. Returns nil if not found.
func ( self * StateDB ) GetStateObject ( addr common . Address ) ( stateObject * StateObject ) {
func ( self * StateDB ) GetStateObject ( addr common . Address ) ( stateObject * StateObject ) {
stateObject = self . stateObjects [ addr . Str ( ) ]
// Prefer 'live' objects.
if stateObject != nil {
if obj := self . stateObjects [ addr ] ; obj != nil {
if stateObject . deleted {
if obj . deleted {
stateObject = nil
return nil
}
return obj
}
}
return stateObject
// Use cached account data from the canon state if possible.
if data , ok := self . all [ addr ] ; ok {
obj := NewObject ( addr , data , self . MarkStateObjectDirty )
self . SetStateObject ( obj )
return obj
}
}
data := self . trie . Get ( addr [ : ] )
// Load the object from the database.
if len ( data ) == 0 {
enc := self . trie . Get ( addr [ : ] )
if len ( enc ) == 0 {
return nil
return nil
}
}
stateObject , err := DecodeObject ( addr , self . db , data )
var data Account
if err != nil {
if err := rlp . DecodeBytes ( enc , & data ) ; err != nil {
glog . Errorf ( "can't decode object at %x: %v" , addr [ : ] , err )
glog . Errorf ( "can't decode object at %x: %v" , addr [ : ] , err )
return nil
return nil
}
}
self . SetStateObject ( stateObject )
// Update the all cache. Content in DB always corresponds
return stateObject
// to the current head state so this is ok to do here.
// The object we just loaded has no storage trie and code yet.
self . all [ addr ] = data
// Insert into the live set.
obj := NewObject ( addr , data , self . MarkStateObjectDirty )
self . SetStateObject ( obj )
return obj
}
}
func ( self * StateDB ) SetStateObject ( object * StateObject ) {
func ( self * StateDB ) SetStateObject ( object * StateObject ) {
self . stateObjects [ object . Address ( ) . Str ( ) ] = object
self . stateObjects [ object . Address ( ) ] = object
}
}
// Retrieve a state object or create a new state object if nil
// Retrieve a state object or create a new state object if nil
@ -288,15 +315,19 @@ func (self *StateDB) newStateObject(addr common.Address) *StateObject {
if glog . V ( logger . Core ) {
if glog . V ( logger . Core ) {
glog . Infof ( "(+) %x\n" , addr )
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
}
stateObject := NewStateObject ( addr , self . db )
// MarkStateObjectDirty adds the specified object to the dirty map to avoid costly
stateObject . SetNonce ( StartingNonce )
// state object cache iteration to find a handful of modified ones.
self . stateObjects [ addr . Str ( ) ] = stateObject
func ( self * StateDB ) MarkStateObjectDirty ( addr common . Address ) {
self . stateObjectsDirty [ addr ] = struct { } { }
return stateObject
}
}
// Creates creates a new state object and takes ownership. This is different from "NewStateObject"
// Creates creates a new state object and takes ownership.
func ( self * StateDB ) CreateStateObject ( addr common . Address ) * StateObject {
func ( self * StateDB ) CreateStateObject ( addr common . Address ) * StateObject {
// Get previous (if any)
// Get previous (if any)
so := self . GetStateObject ( addr )
so := self . GetStateObject ( addr )
@ -305,7 +336,7 @@ func (self *StateDB) CreateStateObject(addr common.Address) *StateObject {
// If it existed set the balance to the new account
// If it existed set the balance to the new account
if so != nil {
if so != nil {
newSo . b alance = so . b alance
newSo . data . B alance = so . data . B alance
}
}
return newSo
return newSo
@ -320,29 +351,34 @@ func (self *StateDB) CreateAccount(addr common.Address) vm.Account {
//
//
func ( self * StateDB ) Copy ( ) * StateDB {
func ( self * StateDB ) Copy ( ) * StateDB {
// ignore error - we assume state-to-be-copied always exists
// Copy all the basic fields, initialize the memory ones
state , _ := New ( common . Hash { } , self . db )
state := & StateDB {
state . trie = self . trie
db : self . db ,
for k , stateObject := range self . stateObjects {
trie : self . trie ,
if stateObject . dirty {
all : self . all ,
state . stateObjects [ k ] = stateObject . Copy ( )
stateObjects : make ( map [ common . Address ] * StateObject , len ( self . stateObjectsDirty ) ) ,
}
stateObjectsDirty : make ( map [ common . Address ] struct { } , len ( self . stateObjectsDirty ) ) ,
refund : new ( big . Int ) . Set ( self . refund ) ,
logs : make ( map [ common . Hash ] vm . Logs , len ( self . logs ) ) ,
logSize : self . logSize ,
}
// Copy the dirty states and logs
for addr , _ := range self . stateObjectsDirty {
state . stateObjects [ addr ] = self . stateObjects [ addr ] . Copy ( self . db , state . MarkStateObjectDirty )
state . stateObjectsDirty [ addr ] = struct { } { }
}
}
state . refund . Set ( self . refund )
for hash , logs := range self . logs {
for hash , logs := range self . logs {
state . logs [ hash ] = make ( vm . Logs , len ( logs ) )
state . logs [ hash ] = make ( vm . Logs , len ( logs ) )
copy ( state . logs [ hash ] , logs )
copy ( state . logs [ hash ] , logs )
}
}
state . logSize = self . logSize
return state
return state
}
}
func ( self * StateDB ) Set ( state * StateDB ) {
func ( self * StateDB ) Set ( state * StateDB ) {
self . trie = state . trie
self . trie = state . trie
self . stateObjects = state . stateObjects
self . stateObjects = state . stateObjects
self . stateObjectsDirty = state . stateObjectsDirty
self . all = state . all
self . refund = state . refund
self . refund = state . refund
self . logs = state . logs
self . logs = state . logs
@ -358,16 +394,15 @@ func (self *StateDB) GetRefund() *big.Int {
// 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 )
s . refund = new ( big . Int )
for _ , stateObject := range s . stateObjects {
for addr , _ := range s . stateObjectsDirty {
if stateObject . dirty {
stateObject := s . stateObjects [ addr ]
if stateObject . remove {
if stateObject . remove {
s . DeleteStateObject ( stateObject )
s . DeleteStateObject ( stateObject )
} else {
} else {
stateObject . Update ( )
stateObject . UpdateRoot ( s . db )
s . UpdateStateObject ( stateObject )
s . UpdateStateObject ( stateObject )
}
}
}
}
}
return s . trie . Hash ( )
return s . trie . Hash ( )
}
}
@ -380,15 +415,15 @@ 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 . refund = new ( big . Int )
s . refund = new ( big . Int )
for _ , stateObject := range s . stateObjects {
for addr , _ := range s . stateObjectsDirty {
if stateObject . dirty {
stateObject := s . stateObjects [ addr ]
// If the object has been removed by a suicide
// If the object has been removed by a suicide
// flag the object as deleted.
// flag the object as deleted.
if stateObject . remove {
if stateObject . remove {
stateObject . deleted = true
stateObject . deleted = true
}
}
stateObject . dirty = false
delete ( s . stateObjectsDirty , addr )
}
}
}
}
}
@ -407,46 +442,44 @@ func (s *StateDB) CommitBatch() (root common.Hash, batch ethdb.Batch) {
return root , batch
return root , batch
}
}
func ( s * StateDB ) commit ( db trie . DatabaseWriter ) ( common . Hash , error ) {
func ( s * StateDB ) commit ( dbw trie . DatabaseWriter ) ( root common . Hash , err error ) {
s . refund = new ( big . Int )
s . refund = new ( big . Int )
defer func ( ) {
if err != nil {
// Committing failed, any updates to the canon state are invalid.
s . all = make ( map [ common . Address ] Account )
}
} ( )
for _ , stateObject := range s . stateObjects {
// Commit objects to the trie.
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 . DeleteStateObject ( stateObject )
s . DeleteStateObject ( stateObject )
} else {
delete ( s . all , addr )
} 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 len ( stateObject . code ) > 0 {
if stateObject . code != nil && stateObject . dirtyCode {
if err := db . Put ( stateObject . codeHash , stateObject . code ) ; err != nil {
if err := dbw . Put ( stateObject . CodeHash ( ) , stateObject . code ) ; err != nil {
return common . Hash { } , err
return common . Hash { } , err
}
}
stateObject . dirtyCode = false
}
}
// Write any storage changes in the state object to its trie.
// Write any storage changes in the state object to its storage trie.
stateObject . Update ( )
if err := stateObject . CommitTrie ( s . db , dbw ) ; err != nil {
// Commit the trie of the object to the batch.
// This updates the trie root internally, so
// getting the root hash of the storage trie
// through UpdateStateObject is fast.
if _ , err := stateObject . trie . CommitTo ( db ) ; err != nil {
return common . Hash { } , err
return common . Hash { } , err
}
}
// Update the object in the account trie.
// Update the object in the main account trie.
s . UpdateStateObject ( stateObject )
s . UpdateStateObject ( stateObject )
s . all [ addr ] = stateObject . data
}
}
stateObject . dirty = false
delete ( s . stateObjectsDirty , addr )
}
}
return s . trie . CommitTo ( db )
// Write trie changes.
return s . trie . CommitTo ( dbw )
}
}
func ( self * StateDB ) Refunds ( ) * big . Int {
func ( self * StateDB ) Refunds ( ) * big . Int {
return self . refund
return self . refund
}
}
// Debug stuff
func ( self * StateDB ) CreateOutputForDiff ( ) {
for _ , stateObject := range self . stateObjects {
stateObject . CreateOutputForDiff ( )
}
}