diff options
Diffstat (limited to 'core/state/statedb.go')
-rw-r--r-- | core/state/statedb.go | 144 |
1 files changed, 85 insertions, 59 deletions
diff --git a/core/state/statedb.go b/core/state/statedb.go index 24f97e32a..ad673aecb 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -21,12 +21,17 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/trie" ) +// The starting nonce determines the default nonce when new accounts are being +// created. +var StartingNonce uint64 + // StateDBs within the ethereum protocol are used to store anything // within the merkle trie. StateDBs take care of caching and storing // nested states. It's the general query interface to retrieve: @@ -35,7 +40,6 @@ import ( type StateDB struct { db ethdb.Database trie *trie.SecureTrie - root common.Hash stateObjects map[string]*StateObject @@ -43,18 +47,25 @@ type StateDB struct { thash, bhash common.Hash txIndex int - logs map[common.Hash]Logs + logs map[common.Hash]vm.Logs logSize uint } // Create a new state from a given trie func New(root common.Hash, db ethdb.Database) *StateDB { - trie := trie.NewSecure(root[:], db) - return &StateDB{root: root, db: db, trie: trie, stateObjects: make(map[string]*StateObject), refund: new(big.Int), logs: make(map[common.Hash]Logs)} -} - -func (self *StateDB) PrintRoot() { - self.trie.Trie.PrintRoot() + tr, err := trie.NewSecure(root, db) + if err != nil { + // TODO: bubble this up + tr, _ = trie.NewSecure(common.Hash{}, db) + glog.Errorf("can't create state trie with root %x: %v", root[:], err) + } + return &StateDB{ + db: db, + trie: tr, + stateObjects: make(map[string]*StateObject), + refund: new(big.Int), + logs: make(map[common.Hash]vm.Logs), + } } func (self *StateDB) StartRecord(thash, bhash common.Hash, ti int) { @@ -63,7 +74,7 @@ func (self *StateDB) StartRecord(thash, bhash common.Hash, ti int) { self.txIndex = ti } -func (self *StateDB) AddLog(log *Log) { +func (self *StateDB) AddLog(log *vm.Log) { log.TxHash = self.thash log.BlockHash = self.bhash log.TxIndex = uint(self.txIndex) @@ -72,30 +83,34 @@ func (self *StateDB) AddLog(log *Log) { self.logSize++ } -func (self *StateDB) GetLogs(hash common.Hash) Logs { +func (self *StateDB) GetLogs(hash common.Hash) vm.Logs { return self.logs[hash] } -func (self *StateDB) Logs() Logs { - var logs Logs +func (self *StateDB) Logs() vm.Logs { + var logs vm.Logs for _, lgs := range self.logs { logs = append(logs, lgs...) } return logs } -func (self *StateDB) Refund(gas *big.Int) { +func (self *StateDB) AddRefund(gas *big.Int) { self.refund.Add(self.refund, gas) } -/* - * GETTERS - */ - func (self *StateDB) HasAccount(addr common.Address) bool { return self.GetStateObject(addr) != nil } +func (self *StateDB) Exist(addr common.Address) bool { + return self.GetStateObject(addr) != nil +} + +func (self *StateDB) GetAccount(addr common.Address) vm.Account { + return self.GetStateObject(addr) +} + // Retrieve the balance from the given address or 0 if object not found func (self *StateDB) GetBalance(addr common.Address) *big.Int { stateObject := self.GetStateObject(addr) @@ -196,7 +211,6 @@ func (self *StateDB) UpdateStateObject(stateObject *StateObject) { if len(stateObject.CodeHash()) > 0 { self.db.Put(stateObject.CodeHash(), stateObject.code) } - addr := stateObject.Address() self.trie.Update(addr[:], stateObject.RlpEncode()) } @@ -207,6 +221,7 @@ func (self *StateDB) DeleteStateObject(stateObject *StateObject) { addr := stateObject.Address() self.trie.Delete(addr[:]) + //delete(self.stateObjects, addr.Str()) } // Retrieve a state object given my the address. Nil if not found @@ -239,7 +254,7 @@ func (self *StateDB) SetStateObject(object *StateObject) { func (self *StateDB) GetOrNewStateObject(addr common.Address) *StateObject { stateObject := self.GetStateObject(addr) if stateObject == nil || stateObject.deleted { - stateObject = self.CreateAccount(addr) + stateObject = self.CreateStateObject(addr) } return stateObject @@ -252,13 +267,14 @@ func (self *StateDB) newStateObject(addr common.Address) *StateObject { } stateObject := NewStateObject(addr, self.db) + stateObject.SetNonce(StartingNonce) self.stateObjects[addr.Str()] = stateObject return stateObject } // Creates creates a new state object and takes ownership. This is different from "NewStateObject" -func (self *StateDB) CreateAccount(addr common.Address) *StateObject { +func (self *StateDB) CreateStateObject(addr common.Address) *StateObject { // Get previous (if any) so := self.GetStateObject(addr) // Create a new one @@ -272,6 +288,10 @@ func (self *StateDB) CreateAccount(addr common.Address) *StateObject { return newSo } +func (self *StateDB) CreateAccount(addr common.Address) vm.Account { + return self.CreateStateObject(addr) +} + // // Setting, copying of the state methods // @@ -286,7 +306,7 @@ func (self *StateDB) Copy() *StateDB { state.refund.Set(self.refund) for hash, logs := range self.logs { - state.logs[hash] = make(Logs, len(logs)) + state.logs[hash] = make(vm.Logs, len(logs)) copy(state.logs[hash], logs) } state.logSize = self.logSize @@ -303,65 +323,71 @@ func (self *StateDB) Set(state *StateDB) { self.logSize = state.logSize } -func (s *StateDB) Root() common.Hash { - return common.BytesToHash(s.trie.Root()) -} - -// Syncs the trie and all siblings -func (s *StateDB) Sync() { - // Sync all nested states - for _, stateObject := range s.stateObjects { - stateObject.trie.Commit() - } - - s.trie.Commit() - - s.Empty() -} - -func (self *StateDB) Empty() { - self.stateObjects = make(map[string]*StateObject) - self.refund = new(big.Int) -} - -func (self *StateDB) Refunds() *big.Int { +func (self *StateDB) GetRefund() *big.Int { return self.refund } -// SyncIntermediate updates the intermediate state and all mid steps -func (self *StateDB) SyncIntermediate() { - self.refund = new(big.Int) - - for _, stateObject := range self.stateObjects { +// 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 (s *StateDB) IntermediateRoot() common.Hash { + s.refund = new(big.Int) + for _, stateObject := range s.stateObjects { if stateObject.dirty { if stateObject.remove { - self.DeleteStateObject(stateObject) + s.DeleteStateObject(stateObject) } else { stateObject.Update() - - self.UpdateStateObject(stateObject) + s.UpdateStateObject(stateObject) } stateObject.dirty = false } } + return s.trie.Hash() } -// SyncObjects syncs the changed objects to the trie -func (self *StateDB) SyncObjects() { - self.trie = trie.NewSecure(self.root[:], self.db) +// Commit commits all state changes to the database. +func (s *StateDB) Commit() (root common.Hash, err error) { + return s.commit(s.db) +} - self.refund = new(big.Int) +// CommitBatch commits all state changes to a write batch but does not +// execute the batch. It is used to validate state changes against +// the root hash stored in a block. +func (s *StateDB) CommitBatch() (root common.Hash, batch ethdb.Batch) { + batch = s.db.NewBatch() + root, _ = s.commit(batch) + return root, batch +} - for _, stateObject := range self.stateObjects { +func (s *StateDB) commit(db trie.DatabaseWriter) (common.Hash, error) { + s.refund = new(big.Int) + + for _, stateObject := range s.stateObjects { if stateObject.remove { - self.DeleteStateObject(stateObject) + // If the object has been removed, don't bother syncing it + // and just mark it for deletion in the trie. + s.DeleteStateObject(stateObject) } else { + // Write any storage changes in the state object to its trie. stateObject.Update() - - self.UpdateStateObject(stateObject) + // 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 + } + // Update the object in the account trie. + s.UpdateStateObject(stateObject) } stateObject.dirty = false } + return s.trie.CommitTo(db) +} + +func (self *StateDB) Refunds() *big.Int { + return self.refund } // Debug stuff |