Browse Source

core/state, core/types use package rlp for state, receipt serialisation

Felix Lange 10 years ago
parent
commit
1b89bd5d26
5 changed files with 67 additions and 71 deletions
  1. 1 1
      core/state/dump.go
  2. 44 49
      core/state/state_object.go
  3. 2 4
      core/state/state_test.go
  4. 14 8
      core/state/statedb.go
  5. 6 9
      core/types/receipt.go

+ 1 - 1
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)

+ 44 - 49
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
 }

+ 2 - 4
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

+ 14 - 8
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
 }
 

+ 6 - 9
core/types/receipt.go

@@ -125,17 +125,14 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
 // Receipts is a wrapper around a Receipt array to implement types.DerivableList.
 type Receipts []*Receipt
 
-// RlpEncode implements common.RlpEncode required for SHA3 derivation.
-func (r Receipts) RlpEncode() []byte {
-	bytes, err := rlp.EncodeToBytes(r)
+// Len returns the number of receipts in this list.
+func (r Receipts) Len() int { return len(r) }
+
+// GetRlp returns the RLP encoding of one receipt from the list.
+func (r Receipts) GetRlp(i int) []byte {
+	bytes, err := rlp.EncodeToBytes(r[i])
 	if err != nil {
 		panic(err)
 	}
 	return bytes
 }
-
-// Len returns the number of receipts in this list.
-func (r Receipts) Len() int { return len(r) }
-
-// GetRlp returns the RLP encoding of one receipt from the list.
-func (r Receipts) GetRlp(i int) []byte { return common.Rlp(r[i]) }