aboutsummaryrefslogtreecommitdiffstats
path: root/core/state/statedb.go
diff options
context:
space:
mode:
Diffstat (limited to 'core/state/statedb.go')
-rw-r--r--core/state/statedb.go144
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