aboutsummaryrefslogtreecommitdiffstats
path: root/core/state
diff options
context:
space:
mode:
authorFelix Lange <fjl@twurst.com>2015-08-18 20:14:45 +0800
committerFelix Lange <fjl@twurst.com>2015-09-23 04:57:37 +0800
commita2d5a60418e70ce56112381dffdd121cc678a1b6 (patch)
treec9733cb16b7ca5bac98d6ae11254def5a48aafb8 /core/state
parent565d9f2306d19f63be6a6e1b8fc480af8dca9617 (diff)
downloaddexon-a2d5a60418e70ce56112381dffdd121cc678a1b6.tar.gz
dexon-a2d5a60418e70ce56112381dffdd121cc678a1b6.tar.zst
dexon-a2d5a60418e70ce56112381dffdd121cc678a1b6.zip
core, core/state: batch-based state sync
Diffstat (limited to 'core/state')
-rw-r--r--core/state/state_object.go8
-rw-r--r--core/state/state_test.go3
-rw-r--r--core/state/statedb.go86
3 files changed, 46 insertions, 51 deletions
diff --git a/core/state/state_object.go b/core/state/state_object.go
index 251a31093..40af9ed9c 100644
--- a/core/state/state_object.go
+++ b/core/state/state_object.go
@@ -218,6 +218,7 @@ func (c *StateObject) ReturnGas(gas, price *big.Int) {}
func (self *StateObject) SetGasLimit(gasLimit *big.Int) {
self.gasPool = new(big.Int).Set(gasLimit)
+ self.dirty = true
if glog.V(logger.Core) {
glog.Infof("%x: gas (+ %v)", self.Address(), self.gasPool)
@@ -228,19 +229,14 @@ func (self *StateObject) SubGas(gas, price *big.Int) error {
if self.gasPool.Cmp(gas) < 0 {
return GasLimitError(self.gasPool, gas)
}
-
self.gasPool.Sub(self.gasPool, gas)
-
- rGas := new(big.Int).Set(gas)
- rGas.Mul(rGas, price)
-
self.dirty = true
-
return nil
}
func (self *StateObject) AddGas(gas, price *big.Int) {
self.gasPool.Add(self.gasPool, gas)
+ self.dirty = true
}
func (self *StateObject) Copy() *StateObject {
diff --git a/core/state/state_test.go b/core/state/state_test.go
index 60836738e..b5a7f4081 100644
--- a/core/state/state_test.go
+++ b/core/state/state_test.go
@@ -89,8 +89,7 @@ func TestNull(t *testing.T) {
//value := common.FromHex("0x823140710bf13990e4500136726d8b55")
var value common.Hash
state.SetState(address, common.Hash{}, value)
- state.SyncIntermediate()
- state.Sync()
+ state.Commit()
value = state.GetState(address, common.Hash{})
if !common.EmptyHash(value) {
t.Errorf("expected empty hash. got %x", value)
diff --git a/core/state/statedb.go b/core/state/statedb.go
index c2bc99564..4233c763b 100644
--- a/core/state/statedb.go
+++ b/core/state/statedb.go
@@ -35,7 +35,6 @@ import (
type StateDB struct {
db ethdb.Database
trie *trie.SecureTrie
- root common.Hash
stateObjects map[string]*StateObject
@@ -56,7 +55,6 @@ func New(root common.Hash, db ethdb.Database) *StateDB {
glog.Errorf("can't create state trie with root %x: %v", root[:], err)
}
return &StateDB{
- root: root,
db: db,
trie: tr,
stateObjects: make(map[string]*StateObject),
@@ -204,7 +202,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())
}
@@ -215,6 +212,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
@@ -311,65 +309,67 @@ func (self *StateDB) Set(state *StateDB) {
self.logSize = state.logSize
}
-func (s *StateDB) Root() common.Hash {
- return s.trie.Hash()
-}
-
-// Syncs the trie and all siblings
-func (s *StateDB) Sync() {
- // Sync all nested states
+// 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 {
- 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 {
- 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 {
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)
+}
+
+// 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
+}
- self.refund = new(big.Int)
+func (s *StateDB) commit(db trie.DatabaseWriter) (common.Hash, error) {
+ s.refund = new(big.Int)
- for _, stateObject := range self.stateObjects {
+ 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