mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-25 22:26:42 +00:00
Merge 87d99d09d8 into f466243417
This commit is contained in:
commit
7349b4633c
12 changed files with 189 additions and 104 deletions
|
|
@ -82,7 +82,7 @@ func NewBlockProcessor(db ethdb.Database, pow pow.PoW, blockchain *BlockChain, e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block, transientProcess bool) (receipts types.Receipts, err error) {
|
func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block, transientProcess bool) (receipts types.Receipts, err error) {
|
||||||
gp := statedb.GetOrNewStateObject(block.Coinbase())
|
gp, _ := statedb.GetOrNewStateObject(block.Coinbase())
|
||||||
gp.SetGasLimit(block.GasLimit())
|
gp.SetGasLimit(block.GasLimit())
|
||||||
|
|
||||||
// Process the transactions on to parent state
|
// Process the transactions on to parent state
|
||||||
|
|
|
||||||
|
|
@ -35,16 +35,20 @@ var (
|
||||||
// dies a horrible death.
|
// dies a horrible death.
|
||||||
func Canary(statedb *state.StateDB) bool {
|
func Canary(statedb *state.StateDB) bool {
|
||||||
var r int
|
var r int
|
||||||
if (statedb.GetState(jeff, common.Hash{}).Big().Cmp(big.NewInt(0)) > 0) {
|
state, err := statedb.GetState(jeff, common.Hash{})
|
||||||
|
if err == nil && (state.Big().Cmp(big.NewInt(0)) > 0) {
|
||||||
r++
|
r++
|
||||||
}
|
}
|
||||||
if (statedb.GetState(gav, common.Hash{}).Big().Cmp(big.NewInt(0)) > 0) {
|
state, err = statedb.GetState(gav, common.Hash{})
|
||||||
|
if err == nil && (state.Big().Cmp(big.NewInt(0)) > 0) {
|
||||||
r++
|
r++
|
||||||
}
|
}
|
||||||
if (statedb.GetState(christoph, common.Hash{}).Big().Cmp(big.NewInt(0)) > 0) {
|
state, err = statedb.GetState(christoph, common.Hash{})
|
||||||
|
if err == nil && (state.Big().Cmp(big.NewInt(0)) > 0) {
|
||||||
r++
|
r++
|
||||||
}
|
}
|
||||||
if (statedb.GetState(vitalik, common.Hash{}).Big().Cmp(big.NewInt(0)) > 0) {
|
state, err = statedb.GetState(vitalik, common.Hash{})
|
||||||
|
if err == nil && (state.Big().Cmp(big.NewInt(0)) > 0) {
|
||||||
r++
|
r++
|
||||||
}
|
}
|
||||||
return r > 1
|
return r > 1
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ func (b *BlockGen) SetCoinbase(addr common.Address) {
|
||||||
panic("coinbase can only be set once")
|
panic("coinbase can only be set once")
|
||||||
}
|
}
|
||||||
b.header.Coinbase = addr
|
b.header.Coinbase = addr
|
||||||
b.coinbase = b.statedb.GetOrNewStateObject(addr)
|
b.coinbase, _ = b.statedb.GetOrNewStateObject(addr)
|
||||||
b.coinbase.SetGasLimit(b.header.GasLimit)
|
b.coinbase.SetGasLimit(b.header.GasLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,10 +108,12 @@ func (b *BlockGen) AddTx(tx *types.Transaction) {
|
||||||
// TxNonce returns the next valid transaction nonce for the
|
// TxNonce returns the next valid transaction nonce for the
|
||||||
// account at addr. It panics if the account does not exist.
|
// account at addr. It panics if the account does not exist.
|
||||||
func (b *BlockGen) TxNonce(addr common.Address) uint64 {
|
func (b *BlockGen) TxNonce(addr common.Address) uint64 {
|
||||||
if !b.statedb.HasAccount(addr) {
|
ha, _ := b.statedb.HasAccount(addr)
|
||||||
|
if !ha {
|
||||||
panic("account does not exist")
|
panic("account does not exist")
|
||||||
}
|
}
|
||||||
return b.statedb.GetNonce(addr)
|
nonce, _ := b.statedb.GetNonce(addr)
|
||||||
|
return nonce
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddUncle adds an uncle header to the generated block.
|
// AddUncle adds an uncle header to the generated block.
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,7 @@ func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block,
|
||||||
// The state trie of the block is written to db.
|
// The state trie of the block is written to db.
|
||||||
func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big.Int) *types.Block {
|
func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big.Int) *types.Block {
|
||||||
statedb := state.New(common.Hash{}, db)
|
statedb := state.New(common.Hash{}, db)
|
||||||
obj := statedb.GetOrNewStateObject(addr)
|
obj, _ := statedb.GetOrNewStateObject(addr)
|
||||||
obj.SetBalance(balance)
|
obj.SetBalance(balance)
|
||||||
root, err := statedb.Commit()
|
root, err := statedb.Commit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -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, _ := NewStateObjectFromBytes(common.BytesToAddress(addr), it.Value, self.db)
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,8 @@ func (ms *ManagedState) GetNonce(addr common.Address) uint64 {
|
||||||
account := ms.getAccount(addr)
|
account := ms.getAccount(addr)
|
||||||
return uint64(len(account.nonces)) + account.nstart
|
return uint64(len(account.nonces)) + account.nstart
|
||||||
} else {
|
} else {
|
||||||
return ms.StateDB.GetNonce(addr)
|
nonce, _ := ms.StateDB.GetNonce(addr)
|
||||||
|
return nonce
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,7 +101,7 @@ func (ms *ManagedState) SetNonce(addr common.Address, nonce uint64) {
|
||||||
ms.mu.Lock()
|
ms.mu.Lock()
|
||||||
defer ms.mu.Unlock()
|
defer ms.mu.Unlock()
|
||||||
|
|
||||||
so := ms.GetOrNewStateObject(addr)
|
so, _ := ms.GetOrNewStateObject(addr)
|
||||||
so.SetNonce(nonce)
|
so.SetNonce(nonce)
|
||||||
|
|
||||||
ms.accounts[addr.Str()] = newAccount(so)
|
ms.accounts[addr.Str()] = newAccount(so)
|
||||||
|
|
@ -122,12 +123,12 @@ func (ms *ManagedState) hasAccount(addr common.Address) bool {
|
||||||
func (ms *ManagedState) getAccount(addr common.Address) *account {
|
func (ms *ManagedState) getAccount(addr common.Address) *account {
|
||||||
straddr := addr.Str()
|
straddr := addr.Str()
|
||||||
if account, ok := ms.accounts[straddr]; !ok {
|
if account, ok := ms.accounts[straddr]; !ok {
|
||||||
so := ms.GetOrNewStateObject(addr)
|
so, _ := ms.GetOrNewStateObject(addr)
|
||||||
ms.accounts[straddr] = newAccount(so)
|
ms.accounts[straddr] = newAccount(so)
|
||||||
} else {
|
} else {
|
||||||
// Always make sure the state account nonce isn't actually higher
|
// Always make sure the state account nonce isn't actually higher
|
||||||
// than the tracked one.
|
// than the tracked one.
|
||||||
so := ms.StateDB.GetStateObject(addr)
|
so, _ := ms.StateDB.GetStateObject(addr)
|
||||||
if so != nil && uint64(len(account.nonces))+account.nstart < so.nonce {
|
if so != nil && uint64(len(account.nonces))+account.nstart < so.nonce {
|
||||||
ms.accounts[straddr] = newAccount(so)
|
ms.accounts[straddr] = newAccount(so)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ func NewStateObject(address common.Address, db ethdb.Database) *StateObject {
|
||||||
return object
|
return object
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStateObjectFromBytes(address common.Address, data []byte, db ethdb.Database) *StateObject {
|
func NewStateObjectFromBytes(address common.Address, data []byte, db ethdb.Database) (*StateObject, error) {
|
||||||
var extobject struct {
|
var extobject struct {
|
||||||
Nonce uint64
|
Nonce uint64
|
||||||
Balance *big.Int
|
Balance *big.Int
|
||||||
|
|
@ -106,13 +106,13 @@ func NewStateObjectFromBytes(address common.Address, data []byte, db ethdb.Datab
|
||||||
err := rlp.Decode(bytes.NewReader(data), &extobject)
|
err := rlp.Decode(bytes.NewReader(data), &extobject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("can't decode state object %x: %v", address, err)
|
glog.Errorf("can't decode state object %x: %v", address, err)
|
||||||
return nil
|
return nil, err
|
||||||
}
|
}
|
||||||
trie, err := trie.NewSecure(extobject.Root, db)
|
trie, err := trie.NewSecure(extobject.Root, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO: bubble this up or panic
|
// TODO: bubble this up or panic
|
||||||
glog.Errorf("can't create account trie with root %x: %v", extobject.Root[:], err)
|
glog.Errorf("can't create account trie with root %x: %v", extobject.Root[:], err)
|
||||||
return nil
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
object := &StateObject{address: address, db: db}
|
object := &StateObject{address: address, db: db}
|
||||||
|
|
@ -122,8 +122,12 @@ func NewStateObjectFromBytes(address common.Address, data []byte, db ethdb.Datab
|
||||||
object.trie = trie
|
object.trie = trie
|
||||||
object.storage = make(map[string]common.Hash)
|
object.storage = make(map[string]common.Hash)
|
||||||
object.gasPool = new(big.Int)
|
object.gasPool = new(big.Int)
|
||||||
object.code, _ = db.Get(extobject.CodeHash)
|
object.code, err = db.Get(extobject.CodeHash)
|
||||||
return object
|
if err != nil {
|
||||||
|
glog.Errorf("can't retrieve contract code %x: %v", extobject.CodeHash, err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return object, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateObject) MarkForDeletion() {
|
func (self *StateObject) MarkForDeletion() {
|
||||||
|
|
@ -135,10 +139,14 @@ func (self *StateObject) MarkForDeletion() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StateObject) getAddr(addr common.Hash) common.Hash {
|
func (c *StateObject) getAddr(addr common.Hash) (common.Hash, error) {
|
||||||
var ret []byte
|
var ret []byte
|
||||||
rlp.DecodeBytes(c.trie.Get(addr[:]), &ret)
|
value, err := c.trie.Get(addr[:])
|
||||||
return common.BytesToHash(ret)
|
if err != nil {
|
||||||
|
return common.Hash{}, err
|
||||||
|
}
|
||||||
|
rlp.DecodeBytes(value, &ret)
|
||||||
|
return common.BytesToHash(ret), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StateObject) setAddr(addr []byte, value common.Hash) {
|
func (c *StateObject) setAddr(addr []byte, value common.Hash) {
|
||||||
|
|
@ -154,17 +162,21 @@ func (self *StateObject) Storage() Storage {
|
||||||
return self.storage
|
return self.storage
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateObject) GetState(key common.Hash) common.Hash {
|
func (self *StateObject) GetState(key common.Hash) (common.Hash, error) {
|
||||||
strkey := key.Str()
|
strkey := key.Str()
|
||||||
value, exists := self.storage[strkey]
|
value, exists := self.storage[strkey]
|
||||||
if !exists {
|
if !exists {
|
||||||
value = self.getAddr(key)
|
var err error
|
||||||
|
value, err = self.getAddr(key)
|
||||||
|
if err != nil {
|
||||||
|
return common.Hash{}, err
|
||||||
|
}
|
||||||
if (value != common.Hash{}) {
|
if (value != common.Hash{}) {
|
||||||
self.storage[strkey] = value
|
self.storage[strkey] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return value
|
return value, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateObject) SetState(k, value common.Hash) {
|
func (self *StateObject) SetState(k, value common.Hash) {
|
||||||
|
|
|
||||||
|
|
@ -99,105 +99,152 @@ func (self *StateDB) AddRefund(gas *big.Int) {
|
||||||
self.refund.Add(self.refund, gas)
|
self.refund.Add(self.refund, gas)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) HasAccount(addr common.Address) bool {
|
func (self *StateDB) HasAccount(addr common.Address) (bool, error) {
|
||||||
return self.GetStateObject(addr) != nil
|
acc, err := self.GetStateObject(addr)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return acc != nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) Exist(addr common.Address) bool {
|
func (self *StateDB) Exist(addr common.Address) (bool, error) {
|
||||||
return self.GetStateObject(addr) != nil
|
acc, err := self.GetStateObject(addr)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return acc != nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) GetAccount(addr common.Address) vm.Account {
|
func (self *StateDB) GetAccount(addr common.Address) (vm.Account, error) {
|
||||||
return self.GetStateObject(addr)
|
acc, err := self.GetStateObject(addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return acc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve the balance from the given address or 0 if object not found
|
// Retrieve the balance from the given address or 0 if object not found
|
||||||
func (self *StateDB) GetBalance(addr common.Address) *big.Int {
|
func (self *StateDB) GetBalance(addr common.Address) (*big.Int, error) {
|
||||||
stateObject := self.GetStateObject(addr)
|
stateObject, err := self.GetStateObject(addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
return stateObject.balance
|
return stateObject.balance, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return common.Big0
|
return common.Big0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) GetNonce(addr common.Address) uint64 {
|
func (self *StateDB) GetNonce(addr common.Address) (uint64, error) {
|
||||||
stateObject := self.GetStateObject(addr)
|
stateObject, err := self.GetStateObject(addr)
|
||||||
if stateObject != nil {
|
if err != nil {
|
||||||
return stateObject.nonce
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *StateDB) GetCode(addr common.Address) []byte {
|
|
||||||
stateObject := self.GetStateObject(addr)
|
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
return stateObject.code
|
return stateObject.nonce, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) GetState(a common.Address, b common.Hash) common.Hash {
|
func (self *StateDB) GetCode(addr common.Address) ([]byte, error) {
|
||||||
stateObject := self.GetStateObject(a)
|
stateObject, err := self.GetStateObject(addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if stateObject != nil {
|
||||||
|
return stateObject.code, nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *StateDB) GetState(a common.Address, b common.Hash) (common.Hash, error) {
|
||||||
|
stateObject, err := self.GetStateObject(a)
|
||||||
|
if err != nil {
|
||||||
|
return common.Hash{}, err
|
||||||
|
}
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
return stateObject.GetState(b)
|
return stateObject.GetState(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
return common.Hash{}
|
return common.Hash{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) IsDeleted(addr common.Address) bool {
|
func (self *StateDB) IsDeleted(addr common.Address) (bool, error) {
|
||||||
stateObject := self.GetStateObject(addr)
|
stateObject, err := self.GetStateObject(addr)
|
||||||
if stateObject != nil {
|
if err != nil {
|
||||||
return stateObject.remove
|
return false, err
|
||||||
}
|
}
|
||||||
return false
|
if stateObject != nil {
|
||||||
|
return stateObject.remove, nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SETTERS
|
* SETTERS
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) {
|
func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) error {
|
||||||
stateObject := self.GetOrNewStateObject(addr)
|
stateObject, err := self.GetOrNewStateObject(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
stateObject.AddBalance(amount)
|
stateObject.AddBalance(amount)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) SetNonce(addr common.Address, nonce uint64) {
|
func (self *StateDB) SetNonce(addr common.Address, nonce uint64) error {
|
||||||
stateObject := self.GetOrNewStateObject(addr)
|
stateObject, err := self.GetOrNewStateObject(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
stateObject.SetNonce(nonce)
|
stateObject.SetNonce(nonce)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) SetCode(addr common.Address, code []byte) {
|
func (self *StateDB) SetCode(addr common.Address, code []byte) error {
|
||||||
stateObject := self.GetOrNewStateObject(addr)
|
stateObject, err := self.GetOrNewStateObject(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
stateObject.SetCode(code)
|
stateObject.SetCode(code)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) SetState(addr common.Address, key common.Hash, value common.Hash) {
|
func (self *StateDB) SetState(addr common.Address, key common.Hash, value common.Hash) error {
|
||||||
stateObject := self.GetOrNewStateObject(addr)
|
stateObject, err := self.GetOrNewStateObject(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
stateObject.SetState(key, value)
|
stateObject.SetState(key, value)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) Delete(addr common.Address) bool {
|
func (self *StateDB) Delete(addr common.Address) (bool, error) {
|
||||||
stateObject := self.GetStateObject(addr)
|
stateObject, err := self.GetStateObject(addr)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
stateObject.MarkForDeletion()
|
stateObject.MarkForDeletion()
|
||||||
stateObject.balance = new(big.Int)
|
stateObject.balance = new(big.Int)
|
||||||
|
|
||||||
return true
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
@ -225,25 +272,28 @@ func (self *StateDB) DeleteStateObject(stateObject *StateObject) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve a state object given my the address. Nil if not found
|
// Retrieve a state object given my the address. Nil if not found
|
||||||
func (self *StateDB) GetStateObject(addr common.Address) (stateObject *StateObject) {
|
func (self *StateDB) GetStateObject(addr common.Address) (stateObject *StateObject, err error) {
|
||||||
stateObject = self.stateObjects[addr.Str()]
|
stateObject = self.stateObjects[addr.Str()]
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
if stateObject.deleted {
|
if stateObject.deleted {
|
||||||
stateObject = nil
|
stateObject = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return stateObject
|
return stateObject, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
data := self.trie.Get(addr[:])
|
data, err := self.trie.Get(addr[:])
|
||||||
if len(data) == 0 {
|
if err != nil {
|
||||||
return nil
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
stateObject = NewStateObjectFromBytes(addr, []byte(data), self.db)
|
stateObject, err = NewStateObjectFromBytes(addr, []byte(data), self.db)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
self.SetStateObject(stateObject)
|
self.SetStateObject(stateObject)
|
||||||
|
|
||||||
return stateObject
|
return stateObject, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) SetStateObject(object *StateObject) {
|
func (self *StateDB) SetStateObject(object *StateObject) {
|
||||||
|
|
@ -251,13 +301,16 @@ func (self *StateDB) SetStateObject(object *StateObject) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve a state object or create a new state object if nil
|
// Retrieve a state object or create a new state object if nil
|
||||||
func (self *StateDB) GetOrNewStateObject(addr common.Address) *StateObject {
|
func (self *StateDB) GetOrNewStateObject(addr common.Address) (*StateObject, error) {
|
||||||
stateObject := self.GetStateObject(addr)
|
stateObject, err := self.GetStateObject(addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if stateObject == nil || stateObject.deleted {
|
if stateObject == nil || stateObject.deleted {
|
||||||
stateObject = self.CreateStateObject(addr)
|
stateObject, err = self.CreateStateObject(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
return stateObject
|
return stateObject, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStateObject create a state object whether it exist in the trie or not
|
// NewStateObject create a state object whether it exist in the trie or not
|
||||||
|
|
@ -274,9 +327,12 @@ func (self *StateDB) newStateObject(addr common.Address) *StateObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates creates a new state object and takes ownership. This is different from "NewStateObject"
|
// Creates creates a new state object and takes ownership. This is different from "NewStateObject"
|
||||||
func (self *StateDB) CreateStateObject(addr common.Address) *StateObject {
|
func (self *StateDB) CreateStateObject(addr common.Address) (*StateObject, error) {
|
||||||
// Get previous (if any)
|
// Get previous (if any)
|
||||||
so := self.GetStateObject(addr)
|
so, err := self.GetStateObject(addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
// Create a new one
|
// Create a new one
|
||||||
newSo := self.newStateObject(addr)
|
newSo := self.newStateObject(addr)
|
||||||
|
|
||||||
|
|
@ -285,10 +341,10 @@ func (self *StateDB) CreateStateObject(addr common.Address) *StateObject {
|
||||||
newSo.balance = so.balance
|
newSo.balance = so.balance
|
||||||
}
|
}
|
||||||
|
|
||||||
return newSo
|
return newSo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) CreateAccount(addr common.Address) vm.Account {
|
func (self *StateDB) CreateAccount(addr common.Address) (vm.Account, error) {
|
||||||
return self.CreateStateObject(addr)
|
return self.CreateStateObject(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -180,12 +180,20 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
|
||||||
|
|
||||||
// Make sure the account exist. Non existent accounts
|
// Make sure the account exist. Non existent accounts
|
||||||
// haven't got funds and well therefor never pass.
|
// haven't got funds and well therefor never pass.
|
||||||
if !pool.currentState().HasAccount(from) {
|
ha, err := pool.currentState().HasAccount(from)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !ha {
|
||||||
return ErrNonExistentAccount
|
return ErrNonExistentAccount
|
||||||
}
|
}
|
||||||
|
|
||||||
// Last but not least check for nonce errors
|
// Last but not least check for nonce errors
|
||||||
if pool.currentState().GetNonce(from) > tx.Nonce() {
|
nonce, err := pool.currentState().GetNonce(from)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if nonce > tx.Nonce() {
|
||||||
return ErrNonce
|
return ErrNonce
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -204,7 +212,11 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
|
||||||
|
|
||||||
// Transactor should have enough funds to cover the costs
|
// Transactor should have enough funds to cover the costs
|
||||||
// cost == V + GP * GL
|
// cost == V + GP * GL
|
||||||
if pool.currentState().GetBalance(from).Cmp(tx.Cost()) < 0 {
|
balance, err := pool.currentState().GetBalance(from)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if balance.Cmp(tx.Cost()) < 0 {
|
||||||
return ErrInsufficientFunds
|
return ErrInsufficientFunds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -389,7 +401,7 @@ func (pool *TxPool) checkQueue() {
|
||||||
// guessed nonce is the nonce currently kept by the tx pool (pending state)
|
// guessed nonce is the nonce currently kept by the tx pool (pending state)
|
||||||
guessedNonce := state.GetNonce(address)
|
guessedNonce := state.GetNonce(address)
|
||||||
// true nonce is the nonce known by the last state
|
// true nonce is the nonce known by the last state
|
||||||
trueNonce := pool.currentState().GetNonce(address)
|
trueNonce, _ := pool.currentState().GetNonce(address)
|
||||||
addq := addq[:0]
|
addq := addq[:0]
|
||||||
for hash, tx := range txs {
|
for hash, tx := range txs {
|
||||||
if tx.Nonce() < trueNonce {
|
if tx.Nonce() < trueNonce {
|
||||||
|
|
@ -438,7 +450,8 @@ func (pool *TxPool) validatePool() {
|
||||||
for hash, tx := range pool.pending {
|
for hash, tx := range pool.pending {
|
||||||
from, _ := tx.From() // err already checked
|
from, _ := tx.From() // err already checked
|
||||||
// perform light nonce validation
|
// perform light nonce validation
|
||||||
if state.GetNonce(from) > tx.Nonce() {
|
nonce, _ := state.GetNonce(from)
|
||||||
|
if nonce > tx.Nonce() {
|
||||||
if glog.V(logger.Core) {
|
if glog.V(logger.Core) {
|
||||||
glog.Infof("removed tx (%x) from pool: low tx nonce\n", hash[:4])
|
glog.Infof("removed tx (%x) from pool: low tx nonce\n", hash[:4])
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ func NewSecure(root common.Hash, db Database) (*SecureTrie, error) {
|
||||||
|
|
||||||
// Get returns the value for key stored in the trie.
|
// Get returns the value for key stored in the trie.
|
||||||
// The value bytes must not be modified by the caller.
|
// The value bytes must not be modified by the caller.
|
||||||
func (t *SecureTrie) Get(key []byte) []byte {
|
func (t *SecureTrie) Get(key []byte) ([]byte, error) {
|
||||||
return t.Trie.Get(t.hashKey(key))
|
return t.Trie.Get(t.hashKey(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
23
trie/trie.go
23
trie/trie.go
|
|
@ -25,8 +25,6 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto/sha3"
|
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -40,6 +38,8 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrMissingRoot = errors.New("missing root node")
|
var ErrMissingRoot = errors.New("missing root node")
|
||||||
|
var ErrMissingNode = errors.New("missing trie node")
|
||||||
|
var ErrInvalidNode = errors.New("invalid trie node")
|
||||||
|
|
||||||
// Database must be implemented by backing stores for the trie.
|
// Database must be implemented by backing stores for the trie.
|
||||||
type Database interface {
|
type Database interface {
|
||||||
|
|
@ -94,29 +94,30 @@ func (t *Trie) Iterator() *Iterator {
|
||||||
|
|
||||||
// Get returns the value for key stored in the trie.
|
// Get returns the value for key stored in the trie.
|
||||||
// The value bytes must not be modified by the caller.
|
// The value bytes must not be modified by the caller.
|
||||||
func (t *Trie) Get(key []byte) []byte {
|
func (t *Trie) Get(key []byte) ([]byte, error) {
|
||||||
key = compactHexDecode(key)
|
key = compactHexDecode(key)
|
||||||
tn := t.root
|
tn := t.root
|
||||||
for len(key) > 0 {
|
for len(key) > 0 {
|
||||||
switch n := tn.(type) {
|
switch n := tn.(type) {
|
||||||
case shortNode:
|
case shortNode:
|
||||||
if len(key) < len(n.Key) || !bytes.Equal(n.Key, key[:len(n.Key)]) {
|
if len(key) < len(n.Key) || !bytes.Equal(n.Key, key[:len(n.Key)]) {
|
||||||
return nil
|
return nil, ErrInvalidNode
|
||||||
}
|
}
|
||||||
tn = n.Val
|
tn = n.Val
|
||||||
key = key[len(n.Key):]
|
key = key[len(n.Key):]
|
||||||
case fullNode:
|
case fullNode:
|
||||||
tn = n[key[0]]
|
tn = n[key[0]]
|
||||||
key = key[1:]
|
key = key[1:]
|
||||||
case nil:
|
|
||||||
return nil
|
|
||||||
case hashNode:
|
case hashNode:
|
||||||
tn = t.resolveHash(n)
|
tn = t.resolveHash(n)
|
||||||
|
if tn == nil {
|
||||||
|
return nil, ErrMissingNode
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("%T: invalid node: %v", tn, tn))
|
panic(fmt.Sprintf("%T: invalid node: %v", tn, tn))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tn.(valueNode)
|
return tn.(valueNode), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update associates key with value in the trie. Subsequent calls to
|
// Update associates key with value in the trie. Subsequent calls to
|
||||||
|
|
@ -295,14 +296,6 @@ func (t *Trie) resolveHash(n hashNode) node {
|
||||||
}
|
}
|
||||||
enc, err := t.db.Get(n)
|
enc, err := t.db.Get(n)
|
||||||
if err != nil || enc == nil {
|
if err != nil || enc == nil {
|
||||||
// TODO: This needs to be improved to properly distinguish errors.
|
|
||||||
// Disk I/O errors shouldn't produce nil (and cause a
|
|
||||||
// consensus failure or weird crash), but it is unclear how
|
|
||||||
// they could be handled because the entire stack above the trie isn't
|
|
||||||
// prepared to cope with missing state nodes.
|
|
||||||
if glog.V(logger.Error) {
|
|
||||||
glog.Errorf("Dangling hash node ref %x: %v", n, err)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
dec := mustDecodeNode(n, enc)
|
dec := mustDecodeNode(n, enc)
|
||||||
|
|
|
||||||
|
|
@ -490,8 +490,12 @@ func (self *XEth) StorageAt(addr, storageAddr string) string {
|
||||||
return self.State().state.GetState(common.HexToAddress(addr), common.HexToHash(storageAddr)).Hex()
|
return self.State().state.GetState(common.HexToAddress(addr), common.HexToHash(storageAddr)).Hex()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *XEth) BalanceAt(addr string) string {
|
func (self *XEth) BalanceAt(addr string) (string, error) {
|
||||||
return common.ToHex(self.State().state.GetBalance(common.HexToAddress(addr)).Bytes())
|
val, err := self.State().state.GetBalance(common.HexToAddress(addr))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return common.ToHex(val.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *XEth) TxCountAt(address string) int {
|
func (self *XEth) TxCountAt(address string) int {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue