aboutsummaryrefslogtreecommitdiffstats
path: root/core/state
diff options
context:
space:
mode:
Diffstat (limited to 'core/state')
-rw-r--r--core/state/dump.go2
-rw-r--r--core/state/state_object.go93
-rw-r--r--core/state/state_test.go6
-rw-r--r--core/state/statedb.go22
4 files changed, 61 insertions, 62 deletions
diff --git a/core/state/dump.go b/core/state/dump.go
index 9acb8a024..cff9c50aa 100644
--- a/core/state/dump.go
+++ b/core/state/dump.go
@@ -45,7 +45,7 @@ func (self *StateDB) RawDump() World {
it := self.trie.Iterator()
for it.Next() {
addr := self.trie.GetKey(it.Key)
- stateObject := NewStateObjectFromBytes(common.BytesToAddress(addr), it.Value, self.db)
+ stateObject, _ := DecodeObject(common.BytesToAddress(addr), self.db, it.Value)
account := Account{Balance: stateObject.balance.String(), Nonce: stateObject.nonce, Root: common.Bytes2Hex(stateObject.Root()), CodeHash: common.Bytes2Hex(stateObject.codeHash)}
account.Storage = make(map[string]string)
diff --git a/core/state/state_object.go b/core/state/state_object.go
index c06e3d227..47546112f 100644
--- a/core/state/state_object.go
+++ b/core/state/state_object.go
@@ -19,17 +19,19 @@ package state
import (
"bytes"
"fmt"
+ "io"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
)
+var emptyCodeHash = crypto.Sha3(nil)
+
type Code []byte
func (self Code) String() string {
@@ -56,8 +58,7 @@ func (self Storage) Copy() Storage {
}
type StateObject struct {
- // State database for storing state changes
- db ethdb.Database
+ db trie.Database // State database for storing state changes
trie *trie.SecureTrie
// Address belonging to this account
@@ -83,39 +84,16 @@ type StateObject struct {
dirty bool
}
-func NewStateObject(address common.Address, db ethdb.Database) *StateObject {
- object := &StateObject{db: db, address: address, balance: new(big.Int), dirty: true}
- object.trie, _ = trie.NewSecure(common.Hash{}, db)
- object.storage = make(Storage)
- return object
-}
-
-func NewStateObjectFromBytes(address common.Address, data []byte, db ethdb.Database) *StateObject {
- var extobject struct {
- Nonce uint64
- Balance *big.Int
- Root common.Hash
- CodeHash []byte
- }
- err := rlp.Decode(bytes.NewReader(data), &extobject)
- if err != nil {
- glog.Errorf("can't decode state object %x: %v", address, err)
- return nil
- }
- trie, err := trie.NewSecure(extobject.Root, db)
- if err != nil {
- // TODO: bubble this up or panic
- glog.Errorf("can't create account trie with root %x: %v", extobject.Root[:], err)
- return nil
+func NewStateObject(address common.Address, db trie.Database) *StateObject {
+ object := &StateObject{
+ db: db,
+ address: address,
+ balance: new(big.Int),
+ dirty: true,
+ codeHash: emptyCodeHash,
+ storage: make(Storage),
}
-
- object := &StateObject{address: address, db: db}
- object.nonce = extobject.Nonce
- object.balance = extobject.Balance
- object.codeHash = extobject.CodeHash
- object.trie = trie
- object.storage = make(map[string]common.Hash)
- object.code, _ = db.Get(extobject.CodeHash)
+ object.trie, _ = trie.NewSecure(common.Hash{}, db)
return object
}
@@ -172,7 +150,6 @@ func (self *StateObject) Update() {
self.trie.Delete([]byte(key))
continue
}
-
self.setAddr([]byte(key), value)
}
}
@@ -248,6 +225,7 @@ func (self *StateObject) Code() []byte {
func (self *StateObject) SetCode(code []byte) {
self.code = code
+ self.codeHash = crypto.Sha3(code)
self.dirty = true
}
@@ -276,23 +254,40 @@ func (self *StateObject) EachStorage(cb func(key, value []byte)) {
}
}
-//
// Encoding
-//
-// State object encoding methods
-func (c *StateObject) RlpEncode() []byte {
- return common.Encode([]interface{}{c.nonce, c.balance, c.Root(), c.CodeHash()})
+type extStateObject struct {
+ Nonce uint64
+ Balance *big.Int
+ Root common.Hash
+ CodeHash []byte
}
-func (c *StateObject) CodeHash() common.Bytes {
- return crypto.Sha3(c.code)
+// EncodeRLP implements rlp.Encoder.
+func (c *StateObject) EncodeRLP(w io.Writer) error {
+ return rlp.Encode(w, []interface{}{c.nonce, c.balance, c.Root(), c.codeHash})
}
-// Storage change object. Used by the manifest for notifying changes to
-// the sub channels.
-type StorageState struct {
- StateAddress []byte
- Address []byte
- Value *big.Int
+// DecodeObject decodes an RLP-encoded state object.
+func DecodeObject(address common.Address, db trie.Database, data []byte) (*StateObject, error) {
+ var (
+ obj = &StateObject{address: address, db: db, storage: make(Storage)}
+ ext extStateObject
+ err error
+ )
+ if err = rlp.DecodeBytes(data, &ext); err != nil {
+ return nil, err
+ }
+ if obj.trie, err = trie.NewSecure(ext.Root, db); err != nil {
+ return nil, err
+ }
+ if !bytes.Equal(ext.CodeHash, emptyCodeHash) {
+ if obj.code, err = db.Get(ext.CodeHash); err != nil {
+ return nil, fmt.Errorf("can't find code for hash %x: %v", ext.CodeHash, err)
+ }
+ }
+ obj.nonce = ext.Nonce
+ obj.balance = ext.Balance
+ obj.codeHash = ext.CodeHash
+ return obj, nil
}
diff --git a/core/state/state_test.go b/core/state/state_test.go
index 7ddbe11a1..7ce341c36 100644
--- a/core/state/state_test.go
+++ b/core/state/state_test.go
@@ -138,8 +138,7 @@ func TestSnapshot2(t *testing.T) {
so0 := state.GetStateObject(stateobjaddr0)
so0.balance = big.NewInt(42)
so0.nonce = 43
- so0.code = []byte{'c', 'a', 'f', 'e'}
- so0.codeHash = so0.CodeHash()
+ so0.SetCode([]byte{'c', 'a', 'f', 'e'})
so0.remove = true
so0.deleted = false
so0.dirty = false
@@ -149,8 +148,7 @@ func TestSnapshot2(t *testing.T) {
so1 := state.GetStateObject(stateobjaddr1)
so1.balance = big.NewInt(52)
so1.nonce = 53
- so1.code = []byte{'c', 'a', 'f', 'e', '2'}
- so1.codeHash = so1.CodeHash()
+ so1.SetCode([]byte{'c', 'a', 'f', 'e', '2'})
so1.remove = true
so1.deleted = true
so1.dirty = true
diff --git a/core/state/statedb.go b/core/state/statedb.go
index a9de71409..ab93870bf 100644
--- a/core/state/statedb.go
+++ b/core/state/statedb.go
@@ -18,6 +18,7 @@
package state
import (
+ "fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
@@ -25,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
+ "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
)
@@ -205,13 +207,15 @@ func (self *StateDB) Delete(addr common.Address) bool {
// Update the given state object and apply it to state trie
func (self *StateDB) UpdateStateObject(stateObject *StateObject) {
- //addr := stateObject.Address()
-
- if len(stateObject.CodeHash()) > 0 {
- self.db.Put(stateObject.CodeHash(), stateObject.code)
+ if len(stateObject.code) > 0 {
+ self.db.Put(stateObject.codeHash, stateObject.code)
}
addr := stateObject.Address()
- self.trie.Update(addr[:], stateObject.RlpEncode())
+ data, err := rlp.EncodeToBytes(stateObject)
+ if err != nil {
+ panic(fmt.Errorf("can't encode object at %x: %v", addr[:], err))
+ }
+ self.trie.Update(addr[:], data)
}
// Delete the given state object and delete it from the state trie
@@ -238,10 +242,12 @@ func (self *StateDB) GetStateObject(addr common.Address) (stateObject *StateObje
if len(data) == 0 {
return nil
}
-
- stateObject = NewStateObjectFromBytes(addr, []byte(data), self.db)
+ stateObject, err := DecodeObject(addr, self.db, data)
+ if err != nil {
+ glog.Errorf("can't decode object at %x: %v", addr[:], err)
+ return nil
+ }
self.SetStateObject(stateObject)
-
return stateObject
}