forked from mirror/go-ethereum
core/state: access trie through Database interface, track errors (#14589)
With this commit, core/state's access to the underlying key/value database is mediated through an interface. Database errors are tracked in StateDB and returned by CommitTo or the new Error method. Motivation for this change: We can remove the light client's duplicated copy of core/state. The light client now supports node iteration, so tracing and storage enumeration can work with the light client (not implemented in this commit).release/1.6
parent
bb366271fe
commit
9e5f03b6c4
@ -0,0 +1,154 @@ |
||||
// Copyright 2017 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package state |
||||
|
||||
import ( |
||||
"fmt" |
||||
"sync" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/ethdb" |
||||
"github.com/ethereum/go-ethereum/trie" |
||||
lru "github.com/hashicorp/golang-lru" |
||||
) |
||||
|
||||
// Trie cache generation limit after which to evic trie nodes from memory.
|
||||
var MaxTrieCacheGen = uint16(120) |
||||
|
||||
const ( |
||||
// Number of past tries to keep. This value is chosen such that
|
||||
// reasonable chain reorg depths will hit an existing trie.
|
||||
maxPastTries = 12 |
||||
|
||||
// Number of codehash->size associations to keep.
|
||||
codeSizeCacheSize = 100000 |
||||
) |
||||
|
||||
// Database wraps access to tries and contract code.
|
||||
type Database interface { |
||||
// Accessing tries:
|
||||
// OpenTrie opens the main account trie.
|
||||
// OpenStorageTrie opens the storage trie of an account.
|
||||
OpenTrie(root common.Hash) (Trie, error) |
||||
OpenStorageTrie(addrHash, root common.Hash) (Trie, error) |
||||
// Accessing contract code:
|
||||
ContractCode(addrHash, codeHash common.Hash) ([]byte, error) |
||||
ContractCodeSize(addrHash, codeHash common.Hash) (int, error) |
||||
// CopyTrie returns an independent copy of the given trie.
|
||||
CopyTrie(Trie) Trie |
||||
} |
||||
|
||||
// Trie is a Ethereum Merkle Trie.
|
||||
type Trie interface { |
||||
TryGet(key []byte) ([]byte, error) |
||||
TryUpdate(key, value []byte) error |
||||
TryDelete(key []byte) error |
||||
CommitTo(trie.DatabaseWriter) (common.Hash, error) |
||||
Hash() common.Hash |
||||
NodeIterator(startKey []byte) trie.NodeIterator |
||||
GetKey([]byte) []byte // TODO(fjl): remove this when SecureTrie is removed
|
||||
} |
||||
|
||||
// NewDatabase creates a backing store for state. The returned database is safe for
|
||||
// concurrent use and retains cached trie nodes in memory.
|
||||
func NewDatabase(db ethdb.Database) Database { |
||||
csc, _ := lru.New(codeSizeCacheSize) |
||||
return &cachingDB{db: db, codeSizeCache: csc} |
||||
} |
||||
|
||||
type cachingDB struct { |
||||
db ethdb.Database |
||||
mu sync.Mutex |
||||
pastTries []*trie.SecureTrie |
||||
codeSizeCache *lru.Cache |
||||
} |
||||
|
||||
func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { |
||||
db.mu.Lock() |
||||
defer db.mu.Unlock() |
||||
|
||||
for i := len(db.pastTries) - 1; i >= 0; i-- { |
||||
if db.pastTries[i].Hash() == root { |
||||
return cachedTrie{db.pastTries[i].Copy(), db}, nil |
||||
} |
||||
} |
||||
tr, err := trie.NewSecure(root, db.db, MaxTrieCacheGen) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return cachedTrie{tr, db}, nil |
||||
} |
||||
|
||||
func (db *cachingDB) pushTrie(t *trie.SecureTrie) { |
||||
db.mu.Lock() |
||||
defer db.mu.Unlock() |
||||
|
||||
if len(db.pastTries) >= maxPastTries { |
||||
copy(db.pastTries, db.pastTries[1:]) |
||||
db.pastTries[len(db.pastTries)-1] = t |
||||
} else { |
||||
db.pastTries = append(db.pastTries, t) |
||||
} |
||||
} |
||||
|
||||
func (db *cachingDB) OpenStorageTrie(addrHash, root common.Hash) (Trie, error) { |
||||
return trie.NewSecure(root, db.db, 0) |
||||
} |
||||
|
||||
func (db *cachingDB) CopyTrie(t Trie) Trie { |
||||
switch t := t.(type) { |
||||
case cachedTrie: |
||||
return cachedTrie{t.SecureTrie.Copy(), db} |
||||
case *trie.SecureTrie: |
||||
return t.Copy() |
||||
default: |
||||
panic(fmt.Errorf("unknown trie type %T", t)) |
||||
} |
||||
} |
||||
|
||||
func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error) { |
||||
code, err := db.db.Get(codeHash[:]) |
||||
if err == nil { |
||||
db.codeSizeCache.Add(codeHash, len(code)) |
||||
} |
||||
return code, err |
||||
} |
||||
|
||||
func (db *cachingDB) ContractCodeSize(addrHash, codeHash common.Hash) (int, error) { |
||||
if cached, ok := db.codeSizeCache.Get(codeHash); ok { |
||||
return cached.(int), nil |
||||
} |
||||
code, err := db.ContractCode(addrHash, codeHash) |
||||
if err == nil { |
||||
db.codeSizeCache.Add(codeHash, len(code)) |
||||
} |
||||
return len(code), err |
||||
} |
||||
|
||||
// cachedTrie inserts its trie into a cachingDB on commit.
|
||||
type cachedTrie struct { |
||||
*trie.SecureTrie |
||||
db *cachingDB |
||||
} |
||||
|
||||
func (m cachedTrie) CommitTo(dbw trie.DatabaseWriter) (common.Hash, error) { |
||||
root, err := m.SecureTrie.CommitTo(dbw) |
||||
if err == nil { |
||||
m.db.pushTrie(m.SecureTrie) |
||||
} |
||||
return root, err |
||||
} |
@ -1,316 +0,0 @@ |
||||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package light |
||||
|
||||
import ( |
||||
"context" |
||||
"math/big" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/crypto" |
||||
) |
||||
|
||||
// LightState is a memory representation of a state.
|
||||
// This version is ODR capable, caching only the already accessed part of the
|
||||
// state, retrieving unknown parts on-demand from the ODR backend. Changes are
|
||||
// never stored in the local database, only in the memory objects.
|
||||
type LightState struct { |
||||
odr OdrBackend |
||||
trie *LightTrie |
||||
id *TrieID |
||||
stateObjects map[string]*StateObject |
||||
refund *big.Int |
||||
} |
||||
|
||||
// NewLightState creates a new LightState with the specified root.
|
||||
// Note that the creation of a light state is always successful, even if the
|
||||
// root is non-existent. In that case, ODR retrieval will always be unsuccessful
|
||||
// and every operation will return with an error or wait for the context to be
|
||||
// cancelled.
|
||||
func NewLightState(id *TrieID, odr OdrBackend) *LightState { |
||||
var tr *LightTrie |
||||
if id != nil { |
||||
tr = NewLightTrie(id, odr, true) |
||||
} |
||||
return &LightState{ |
||||
odr: odr, |
||||
trie: tr, |
||||
id: id, |
||||
stateObjects: make(map[string]*StateObject), |
||||
refund: new(big.Int), |
||||
} |
||||
} |
||||
|
||||
// AddRefund adds an amount to the refund value collected during a vm execution
|
||||
func (self *LightState) AddRefund(gas *big.Int) { |
||||
self.refund.Add(self.refund, gas) |
||||
} |
||||
|
||||
// HasAccount returns true if an account exists at the given address
|
||||
func (self *LightState) HasAccount(ctx context.Context, addr common.Address) (bool, error) { |
||||
so, err := self.GetStateObject(ctx, addr) |
||||
return so != nil, err |
||||
} |
||||
|
||||
// GetBalance retrieves the balance from the given address or 0 if the account does
|
||||
// not exist
|
||||
func (self *LightState) GetBalance(ctx context.Context, addr common.Address) (*big.Int, error) { |
||||
stateObject, err := self.GetStateObject(ctx, addr) |
||||
if err != nil { |
||||
return common.Big0, err |
||||
} |
||||
if stateObject != nil { |
||||
return stateObject.balance, nil |
||||
} |
||||
|
||||
return common.Big0, nil |
||||
} |
||||
|
||||
// GetNonce returns the nonce at the given address or 0 if the account does
|
||||
// not exist
|
||||
func (self *LightState) GetNonce(ctx context.Context, addr common.Address) (uint64, error) { |
||||
stateObject, err := self.GetStateObject(ctx, addr) |
||||
if err != nil { |
||||
return 0, err |
||||
} |
||||
if stateObject != nil { |
||||
return stateObject.nonce, nil |
||||
} |
||||
return 0, nil |
||||
} |
||||
|
||||
// GetCode returns the contract code at the given address or nil if the account
|
||||
// does not exist
|
||||
func (self *LightState) GetCode(ctx context.Context, addr common.Address) ([]byte, error) { |
||||
stateObject, err := self.GetStateObject(ctx, addr) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
if stateObject != nil { |
||||
return stateObject.code, nil |
||||
} |
||||
return nil, nil |
||||
} |
||||
|
||||
// GetState returns the contract storage value at storage address b from the
|
||||
// contract address a or common.Hash{} if the account does not exist
|
||||
func (self *LightState) GetState(ctx context.Context, a common.Address, b common.Hash) (common.Hash, error) { |
||||
stateObject, err := self.GetStateObject(ctx, a) |
||||
if err == nil && stateObject != nil { |
||||
return stateObject.GetState(ctx, b) |
||||
} |
||||
return common.Hash{}, err |
||||
} |
||||
|
||||
// HasSuicided returns true if the given account has been marked for deletion
|
||||
// or false if the account does not exist
|
||||
func (self *LightState) HasSuicided(ctx context.Context, addr common.Address) (bool, error) { |
||||
stateObject, err := self.GetStateObject(ctx, addr) |
||||
if err == nil && stateObject != nil { |
||||
return stateObject.remove, nil |
||||
} |
||||
return false, err |
||||
} |
||||
|
||||
/* |
||||
* SETTERS |
||||
*/ |
||||
|
||||
// AddBalance adds the given amount to the balance of the specified account
|
||||
func (self *LightState) AddBalance(ctx context.Context, addr common.Address, amount *big.Int) error { |
||||
stateObject, err := self.GetOrNewStateObject(ctx, addr) |
||||
if err == nil && stateObject != nil { |
||||
stateObject.AddBalance(amount) |
||||
} |
||||
return err |
||||
} |
||||
|
||||
// SubBalance adds the given amount to the balance of the specified account
|
||||
func (self *LightState) SubBalance(ctx context.Context, addr common.Address, amount *big.Int) error { |
||||
stateObject, err := self.GetOrNewStateObject(ctx, addr) |
||||
if err == nil && stateObject != nil { |
||||
stateObject.SubBalance(amount) |
||||
} |
||||
return err |
||||
} |
||||
|
||||
// SetNonce sets the nonce of the specified account
|
||||
func (self *LightState) SetNonce(ctx context.Context, addr common.Address, nonce uint64) error { |
||||
stateObject, err := self.GetOrNewStateObject(ctx, addr) |
||||
if err == nil && stateObject != nil { |
||||
stateObject.SetNonce(nonce) |
||||
} |
||||
return err |
||||
} |
||||
|
||||
// SetCode sets the contract code at the specified account
|
||||
func (self *LightState) SetCode(ctx context.Context, addr common.Address, code []byte) error { |
||||
stateObject, err := self.GetOrNewStateObject(ctx, addr) |
||||
if err == nil && stateObject != nil { |
||||
stateObject.SetCode(crypto.Keccak256Hash(code), code) |
||||
} |
||||
return err |
||||
} |
||||
|
||||
// SetState sets the storage value at storage address key of the account addr
|
||||
func (self *LightState) SetState(ctx context.Context, addr common.Address, key common.Hash, value common.Hash) error { |
||||
stateObject, err := self.GetOrNewStateObject(ctx, addr) |
||||
if err == nil && stateObject != nil { |
||||
stateObject.SetState(key, value) |
||||
} |
||||
return err |
||||
} |
||||
|
||||
// Delete marks an account to be removed and clears its balance
|
||||
func (self *LightState) Suicide(ctx context.Context, addr common.Address) (bool, error) { |
||||
stateObject, err := self.GetOrNewStateObject(ctx, addr) |
||||
if err == nil && stateObject != nil { |
||||
stateObject.MarkForDeletion() |
||||
stateObject.balance = new(big.Int) |
||||
|
||||
return true, nil |
||||
} |
||||
|
||||
return false, err |
||||
} |
||||
|
||||
//
|
||||
// Get, set, new state object methods
|
||||
//
|
||||
|
||||
// GetStateObject returns the state object of the given account or nil if the
|
||||
// account does not exist
|
||||
func (self *LightState) GetStateObject(ctx context.Context, addr common.Address) (stateObject *StateObject, err error) { |
||||
stateObject = self.stateObjects[addr.Str()] |
||||
if stateObject != nil { |
||||
if stateObject.deleted { |
||||
stateObject = nil |
||||
} |
||||
return stateObject, nil |
||||
} |
||||
data, err := self.trie.Get(ctx, addr[:]) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
if len(data) == 0 { |
||||
return nil, nil |
||||
} |
||||
|
||||
stateObject, err = DecodeObject(ctx, self.id, addr, self.odr, []byte(data)) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
self.SetStateObject(stateObject) |
||||
|
||||
return stateObject, nil |
||||
} |
||||
|
||||
// SetStateObject sets the state object of the given account
|
||||
func (self *LightState) SetStateObject(object *StateObject) { |
||||
self.stateObjects[object.Address().Str()] = object |
||||
} |
||||
|
||||
// GetOrNewStateObject returns the state object of the given account or creates a
|
||||
// new one if the account does not exist
|
||||
func (self *LightState) GetOrNewStateObject(ctx context.Context, addr common.Address) (*StateObject, error) { |
||||
stateObject, err := self.GetStateObject(ctx, addr) |
||||
if err == nil && (stateObject == nil || stateObject.deleted) { |
||||
stateObject, err = self.CreateStateObject(ctx, addr) |
||||
} |
||||
return stateObject, err |
||||
} |
||||
|
||||
// newStateObject creates a state object whether it exists in the state or not
|
||||
func (self *LightState) newStateObject(addr common.Address) *StateObject { |
||||
stateObject := NewStateObject(addr, self.odr) |
||||
self.stateObjects[addr.Str()] = stateObject |
||||
|
||||
return stateObject |
||||
} |
||||
|
||||
// CreateStateObject creates creates a new state object and takes ownership.
|
||||
// This is different from "NewStateObject"
|
||||
func (self *LightState) CreateStateObject(ctx context.Context, addr common.Address) (*StateObject, error) { |
||||
// Get previous (if any)
|
||||
so, err := self.GetStateObject(ctx, addr) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
// Create a new one
|
||||
newSo := self.newStateObject(addr) |
||||
|
||||
// If it existed set the balance to the new account
|
||||
if so != nil { |
||||
newSo.balance = so.balance |
||||
} |
||||
|
||||
return newSo, nil |
||||
} |
||||
|
||||
// ForEachStorage calls a callback function for every key/value pair found
|
||||
// in the local storage cache. Note that unlike core/state.StateObject,
|
||||
// light.StateObject only returns cached values and doesn't download the
|
||||
// entire storage tree.
|
||||
func (self *LightState) ForEachStorage(ctx context.Context, addr common.Address, cb func(key, value common.Hash) bool) error { |
||||
so, err := self.GetStateObject(ctx, addr) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
if so == nil { |
||||
return nil |
||||
} |
||||
|
||||
for h, v := range so.storage { |
||||
cb(h, v) |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
//
|
||||
// Setting, copying of the state methods
|
||||
//
|
||||
|
||||
// Copy creates a copy of the state
|
||||
func (self *LightState) Copy() *LightState { |
||||
// ignore error - we assume state-to-be-copied always exists
|
||||
state := NewLightState(nil, self.odr) |
||||
state.trie = self.trie |
||||
state.id = self.id |
||||
for k, stateObject := range self.stateObjects { |
||||
if stateObject.dirty { |
||||
state.stateObjects[k] = stateObject.Copy() |
||||
} |
||||
} |
||||
|
||||
state.refund.Set(self.refund) |
||||
return state |
||||
} |
||||
|
||||
// Set copies the contents of the given state onto this state, overwriting
|
||||
// its contents
|
||||
func (self *LightState) Set(state *LightState) { |
||||
self.trie = state.trie |
||||
self.stateObjects = state.stateObjects |
||||
self.refund = state.refund |
||||
} |
||||
|
||||
// GetRefund returns the refund value collected during a vm execution
|
||||
func (self *LightState) GetRefund() *big.Int { |
||||
return self.refund |
||||
} |
@ -1,275 +0,0 @@ |
||||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package light |
||||
|
||||
import ( |
||||
"bytes" |
||||
"context" |
||||
"fmt" |
||||
"math/big" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/crypto" |
||||
"github.com/ethereum/go-ethereum/rlp" |
||||
) |
||||
|
||||
var emptyCodeHash = crypto.Keccak256(nil) |
||||
|
||||
// Code represents a contract code in binary form
|
||||
type Code []byte |
||||
|
||||
// String returns a string representation of the code
|
||||
func (self Code) String() string { |
||||
return string(self) //strings.Join(Disassemble(self), " ")
|
||||
} |
||||
|
||||
// Storage is a memory map cache of a contract storage
|
||||
type Storage map[common.Hash]common.Hash |
||||
|
||||
// String returns a string representation of the storage cache
|
||||
func (self Storage) String() (str string) { |
||||
for key, value := range self { |
||||
str += fmt.Sprintf("%X : %X\n", key, value) |
||||
} |
||||
|
||||
return |
||||
} |
||||
|
||||
// Copy copies the contents of a storage cache
|
||||
func (self Storage) Copy() Storage { |
||||
cpy := make(Storage) |
||||
for key, value := range self { |
||||
cpy[key] = value |
||||
} |
||||
|
||||
return cpy |
||||
} |
||||
|
||||
// StateObject is a memory representation of an account or contract and its storage.
|
||||
// This version is ODR capable, caching only the already accessed part of the
|
||||
// storage, retrieving unknown parts on-demand from the ODR backend. Changes are
|
||||
// never stored in the local database, only in the memory objects.
|
||||
type StateObject struct { |
||||
odr OdrBackend |
||||
trie *LightTrie |
||||
|
||||
// Address belonging to this account
|
||||
address common.Address |
||||
// The balance of the account
|
||||
balance *big.Int |
||||
// The nonce of the account
|
||||
nonce uint64 |
||||
// The code hash if code is present (i.e. a contract)
|
||||
codeHash []byte |
||||
// The code for this account
|
||||
code Code |
||||
// Cached storage (flushed when updated)
|
||||
storage Storage |
||||
|
||||
// Mark for deletion
|
||||
// When an object is marked for deletion it will be delete from the trie
|
||||
// during the "update" phase of the state transition
|
||||
remove bool |
||||
deleted bool |
||||
dirty bool |
||||
} |
||||
|
||||
// NewStateObject creates a new StateObject of the specified account address
|
||||
func NewStateObject(address common.Address, odr OdrBackend) *StateObject { |
||||
object := &StateObject{ |
||||
odr: odr, |
||||
address: address, |
||||
balance: new(big.Int), |
||||
dirty: true, |
||||
codeHash: emptyCodeHash, |
||||
storage: make(Storage), |
||||
} |
||||
object.trie = NewLightTrie(&TrieID{}, odr, true) |
||||
return object |
||||
} |
||||
|
||||
// MarkForDeletion marks an account to be removed
|
||||
func (self *StateObject) MarkForDeletion() { |
||||
self.remove = true |
||||
self.dirty = true |
||||
} |
||||
|
||||
// getAddr gets the storage value at the given address from the trie
|
||||
func (c *StateObject) getAddr(ctx context.Context, addr common.Hash) (common.Hash, error) { |
||||
var ret []byte |
||||
val, err := c.trie.Get(ctx, addr[:]) |
||||
if err != nil { |
||||
return common.Hash{}, err |
||||
} |
||||
rlp.DecodeBytes(val, &ret) |
||||
return common.BytesToHash(ret), nil |
||||
} |
||||
|
||||
// Storage returns the storage cache object of the account
|
||||
func (self *StateObject) Storage() Storage { |
||||
return self.storage |
||||
} |
||||
|
||||
// GetState returns the storage value at the given address from either the cache
|
||||
// or the trie
|
||||
func (self *StateObject) GetState(ctx context.Context, key common.Hash) (common.Hash, error) { |
||||
value, exists := self.storage[key] |
||||
if !exists { |
||||
var err error |
||||
value, err = self.getAddr(ctx, key) |
||||
if err != nil { |
||||
return common.Hash{}, err |
||||
} |
||||
if (value != common.Hash{}) { |
||||
self.storage[key] = value |
||||
} |
||||
} |
||||
|
||||
return value, nil |
||||
} |
||||
|
||||
// SetState sets the storage value at the given address
|
||||
func (self *StateObject) SetState(k, value common.Hash) { |
||||
self.storage[k] = value |
||||
self.dirty = true |
||||
} |
||||
|
||||
// AddBalance adds the given amount to the account balance
|
||||
func (c *StateObject) AddBalance(amount *big.Int) { |
||||
c.SetBalance(new(big.Int).Add(c.balance, amount)) |
||||
} |
||||
|
||||
// SubBalance subtracts the given amount from the account balance
|
||||
func (c *StateObject) SubBalance(amount *big.Int) { |
||||
c.SetBalance(new(big.Int).Sub(c.balance, amount)) |
||||
} |
||||
|
||||
// SetBalance sets the account balance to the given amount
|
||||
func (c *StateObject) SetBalance(amount *big.Int) { |
||||
c.balance = amount |
||||
c.dirty = true |
||||
} |
||||
|
||||
// ReturnGas returns the gas back to the origin. Used by the Virtual machine or Closures
|
||||
func (c *StateObject) ReturnGas(gas *big.Int) {} |
||||
|
||||
// Copy creates a copy of the state object
|
||||
func (self *StateObject) Copy() *StateObject { |
||||
stateObject := NewStateObject(self.Address(), self.odr) |
||||
stateObject.balance.Set(self.balance) |
||||
stateObject.codeHash = common.CopyBytes(self.codeHash) |
||||
stateObject.nonce = self.nonce |
||||
stateObject.trie = self.trie |
||||
stateObject.code = self.code |
||||
stateObject.storage = self.storage.Copy() |
||||
stateObject.remove = self.remove |
||||
stateObject.dirty = self.dirty |
||||
stateObject.deleted = self.deleted |
||||
|
||||
return stateObject |
||||
} |
||||
|
||||
//
|
||||
// Attribute accessors
|
||||
//
|
||||
|
||||
// empty returns whether the account is considered empty.
|
||||
func (self *StateObject) empty() bool { |
||||
return self.nonce == 0 && self.balance.Sign() == 0 && bytes.Equal(self.codeHash, emptyCodeHash) |
||||
} |
||||
|
||||
// Balance returns the account balance
|
||||
func (self *StateObject) Balance() *big.Int { |
||||
return self.balance |
||||
} |
||||
|
||||
// Address returns the address of the contract/account
|
||||
func (self *StateObject) Address() common.Address { |
||||
return self.address |
||||
} |
||||
|
||||
// Code returns the contract code
|
||||
func (self *StateObject) Code() []byte { |
||||
return self.code |
||||
} |
||||
|
||||
// SetCode sets the contract code
|
||||
func (self *StateObject) SetCode(hash common.Hash, code []byte) { |
||||
self.code = code |
||||
self.codeHash = hash[:] |
||||
self.dirty = true |
||||
} |
||||
|
||||
// SetNonce sets the account nonce
|
||||
func (self *StateObject) SetNonce(nonce uint64) { |
||||
self.nonce = nonce |
||||
self.dirty = true |
||||
} |
||||
|
||||
// Nonce returns the account nonce
|
||||
func (self *StateObject) Nonce() uint64 { |
||||
return self.nonce |
||||
} |
||||
|
||||
// ForEachStorage calls a callback function for every key/value pair found
|
||||
// in the local storage cache. Note that unlike core/state.StateObject,
|
||||
// light.StateObject only returns cached values and doesn't download the
|
||||
// entire storage tree.
|
||||
func (self *StateObject) ForEachStorage(cb func(key, value common.Hash) bool) { |
||||
for h, v := range self.storage { |
||||
cb(h, v) |
||||
} |
||||
} |
||||
|
||||
// Never called, but must be present to allow StateObject to be used
|
||||
// as a vm.Account interface that also satisfies the vm.ContractRef
|
||||
// interface. Interfaces are awesome.
|
||||
func (self *StateObject) Value() *big.Int { |
||||
panic("Value on StateObject should never be called") |
||||
} |
||||
|
||||
// Encoding
|
||||
|
||||
type extStateObject struct { |
||||
Nonce uint64 |
||||
Balance *big.Int |
||||
Root common.Hash |
||||
CodeHash []byte |
||||
} |
||||
|
||||
// DecodeObject decodes an RLP-encoded state object.
|
||||
func DecodeObject(ctx context.Context, stateID *TrieID, address common.Address, odr OdrBackend, data []byte) (*StateObject, error) { |
||||
var ( |
||||
obj = &StateObject{address: address, odr: odr, storage: make(Storage)} |
||||
ext extStateObject |
||||
err error |
||||
) |
||||
if err = rlp.DecodeBytes(data, &ext); err != nil { |
||||
return nil, err |
||||
} |
||||
trieID := StorageTrieID(stateID, address, ext.Root) |
||||
obj.trie = NewLightTrie(trieID, odr, true) |
||||
if !bytes.Equal(ext.CodeHash, emptyCodeHash) { |
||||
if obj.code, err = retrieveContractCode(ctx, obj.odr, trieID, common.BytesToHash(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 |
||||
} |
@ -1,248 +0,0 @@ |
||||
// Copyright 2015 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package light |
||||
|
||||
import ( |
||||
"bytes" |
||||
"context" |
||||
"math/big" |
||||
"testing" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/core" |
||||
"github.com/ethereum/go-ethereum/core/state" |
||||
"github.com/ethereum/go-ethereum/core/types" |
||||
"github.com/ethereum/go-ethereum/ethdb" |
||||
) |
||||
|
||||
func makeTestState() (common.Hash, ethdb.Database) { |
||||
sdb, _ := ethdb.NewMemDatabase() |
||||
st, _ := state.New(common.Hash{}, sdb) |
||||
for i := byte(0); i < 100; i++ { |
||||
addr := common.Address{i} |
||||
for j := byte(0); j < 100; j++ { |
||||
st.SetState(addr, common.Hash{j}, common.Hash{i, j}) |
||||
} |
||||
st.SetNonce(addr, 100) |
||||
st.AddBalance(addr, big.NewInt(int64(i))) |
||||
st.SetCode(addr, []byte{i, i, i}) |
||||
} |
||||
root, _ := st.Commit(false) |
||||
return root, sdb |
||||
} |
||||
|
||||
func TestLightStateOdr(t *testing.T) { |
||||
root, sdb := makeTestState() |
||||
header := &types.Header{Root: root, Number: big.NewInt(0)} |
||||
core.WriteHeader(sdb, header) |
||||
ldb, _ := ethdb.NewMemDatabase() |
||||
odr := &testOdr{sdb: sdb, ldb: ldb} |
||||
ls := NewLightState(StateTrieID(header), odr) |
||||
ctx := context.Background() |
||||
|
||||
for i := byte(0); i < 100; i++ { |
||||
addr := common.Address{i} |
||||
err := ls.AddBalance(ctx, addr, big.NewInt(1000)) |
||||
if err != nil { |
||||
t.Fatalf("Error adding balance to acc[%d]: %v", i, err) |
||||
} |
||||
err = ls.SetState(ctx, addr, common.Hash{100}, common.Hash{i, 100}) |
||||
if err != nil { |
||||
t.Fatalf("Error setting storage of acc[%d]: %v", i, err) |
||||
} |
||||
} |
||||
|
||||
addr := common.Address{100} |
||||
_, err := ls.CreateStateObject(ctx, addr) |
||||
if err != nil { |
||||
t.Fatalf("Error creating state object: %v", err) |
||||
} |
||||
err = ls.SetCode(ctx, addr, []byte{100, 100, 100}) |
||||
if err != nil { |
||||
t.Fatalf("Error setting code: %v", err) |
||||
} |
||||
err = ls.AddBalance(ctx, addr, big.NewInt(1100)) |
||||
if err != nil { |
||||
t.Fatalf("Error adding balance to acc[100]: %v", err) |
||||
} |
||||
for j := byte(0); j < 101; j++ { |
||||
err = ls.SetState(ctx, addr, common.Hash{j}, common.Hash{100, j}) |
||||
if err != nil { |
||||
t.Fatalf("Error setting storage of acc[100]: %v", err) |
||||
} |
||||
} |
||||
err = ls.SetNonce(ctx, addr, 100) |
||||
if err != nil { |
||||
t.Fatalf("Error setting nonce for acc[100]: %v", err) |
||||
} |
||||
|
||||
for i := byte(0); i < 101; i++ { |
||||
addr := common.Address{i} |
||||
|
||||
bal, err := ls.GetBalance(ctx, addr) |
||||
if err != nil { |
||||
t.Fatalf("Error getting balance of acc[%d]: %v", i, err) |
||||
} |
||||
if bal.Int64() != int64(i)+1000 { |
||||
t.Fatalf("Incorrect balance at acc[%d]: expected %v, got %v", i, int64(i)+1000, bal.Int64()) |
||||
} |
||||
|
||||
nonce, err := ls.GetNonce(ctx, addr) |
||||
if err != nil { |
||||
t.Fatalf("Error getting nonce of acc[%d]: %v", i, err) |
||||
} |
||||
if nonce != 100 { |
||||
t.Fatalf("Incorrect nonce at acc[%d]: expected %v, got %v", i, 100, nonce) |
||||
} |
||||
|
||||
code, err := ls.GetCode(ctx, addr) |
||||
exp := []byte{i, i, i} |
||||
if err != nil { |
||||
t.Fatalf("Error getting code of acc[%d]: %v", i, err) |
||||
} |
||||
if !bytes.Equal(code, exp) { |
||||
t.Fatalf("Incorrect code at acc[%d]: expected %v, got %v", i, exp, code) |
||||
} |
||||
|
||||
for j := byte(0); j < 101; j++ { |
||||
exp := common.Hash{i, j} |
||||
val, err := ls.GetState(ctx, addr, common.Hash{j}) |
||||
if err != nil { |
||||
t.Fatalf("Error retrieving acc[%d].storage[%d]: %v", i, j, err) |
||||
} |
||||
if val != exp { |
||||
t.Fatalf("Retrieved wrong value from acc[%d].storage[%d]: expected %04x, got %04x", i, j, exp, val) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
func TestLightStateSetCopy(t *testing.T) { |
||||
root, sdb := makeTestState() |
||||
header := &types.Header{Root: root, Number: big.NewInt(0)} |
||||
core.WriteHeader(sdb, header) |
||||
ldb, _ := ethdb.NewMemDatabase() |
||||
odr := &testOdr{sdb: sdb, ldb: ldb} |
||||
ls := NewLightState(StateTrieID(header), odr) |
||||
ctx := context.Background() |
||||
|
||||
for i := byte(0); i < 100; i++ { |
||||
addr := common.Address{i} |
||||
err := ls.AddBalance(ctx, addr, big.NewInt(1000)) |
||||
if err != nil { |
||||
t.Fatalf("Error adding balance to acc[%d]: %v", i, err) |
||||
} |
||||
err = ls.SetState(ctx, addr, common.Hash{100}, common.Hash{i, 100}) |
||||
if err != nil { |
||||
t.Fatalf("Error setting storage of acc[%d]: %v", i, err) |
||||
} |
||||
} |
||||
|
||||
ls2 := ls.Copy() |
||||
|
||||
for i := byte(0); i < 100; i++ { |
||||
addr := common.Address{i} |
||||
err := ls2.AddBalance(ctx, addr, big.NewInt(1000)) |
||||
if err != nil { |
||||
t.Fatalf("Error adding balance to acc[%d]: %v", i, err) |
||||
} |
||||
err = ls2.SetState(ctx, addr, common.Hash{100}, common.Hash{i, 200}) |
||||
if err != nil { |
||||
t.Fatalf("Error setting storage of acc[%d]: %v", i, err) |
||||
} |
||||
} |
||||
|
||||
lsx := ls.Copy() |
||||
ls.Set(ls2) |
||||
ls2.Set(lsx) |
||||
|
||||
for i := byte(0); i < 100; i++ { |
||||
addr := common.Address{i} |
||||
// check balance in ls
|
||||
bal, err := ls.GetBalance(ctx, addr) |
||||
if err != nil { |
||||
t.Fatalf("Error getting balance to acc[%d]: %v", i, err) |
||||
} |
||||
if bal.Int64() != int64(i)+2000 { |
||||
t.Fatalf("Incorrect balance at ls.acc[%d]: expected %v, got %v", i, int64(i)+1000, bal.Int64()) |
||||
} |
||||
// check balance in ls2
|
||||
bal, err = ls2.GetBalance(ctx, addr) |
||||
if err != nil { |
||||
t.Fatalf("Error getting balance to acc[%d]: %v", i, err) |
||||
} |
||||
if bal.Int64() != int64(i)+1000 { |
||||
t.Fatalf("Incorrect balance at ls.acc[%d]: expected %v, got %v", i, int64(i)+1000, bal.Int64()) |
||||
} |
||||
// check storage in ls
|
||||
exp := common.Hash{i, 200} |
||||
val, err := ls.GetState(ctx, addr, common.Hash{100}) |
||||
if err != nil { |
||||
t.Fatalf("Error retrieving acc[%d].storage[100]: %v", i, err) |
||||
} |
||||
if val != exp { |
||||
t.Fatalf("Retrieved wrong value from acc[%d].storage[100]: expected %04x, got %04x", i, exp, val) |
||||
} |
||||
// check storage in ls2
|
||||
exp = common.Hash{i, 100} |
||||
val, err = ls2.GetState(ctx, addr, common.Hash{100}) |
||||
if err != nil { |
||||
t.Fatalf("Error retrieving acc[%d].storage[100]: %v", i, err) |
||||
} |
||||
if val != exp { |
||||
t.Fatalf("Retrieved wrong value from acc[%d].storage[100]: expected %04x, got %04x", i, exp, val) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func TestLightStateDelete(t *testing.T) { |
||||
root, sdb := makeTestState() |
||||
header := &types.Header{Root: root, Number: big.NewInt(0)} |
||||
core.WriteHeader(sdb, header) |
||||
ldb, _ := ethdb.NewMemDatabase() |
||||
odr := &testOdr{sdb: sdb, ldb: ldb} |
||||
ls := NewLightState(StateTrieID(header), odr) |
||||
ctx := context.Background() |
||||
|
||||
addr := common.Address{42} |
||||
|
||||
b, err := ls.HasAccount(ctx, addr) |
||||
if err != nil { |
||||
t.Fatalf("HasAccount error: %v", err) |
||||
} |
||||
if !b { |
||||
t.Fatalf("HasAccount returned false, expected true") |
||||
} |
||||
|
||||
b, err = ls.HasSuicided(ctx, addr) |
||||
if err != nil { |
||||
t.Fatalf("HasSuicided error: %v", err) |
||||
} |
||||
if b { |
||||
t.Fatalf("HasSuicided returned true, expected false") |
||||
} |
||||
|
||||
ls.Suicide(ctx, addr) |
||||
|
||||
b, err = ls.HasSuicided(ctx, addr) |
||||
if err != nil { |
||||
t.Fatalf("HasSuicided error: %v", err) |
||||
} |
||||
if !b { |
||||
t.Fatalf("HasSuicided returned false, expected true") |
||||
} |
||||
} |
@ -0,0 +1,83 @@ |
||||
// Copyright 2017 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package light |
||||
|
||||
import ( |
||||
"bytes" |
||||
"context" |
||||
"fmt" |
||||
"testing" |
||||
|
||||
"github.com/davecgh/go-spew/spew" |
||||
"github.com/ethereum/go-ethereum/consensus/ethash" |
||||
"github.com/ethereum/go-ethereum/core" |
||||
"github.com/ethereum/go-ethereum/core/state" |
||||
"github.com/ethereum/go-ethereum/core/vm" |
||||
"github.com/ethereum/go-ethereum/ethdb" |
||||
"github.com/ethereum/go-ethereum/event" |
||||
"github.com/ethereum/go-ethereum/params" |
||||
"github.com/ethereum/go-ethereum/trie" |
||||
) |
||||
|
||||
func TestNodeIterator(t *testing.T) { |
||||
var ( |
||||
fulldb, _ = ethdb.NewMemDatabase() |
||||
lightdb, _ = ethdb.NewMemDatabase() |
||||
gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}} |
||||
genesis = gspec.MustCommit(fulldb) |
||||
) |
||||
gspec.MustCommit(lightdb) |
||||
blockchain, _ := core.NewBlockChain(fulldb, params.TestChainConfig, ethash.NewFullFaker(), new(event.TypeMux), vm.Config{}) |
||||
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, fulldb, 4, testChainGen) |
||||
if _, err := blockchain.InsertChain(gchain); err != nil { |
||||
panic(err) |
||||
} |
||||
|
||||
ctx := context.Background() |
||||
odr := &testOdr{sdb: fulldb, ldb: lightdb} |
||||
head := blockchain.CurrentHeader() |
||||
lightTrie, _ := NewStateDatabase(ctx, head, odr).OpenTrie(head.Root) |
||||
fullTrie, _ := state.NewDatabase(fulldb).OpenTrie(head.Root) |
||||
if err := diffTries(fullTrie, lightTrie); err != nil { |
||||
t.Fatal(err) |
||||
} |
||||
} |
||||
|
||||
func diffTries(t1, t2 state.Trie) error { |
||||
i1 := trie.NewIterator(t1.NodeIterator(nil)) |
||||
i2 := trie.NewIterator(t2.NodeIterator(nil)) |
||||
for i1.Next() && i2.Next() { |
||||
if !bytes.Equal(i1.Key, i2.Key) { |
||||
spew.Dump(i2) |
||||
return fmt.Errorf("tries have different keys %x, %x", i1.Key, i2.Key) |
||||
} |
||||
if !bytes.Equal(i2.Value, i2.Value) { |
||||
return fmt.Errorf("tries differ at key %x", i1.Key) |
||||
} |
||||
} |
||||
switch { |
||||
case i1.Err != nil: |
||||
return fmt.Errorf("full trie iterator error: %v", i1.Err) |
||||
case i2.Err != nil: |
||||
return fmt.Errorf("light trie iterator error: %v", i1.Err) |
||||
case i1.Next(): |
||||
return fmt.Errorf("full trie iterator has more k/v pairs") |
||||
case i2.Next(): |
||||
return fmt.Errorf("light trie iterator has more k/v pairs") |
||||
} |
||||
return nil |
||||
} |
@ -1,194 +0,0 @@ |
||||
// Copyright 2016 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package light |
||||
|
||||
import ( |
||||
"context" |
||||
"math/big" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/core/types" |
||||
"github.com/ethereum/go-ethereum/crypto" |
||||
) |
||||
|
||||
// VMState is a wrapper for the light state that holds the actual context and
|
||||
// passes it to any state operation that requires it.
|
||||
type VMState struct { |
||||
ctx context.Context |
||||
state *LightState |
||||
snapshots []*LightState |
||||
err error |
||||
} |
||||
|
||||
func NewVMState(ctx context.Context, state *LightState) *VMState { |
||||
return &VMState{ctx: ctx, state: state} |
||||
} |
||||
|
||||
func (s *VMState) Error() error { |
||||
return s.err |
||||
} |
||||
|
||||
func (s *VMState) AddLog(log *types.Log) {} |
||||
|
||||
func (s *VMState) AddPreimage(hash common.Hash, preimage []byte) {} |
||||
|
||||
// errHandler handles and stores any state error that happens during execution.
|
||||
func (s *VMState) errHandler(err error) { |
||||
if err != nil && s.err == nil { |
||||
s.err = err |
||||
} |
||||
} |
||||
|
||||
func (self *VMState) Snapshot() int { |
||||
self.snapshots = append(self.snapshots, self.state.Copy()) |
||||
return len(self.snapshots) - 1 |
||||
} |
||||
|
||||
func (self *VMState) RevertToSnapshot(idx int) { |
||||
self.state.Set(self.snapshots[idx]) |
||||
self.snapshots = self.snapshots[:idx] |
||||
} |
||||
|
||||
// CreateAccount creates creates a new account object and takes ownership.
|
||||
func (s *VMState) CreateAccount(addr common.Address) { |
||||
_, err := s.state.CreateStateObject(s.ctx, addr) |
||||
s.errHandler(err) |
||||
} |
||||
|
||||
// AddBalance adds the given amount to the balance of the specified account
|
||||
func (s *VMState) AddBalance(addr common.Address, amount *big.Int) { |
||||
err := s.state.AddBalance(s.ctx, addr, amount) |
||||
s.errHandler(err) |
||||
} |
||||
|
||||
// SubBalance adds the given amount to the balance of the specified account
|
||||
func (s *VMState) SubBalance(addr common.Address, amount *big.Int) { |
||||
err := s.state.SubBalance(s.ctx, addr, amount) |
||||
s.errHandler(err) |
||||
} |
||||
|
||||
// ForEachStorage calls a callback function for every key/value pair found
|
||||
// in the local storage cache. Note that unlike core/state.StateObject,
|
||||
// light.StateObject only returns cached values and doesn't download the
|
||||
// entire storage tree.
|
||||
func (s *VMState) ForEachStorage(addr common.Address, cb func(key, value common.Hash) bool) { |
||||
err := s.state.ForEachStorage(s.ctx, addr, cb) |
||||
s.errHandler(err) |
||||
} |
||||
|
||||
// GetBalance retrieves the balance from the given address or 0 if the account does
|
||||
// not exist
|
||||
func (s *VMState) GetBalance(addr common.Address) *big.Int { |
||||
res, err := s.state.GetBalance(s.ctx, addr) |
||||
s.errHandler(err) |
||||
return res |
||||
} |
||||
|
||||
// GetNonce returns the nonce at the given address or 0 if the account does
|
||||
// not exist
|
||||
func (s *VMState) GetNonce(addr common.Address) uint64 { |
||||
res, err := s.state.GetNonce(s.ctx, addr) |
||||
s.errHandler(err) |
||||
return res |
||||
} |
||||
|
||||
// SetNonce sets the nonce of the specified account
|
||||
func (s *VMState) SetNonce(addr common.Address, nonce uint64) { |
||||
err := s.state.SetNonce(s.ctx, addr, nonce) |
||||
s.errHandler(err) |
||||
} |
||||
|
||||
// GetCode returns the contract code at the given address or nil if the account
|
||||
// does not exist
|
||||
func (s *VMState) GetCode(addr common.Address) []byte { |
||||
res, err := s.state.GetCode(s.ctx, addr) |
||||
s.errHandler(err) |
||||
return res |
||||
} |
||||
|
||||
// GetCodeHash returns the contract code hash at the given address
|
||||
func (s *VMState) GetCodeHash(addr common.Address) common.Hash { |
||||
res, err := s.state.GetCode(s.ctx, addr) |
||||
s.errHandler(err) |
||||
return crypto.Keccak256Hash(res) |
||||
} |
||||
|
||||
// GetCodeSize returns the contract code size at the given address
|
||||
func (s *VMState) GetCodeSize(addr common.Address) int { |
||||
res, err := s.state.GetCode(s.ctx, addr) |
||||
s.errHandler(err) |
||||
return len(res) |
||||
} |
||||
|
||||
// SetCode sets the contract code at the specified account
|
||||
func (s *VMState) SetCode(addr common.Address, code []byte) { |
||||
err := s.state.SetCode(s.ctx, addr, code) |
||||
s.errHandler(err) |
||||
} |
||||
|
||||
// AddRefund adds an amount to the refund value collected during a vm execution
|
||||
func (s *VMState) AddRefund(gas *big.Int) { |
||||
s.state.AddRefund(gas) |
||||
} |
||||
|
||||
// GetRefund returns the refund value collected during a vm execution
|
||||
func (s *VMState) GetRefund() *big.Int { |
||||
return s.state.GetRefund() |
||||
} |
||||
|
||||
// GetState returns the contract storage value at storage address b from the
|
||||
// contract address a or common.Hash{} if the account does not exist
|
||||
func (s *VMState) GetState(a common.Address, b common.Hash) common.Hash { |
||||
res, err := s.state.GetState(s.ctx, a, b) |
||||
s.errHandler(err) |
||||
return res |
||||
} |
||||
|
||||
// SetState sets the storage value at storage address key of the account addr
|
||||
func (s *VMState) SetState(addr common.Address, key common.Hash, value common.Hash) { |
||||
err := s.state.SetState(s.ctx, addr, key, value) |
||||
s.errHandler(err) |
||||
} |
||||
|
||||
// Suicide marks an account to be removed and clears its balance
|
||||
func (s *VMState) Suicide(addr common.Address) bool { |
||||
res, err := s.state.Suicide(s.ctx, addr) |
||||
s.errHandler(err) |
||||
return res |
||||
} |
||||
|
||||
// Exist returns true if an account exists at the given address
|
||||
func (s *VMState) Exist(addr common.Address) bool { |
||||
res, err := s.state.HasAccount(s.ctx, addr) |
||||
s.errHandler(err) |
||||
return res |
||||
} |
||||
|
||||
// Empty returns true if the account at the given address is considered empty
|
||||
func (s *VMState) Empty(addr common.Address) bool { |
||||
so, err := s.state.GetStateObject(s.ctx, addr) |
||||
s.errHandler(err) |
||||
return so == nil || so.empty() |
||||
} |
||||
|
||||
// HasSuicided returns true if the given account has been marked for deletion
|
||||
// or false if the account does not exist
|
||||
func (s *VMState) HasSuicided(addr common.Address) bool { |
||||
res, err := s.state.HasSuicided(s.ctx, addr) |
||||
s.errHandler(err) |
||||
return res |
||||
} |
Loading…
Reference in new issue