core/state, core/types use package rlp for state, receipt serialisation
This commit is contained in:
parent
9be5d5cd90
commit
1b89bd5d26
|
@ -45,7 +45,7 @@ func (self *StateDB) RawDump() World {
|
||||||
it := self.trie.Iterator()
|
it := self.trie.Iterator()
|
||||||
for it.Next() {
|
for it.Next() {
|
||||||
addr := self.trie.GetKey(it.Key)
|
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 := Account{Balance: stateObject.balance.String(), Nonce: stateObject.nonce, Root: common.Bytes2Hex(stateObject.Root()), CodeHash: common.Bytes2Hex(stateObject.codeHash)}
|
||||||
account.Storage = make(map[string]string)
|
account.Storage = make(map[string]string)
|
||||||
|
|
|
@ -19,17 +19,19 @@ package state
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var emptyCodeHash = crypto.Sha3(nil)
|
||||||
|
|
||||||
type Code []byte
|
type Code []byte
|
||||||
|
|
||||||
func (self Code) String() string {
|
func (self Code) String() string {
|
||||||
|
@ -56,8 +58,7 @@ func (self Storage) Copy() Storage {
|
||||||
}
|
}
|
||||||
|
|
||||||
type StateObject struct {
|
type StateObject struct {
|
||||||
// State database for storing state changes
|
db trie.Database // State database for storing state changes
|
||||||
db ethdb.Database
|
|
||||||
trie *trie.SecureTrie
|
trie *trie.SecureTrie
|
||||||
|
|
||||||
// Address belonging to this account
|
// Address belonging to this account
|
||||||
|
@ -83,39 +84,16 @@ type StateObject struct {
|
||||||
dirty bool
|
dirty bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStateObject(address common.Address, db ethdb.Database) *StateObject {
|
func NewStateObject(address common.Address, db trie.Database) *StateObject {
|
||||||
object := &StateObject{db: db, address: address, balance: new(big.Int), dirty: true}
|
object := &StateObject{
|
||||||
|
db: db,
|
||||||
|
address: address,
|
||||||
|
balance: new(big.Int),
|
||||||
|
dirty: true,
|
||||||
|
codeHash: emptyCodeHash,
|
||||||
|
storage: make(Storage),
|
||||||
|
}
|
||||||
object.trie, _ = trie.NewSecure(common.Hash{}, db)
|
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
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
return object
|
return object
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +150,6 @@ func (self *StateObject) Update() {
|
||||||
self.trie.Delete([]byte(key))
|
self.trie.Delete([]byte(key))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
self.setAddr([]byte(key), value)
|
self.setAddr([]byte(key), value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -248,6 +225,7 @@ func (self *StateObject) Code() []byte {
|
||||||
|
|
||||||
func (self *StateObject) SetCode(code []byte) {
|
func (self *StateObject) SetCode(code []byte) {
|
||||||
self.code = code
|
self.code = code
|
||||||
|
self.codeHash = crypto.Sha3(code)
|
||||||
self.dirty = true
|
self.dirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,23 +254,40 @@ func (self *StateObject) EachStorage(cb func(key, value []byte)) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Encoding
|
// Encoding
|
||||||
//
|
|
||||||
|
|
||||||
// State object encoding methods
|
type extStateObject struct {
|
||||||
func (c *StateObject) RlpEncode() []byte {
|
Nonce uint64
|
||||||
return common.Encode([]interface{}{c.nonce, c.balance, c.Root(), c.CodeHash()})
|
Balance *big.Int
|
||||||
|
Root common.Hash
|
||||||
|
CodeHash []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StateObject) CodeHash() common.Bytes {
|
// EncodeRLP implements rlp.Encoder.
|
||||||
return crypto.Sha3(c.code)
|
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
|
// DecodeObject decodes an RLP-encoded state object.
|
||||||
// the sub channels.
|
func DecodeObject(address common.Address, db trie.Database, data []byte) (*StateObject, error) {
|
||||||
type StorageState struct {
|
var (
|
||||||
StateAddress []byte
|
obj = &StateObject{address: address, db: db, storage: make(Storage)}
|
||||||
Address []byte
|
ext extStateObject
|
||||||
Value *big.Int
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,8 +138,7 @@ func TestSnapshot2(t *testing.T) {
|
||||||
so0 := state.GetStateObject(stateobjaddr0)
|
so0 := state.GetStateObject(stateobjaddr0)
|
||||||
so0.balance = big.NewInt(42)
|
so0.balance = big.NewInt(42)
|
||||||
so0.nonce = 43
|
so0.nonce = 43
|
||||||
so0.code = []byte{'c', 'a', 'f', 'e'}
|
so0.SetCode([]byte{'c', 'a', 'f', 'e'})
|
||||||
so0.codeHash = so0.CodeHash()
|
|
||||||
so0.remove = true
|
so0.remove = true
|
||||||
so0.deleted = false
|
so0.deleted = false
|
||||||
so0.dirty = false
|
so0.dirty = false
|
||||||
|
@ -149,8 +148,7 @@ func TestSnapshot2(t *testing.T) {
|
||||||
so1 := state.GetStateObject(stateobjaddr1)
|
so1 := state.GetStateObject(stateobjaddr1)
|
||||||
so1.balance = big.NewInt(52)
|
so1.balance = big.NewInt(52)
|
||||||
so1.nonce = 53
|
so1.nonce = 53
|
||||||
so1.code = []byte{'c', 'a', 'f', 'e', '2'}
|
so1.SetCode([]byte{'c', 'a', 'f', 'e', '2'})
|
||||||
so1.codeHash = so1.CodeHash()
|
|
||||||
so1.remove = true
|
so1.remove = true
|
||||||
so1.deleted = true
|
so1.deleted = true
|
||||||
so1.dirty = true
|
so1.dirty = true
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
package state
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
@ -25,6 +26,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"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
|
// Update the given state object and apply it to state trie
|
||||||
func (self *StateDB) UpdateStateObject(stateObject *StateObject) {
|
func (self *StateDB) UpdateStateObject(stateObject *StateObject) {
|
||||||
//addr := stateObject.Address()
|
if len(stateObject.code) > 0 {
|
||||||
|
self.db.Put(stateObject.codeHash, stateObject.code)
|
||||||
if len(stateObject.CodeHash()) > 0 {
|
|
||||||
self.db.Put(stateObject.CodeHash(), stateObject.code)
|
|
||||||
}
|
}
|
||||||
addr := stateObject.Address()
|
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
|
// 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 {
|
if len(data) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
stateObject, err := DecodeObject(addr, self.db, data)
|
||||||
stateObject = NewStateObjectFromBytes(addr, []byte(data), self.db)
|
if err != nil {
|
||||||
|
glog.Errorf("can't decode object at %x: %v", addr[:], err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
self.SetStateObject(stateObject)
|
self.SetStateObject(stateObject)
|
||||||
|
|
||||||
return stateObject
|
return stateObject
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -125,17 +125,14 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
|
||||||
// Receipts is a wrapper around a Receipt array to implement types.DerivableList.
|
// Receipts is a wrapper around a Receipt array to implement types.DerivableList.
|
||||||
type Receipts []*Receipt
|
type Receipts []*Receipt
|
||||||
|
|
||||||
// RlpEncode implements common.RlpEncode required for SHA3 derivation.
|
// Len returns the number of receipts in this list.
|
||||||
func (r Receipts) RlpEncode() []byte {
|
func (r Receipts) Len() int { return len(r) }
|
||||||
bytes, err := rlp.EncodeToBytes(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 {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return bytes
|
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]) }
|
|
||||||
|
|
Loading…
Reference in New Issue