|
|
|
@ -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 |
|
|
|
|
} |
|
|
|
|