core, core/state, core/vm: remove exported account getters (#3618)
Removed exported statedb object accessors, reducing the chance for nasty bugs to creep in. It's also ugly and unnecessary to have these methods.
This commit is contained in:
parent
46ec4357e7
commit
024d41d0c2
@ -29,7 +29,6 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/core/vm/runtime"
|
"github.com/ethereum/go-ethereum/core/vm/runtime"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
@ -115,9 +114,13 @@ func run(ctx *cli.Context) error {
|
|||||||
glog.SetToStderr(true)
|
glog.SetToStderr(true)
|
||||||
glog.SetV(ctx.GlobalInt(VerbosityFlag.Name))
|
glog.SetV(ctx.GlobalInt(VerbosityFlag.Name))
|
||||||
|
|
||||||
db, _ := ethdb.NewMemDatabase()
|
var (
|
||||||
statedb, _ := state.New(common.Hash{}, db)
|
db, _ = ethdb.NewMemDatabase()
|
||||||
sender := statedb.CreateAccount(common.StringToAddress("sender"))
|
statedb, _ = state.New(common.Hash{}, db)
|
||||||
|
address = common.StringToAddress("sender")
|
||||||
|
sender = vm.AccountRef(address)
|
||||||
|
)
|
||||||
|
statedb.CreateAccount(common.StringToAddress("sender"))
|
||||||
|
|
||||||
logger := vm.NewStructLogger(nil)
|
logger := vm.NewStructLogger(nil)
|
||||||
|
|
||||||
@ -166,10 +169,11 @@ func run(ctx *cli.Context) error {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
receiver := statedb.CreateAccount(common.StringToAddress("receiver"))
|
receiverAddress := common.StringToAddress("receiver")
|
||||||
receiver.SetCode(crypto.Keccak256Hash(code), code)
|
statedb.CreateAccount(receiverAddress)
|
||||||
|
statedb.SetCode(receiverAddress, code)
|
||||||
|
|
||||||
ret, err = runtime.Call(receiver.Address(), common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtime.Config{
|
ret, err = runtime.Call(receiverAddress, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtime.Config{
|
||||||
Origin: sender.Address(),
|
Origin: sender.Address(),
|
||||||
State: statedb,
|
State: statedb,
|
||||||
GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)).Uint64(),
|
GasLimit: common.Big(ctx.GlobalString(GasFlag.Name)).Uint64(),
|
||||||
|
@ -214,7 +214,6 @@ func (self *BlockChain) loadLastState() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
self.stateCache = statedb
|
self.stateCache = statedb
|
||||||
self.stateCache.GetAccount(common.Address{})
|
|
||||||
|
|
||||||
// Issue a status log for the user
|
// Issue a status log for the user
|
||||||
headerTd := self.GetTd(currentHeader.Hash(), currentHeader.Number.Uint64())
|
headerTd := self.GetTd(currentHeader.Hash(), currentHeader.Number.Uint64())
|
||||||
|
10
core/dao.go
10
core/dao.go
@ -62,13 +62,13 @@ func ValidateDAOHeaderExtraData(config *params.ChainConfig, header *types.Header
|
|||||||
// contract.
|
// contract.
|
||||||
func ApplyDAOHardFork(statedb *state.StateDB) {
|
func ApplyDAOHardFork(statedb *state.StateDB) {
|
||||||
// Retrieve the contract to refund balances into
|
// Retrieve the contract to refund balances into
|
||||||
refund := statedb.GetOrNewStateObject(params.DAORefundContract)
|
if !statedb.Exist(params.DAORefundContract) {
|
||||||
|
statedb.CreateAccount(params.DAORefundContract)
|
||||||
|
}
|
||||||
|
|
||||||
// Move every DAO account and extra-balance account funds into the refund contract
|
// Move every DAO account and extra-balance account funds into the refund contract
|
||||||
for _, addr := range params.DAODrainList {
|
for _, addr := range params.DAODrainList {
|
||||||
if account := statedb.GetStateObject(addr); account != nil {
|
statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr))
|
||||||
refund.AddBalance(account.Balance())
|
statedb.SetBalance(addr, new(big.Int))
|
||||||
account.SetBalance(new(big.Int))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ type (
|
|||||||
account *common.Address
|
account *common.Address
|
||||||
}
|
}
|
||||||
resetObjectChange struct {
|
resetObjectChange struct {
|
||||||
prev *StateObject
|
prev *stateObject
|
||||||
}
|
}
|
||||||
suicideChange struct {
|
suicideChange struct {
|
||||||
account *common.Address
|
account *common.Address
|
||||||
@ -86,7 +86,7 @@ func (ch resetObjectChange) undo(s *StateDB) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ch suicideChange) undo(s *StateDB) {
|
func (ch suicideChange) undo(s *StateDB) {
|
||||||
obj := s.GetStateObject(*ch.account)
|
obj := s.getStateObject(*ch.account)
|
||||||
if obj != nil {
|
if obj != nil {
|
||||||
obj.suicided = ch.prev
|
obj.suicided = ch.prev
|
||||||
obj.setBalance(ch.prevbalance)
|
obj.setBalance(ch.prevbalance)
|
||||||
@ -103,19 +103,19 @@ func (ch touchChange) undo(s *StateDB) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ch balanceChange) undo(s *StateDB) {
|
func (ch balanceChange) undo(s *StateDB) {
|
||||||
s.GetStateObject(*ch.account).setBalance(ch.prev)
|
s.getStateObject(*ch.account).setBalance(ch.prev)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch nonceChange) undo(s *StateDB) {
|
func (ch nonceChange) undo(s *StateDB) {
|
||||||
s.GetStateObject(*ch.account).setNonce(ch.prev)
|
s.getStateObject(*ch.account).setNonce(ch.prev)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch codeChange) undo(s *StateDB) {
|
func (ch codeChange) undo(s *StateDB) {
|
||||||
s.GetStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode)
|
s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch storageChange) undo(s *StateDB) {
|
func (ch storageChange) undo(s *StateDB) {
|
||||||
s.GetStateObject(*ch.account).setState(ch.key, ch.prevalue)
|
s.getStateObject(*ch.account).setState(ch.key, ch.prevalue)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ch refundChange) undo(s *StateDB) {
|
func (ch refundChange) undo(s *StateDB) {
|
||||||
|
@ -23,7 +23,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type account struct {
|
type account struct {
|
||||||
stateObject *StateObject
|
stateObject *stateObject
|
||||||
nstart uint64
|
nstart uint64
|
||||||
nonces []bool
|
nonces []bool
|
||||||
}
|
}
|
||||||
@ -128,7 +128,7 @@ func (ms *ManagedState) getAccount(addr common.Address) *account {
|
|||||||
} 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[addr] = newAccount(so)
|
ms.accounts[addr] = newAccount(so)
|
||||||
}
|
}
|
||||||
@ -138,6 +138,6 @@ func (ms *ManagedState) getAccount(addr common.Address) *account {
|
|||||||
return ms.accounts[addr]
|
return ms.accounts[addr]
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAccount(so *StateObject) *account {
|
func newAccount(so *stateObject) *account {
|
||||||
return &account{so, so.Nonce(), nil}
|
return &account{so, so.Nonce(), nil}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ func create() (*ManagedState, *account) {
|
|||||||
statedb, _ := New(common.Hash{}, db)
|
statedb, _ := New(common.Hash{}, db)
|
||||||
ms := ManageState(statedb)
|
ms := ManageState(statedb)
|
||||||
ms.StateDB.SetNonce(addr, 100)
|
ms.StateDB.SetNonce(addr, 100)
|
||||||
ms.accounts[addr] = newAccount(ms.StateDB.GetStateObject(addr))
|
ms.accounts[addr] = newAccount(ms.StateDB.getStateObject(addr))
|
||||||
return ms, ms.accounts[addr]
|
return ms, ms.accounts[addr]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,13 +57,13 @@ func (self Storage) Copy() Storage {
|
|||||||
return cpy
|
return cpy
|
||||||
}
|
}
|
||||||
|
|
||||||
// StateObject represents an Ethereum account which is being modified.
|
// stateObject represents an Ethereum account which is being modified.
|
||||||
//
|
//
|
||||||
// The usage pattern is as follows:
|
// The usage pattern is as follows:
|
||||||
// First you need to obtain a state object.
|
// First you need to obtain a state object.
|
||||||
// Account values can be accessed and modified through the object.
|
// Account values can be accessed and modified through the object.
|
||||||
// Finally, call CommitTrie to write the modified storage trie into a database.
|
// Finally, call CommitTrie to write the modified storage trie into a database.
|
||||||
type StateObject struct {
|
type stateObject struct {
|
||||||
address common.Address // Ethereum address of this account
|
address common.Address // Ethereum address of this account
|
||||||
data Account
|
data Account
|
||||||
db *StateDB
|
db *StateDB
|
||||||
@ -93,7 +93,7 @@ type StateObject struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// empty returns whether the account is considered empty.
|
// empty returns whether the account is considered empty.
|
||||||
func (s *StateObject) empty() bool {
|
func (s *stateObject) empty() bool {
|
||||||
return s.data.Nonce == 0 && s.data.Balance.BitLen() == 0 && bytes.Equal(s.data.CodeHash, emptyCodeHash)
|
return s.data.Nonce == 0 && s.data.Balance.BitLen() == 0 && bytes.Equal(s.data.CodeHash, emptyCodeHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,29 +107,29 @@ type Account struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// newObject creates a state object.
|
// newObject creates a state object.
|
||||||
func newObject(db *StateDB, address common.Address, data Account, onDirty func(addr common.Address)) *StateObject {
|
func newObject(db *StateDB, address common.Address, data Account, onDirty func(addr common.Address)) *stateObject {
|
||||||
if data.Balance == nil {
|
if data.Balance == nil {
|
||||||
data.Balance = new(big.Int)
|
data.Balance = new(big.Int)
|
||||||
}
|
}
|
||||||
if data.CodeHash == nil {
|
if data.CodeHash == nil {
|
||||||
data.CodeHash = emptyCodeHash
|
data.CodeHash = emptyCodeHash
|
||||||
}
|
}
|
||||||
return &StateObject{db: db, address: address, data: data, cachedStorage: make(Storage), dirtyStorage: make(Storage), onDirty: onDirty}
|
return &stateObject{db: db, address: address, data: data, cachedStorage: make(Storage), dirtyStorage: make(Storage), onDirty: onDirty}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeRLP implements rlp.Encoder.
|
// EncodeRLP implements rlp.Encoder.
|
||||||
func (c *StateObject) EncodeRLP(w io.Writer) error {
|
func (c *stateObject) EncodeRLP(w io.Writer) error {
|
||||||
return rlp.Encode(w, c.data)
|
return rlp.Encode(w, c.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// setError remembers the first non-nil error it is called with.
|
// setError remembers the first non-nil error it is called with.
|
||||||
func (self *StateObject) setError(err error) {
|
func (self *stateObject) setError(err error) {
|
||||||
if self.dbErr == nil {
|
if self.dbErr == nil {
|
||||||
self.dbErr = err
|
self.dbErr = err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateObject) markSuicided() {
|
func (self *stateObject) markSuicided() {
|
||||||
self.suicided = true
|
self.suicided = true
|
||||||
if self.onDirty != nil {
|
if self.onDirty != nil {
|
||||||
self.onDirty(self.Address())
|
self.onDirty(self.Address())
|
||||||
@ -140,7 +140,7 @@ func (self *StateObject) markSuicided() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StateObject) touch() {
|
func (c *stateObject) touch() {
|
||||||
c.db.journal = append(c.db.journal, touchChange{
|
c.db.journal = append(c.db.journal, touchChange{
|
||||||
account: &c.address,
|
account: &c.address,
|
||||||
prev: c.touched,
|
prev: c.touched,
|
||||||
@ -152,7 +152,7 @@ func (c *StateObject) touch() {
|
|||||||
c.touched = true
|
c.touched = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *StateObject) getTrie(db trie.Database) *trie.SecureTrie {
|
func (c *stateObject) getTrie(db trie.Database) *trie.SecureTrie {
|
||||||
if c.trie == nil {
|
if c.trie == nil {
|
||||||
var err error
|
var err error
|
||||||
c.trie, err = trie.NewSecure(c.data.Root, db, 0)
|
c.trie, err = trie.NewSecure(c.data.Root, db, 0)
|
||||||
@ -165,7 +165,7 @@ func (c *StateObject) getTrie(db trie.Database) *trie.SecureTrie {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetState returns a value in account storage.
|
// GetState returns a value in account storage.
|
||||||
func (self *StateObject) GetState(db trie.Database, key common.Hash) common.Hash {
|
func (self *stateObject) GetState(db trie.Database, key common.Hash) common.Hash {
|
||||||
value, exists := self.cachedStorage[key]
|
value, exists := self.cachedStorage[key]
|
||||||
if exists {
|
if exists {
|
||||||
return value
|
return value
|
||||||
@ -185,7 +185,7 @@ func (self *StateObject) GetState(db trie.Database, key common.Hash) common.Hash
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetState updates a value in account storage.
|
// SetState updates a value in account storage.
|
||||||
func (self *StateObject) SetState(db trie.Database, key, value common.Hash) {
|
func (self *stateObject) SetState(db trie.Database, key, value common.Hash) {
|
||||||
self.db.journal = append(self.db.journal, storageChange{
|
self.db.journal = append(self.db.journal, storageChange{
|
||||||
account: &self.address,
|
account: &self.address,
|
||||||
key: key,
|
key: key,
|
||||||
@ -194,7 +194,7 @@ func (self *StateObject) SetState(db trie.Database, key, value common.Hash) {
|
|||||||
self.setState(key, value)
|
self.setState(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateObject) setState(key, value common.Hash) {
|
func (self *stateObject) setState(key, value common.Hash) {
|
||||||
self.cachedStorage[key] = value
|
self.cachedStorage[key] = value
|
||||||
self.dirtyStorage[key] = value
|
self.dirtyStorage[key] = value
|
||||||
|
|
||||||
@ -205,7 +205,7 @@ func (self *StateObject) setState(key, value common.Hash) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// updateTrie writes cached storage modifications into the object's storage trie.
|
// updateTrie writes cached storage modifications into the object's storage trie.
|
||||||
func (self *StateObject) updateTrie(db trie.Database) {
|
func (self *stateObject) updateTrie(db trie.Database) {
|
||||||
tr := self.getTrie(db)
|
tr := self.getTrie(db)
|
||||||
for key, value := range self.dirtyStorage {
|
for key, value := range self.dirtyStorage {
|
||||||
delete(self.dirtyStorage, key)
|
delete(self.dirtyStorage, key)
|
||||||
@ -220,14 +220,14 @@ func (self *StateObject) updateTrie(db trie.Database) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateRoot sets the trie root to the current root hash of
|
// UpdateRoot sets the trie root to the current root hash of
|
||||||
func (self *StateObject) updateRoot(db trie.Database) {
|
func (self *stateObject) updateRoot(db trie.Database) {
|
||||||
self.updateTrie(db)
|
self.updateTrie(db)
|
||||||
self.data.Root = self.trie.Hash()
|
self.data.Root = self.trie.Hash()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommitTrie the storage trie of the object to dwb.
|
// CommitTrie the storage trie of the object to dwb.
|
||||||
// This updates the trie root.
|
// This updates the trie root.
|
||||||
func (self *StateObject) CommitTrie(db trie.Database, dbw trie.DatabaseWriter) error {
|
func (self *stateObject) CommitTrie(db trie.Database, dbw trie.DatabaseWriter) error {
|
||||||
self.updateTrie(db)
|
self.updateTrie(db)
|
||||||
if self.dbErr != nil {
|
if self.dbErr != nil {
|
||||||
return self.dbErr
|
return self.dbErr
|
||||||
@ -241,7 +241,7 @@ func (self *StateObject) CommitTrie(db trie.Database, dbw trie.DatabaseWriter) e
|
|||||||
|
|
||||||
// AddBalance removes amount from c's balance.
|
// AddBalance removes amount from c's balance.
|
||||||
// It is used to add funds to the destination account of a transfer.
|
// It is used to add funds to the destination account of a transfer.
|
||||||
func (c *StateObject) AddBalance(amount *big.Int) {
|
func (c *stateObject) AddBalance(amount *big.Int) {
|
||||||
// EIP158: We must check emptiness for the objects such that the account
|
// EIP158: We must check emptiness for the objects such that the account
|
||||||
// clearing (0,0,0 objects) can take effect.
|
// clearing (0,0,0 objects) can take effect.
|
||||||
if amount.Cmp(common.Big0) == 0 {
|
if amount.Cmp(common.Big0) == 0 {
|
||||||
@ -260,7 +260,7 @@ func (c *StateObject) AddBalance(amount *big.Int) {
|
|||||||
|
|
||||||
// SubBalance removes amount from c's balance.
|
// SubBalance removes amount from c's balance.
|
||||||
// It is used to remove funds from the origin account of a transfer.
|
// It is used to remove funds from the origin account of a transfer.
|
||||||
func (c *StateObject) SubBalance(amount *big.Int) {
|
func (c *stateObject) SubBalance(amount *big.Int) {
|
||||||
if amount.Cmp(common.Big0) == 0 {
|
if amount.Cmp(common.Big0) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -271,7 +271,7 @@ func (c *StateObject) SubBalance(amount *big.Int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateObject) SetBalance(amount *big.Int) {
|
func (self *stateObject) SetBalance(amount *big.Int) {
|
||||||
self.db.journal = append(self.db.journal, balanceChange{
|
self.db.journal = append(self.db.journal, balanceChange{
|
||||||
account: &self.address,
|
account: &self.address,
|
||||||
prev: new(big.Int).Set(self.data.Balance),
|
prev: new(big.Int).Set(self.data.Balance),
|
||||||
@ -279,7 +279,7 @@ func (self *StateObject) SetBalance(amount *big.Int) {
|
|||||||
self.setBalance(amount)
|
self.setBalance(amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateObject) setBalance(amount *big.Int) {
|
func (self *stateObject) setBalance(amount *big.Int) {
|
||||||
self.data.Balance = amount
|
self.data.Balance = amount
|
||||||
if self.onDirty != nil {
|
if self.onDirty != nil {
|
||||||
self.onDirty(self.Address())
|
self.onDirty(self.Address())
|
||||||
@ -288,9 +288,9 @@ func (self *StateObject) setBalance(amount *big.Int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return the gas back to the origin. Used by the Virtual machine or Closures
|
// Return the gas back to the origin. Used by the Virtual machine or Closures
|
||||||
func (c *StateObject) ReturnGas(gas *big.Int) {}
|
func (c *stateObject) ReturnGas(gas *big.Int) {}
|
||||||
|
|
||||||
func (self *StateObject) deepCopy(db *StateDB, onDirty func(addr common.Address)) *StateObject {
|
func (self *stateObject) deepCopy(db *StateDB, onDirty func(addr common.Address)) *stateObject {
|
||||||
stateObject := newObject(db, self.address, self.data, onDirty)
|
stateObject := newObject(db, self.address, self.data, onDirty)
|
||||||
stateObject.trie = self.trie
|
stateObject.trie = self.trie
|
||||||
stateObject.code = self.code
|
stateObject.code = self.code
|
||||||
@ -307,12 +307,12 @@ func (self *StateObject) deepCopy(db *StateDB, onDirty func(addr common.Address)
|
|||||||
//
|
//
|
||||||
|
|
||||||
// Returns the address of the contract/account
|
// Returns the address of the contract/account
|
||||||
func (c *StateObject) Address() common.Address {
|
func (c *stateObject) Address() common.Address {
|
||||||
return c.address
|
return c.address
|
||||||
}
|
}
|
||||||
|
|
||||||
// Code returns the contract code associated with this object, if any.
|
// Code returns the contract code associated with this object, if any.
|
||||||
func (self *StateObject) Code(db trie.Database) []byte {
|
func (self *stateObject) Code(db trie.Database) []byte {
|
||||||
if self.code != nil {
|
if self.code != nil {
|
||||||
return self.code
|
return self.code
|
||||||
}
|
}
|
||||||
@ -327,7 +327,7 @@ func (self *StateObject) Code(db trie.Database) []byte {
|
|||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateObject) SetCode(codeHash common.Hash, code []byte) {
|
func (self *stateObject) SetCode(codeHash common.Hash, code []byte) {
|
||||||
prevcode := self.Code(self.db.db)
|
prevcode := self.Code(self.db.db)
|
||||||
self.db.journal = append(self.db.journal, codeChange{
|
self.db.journal = append(self.db.journal, codeChange{
|
||||||
account: &self.address,
|
account: &self.address,
|
||||||
@ -337,7 +337,7 @@ func (self *StateObject) SetCode(codeHash common.Hash, code []byte) {
|
|||||||
self.setCode(codeHash, code)
|
self.setCode(codeHash, code)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateObject) setCode(codeHash common.Hash, code []byte) {
|
func (self *stateObject) setCode(codeHash common.Hash, code []byte) {
|
||||||
self.code = code
|
self.code = code
|
||||||
self.data.CodeHash = codeHash[:]
|
self.data.CodeHash = codeHash[:]
|
||||||
self.dirtyCode = true
|
self.dirtyCode = true
|
||||||
@ -347,7 +347,7 @@ func (self *StateObject) setCode(codeHash common.Hash, code []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateObject) SetNonce(nonce uint64) {
|
func (self *stateObject) SetNonce(nonce uint64) {
|
||||||
self.db.journal = append(self.db.journal, nonceChange{
|
self.db.journal = append(self.db.journal, nonceChange{
|
||||||
account: &self.address,
|
account: &self.address,
|
||||||
prev: self.data.Nonce,
|
prev: self.data.Nonce,
|
||||||
@ -355,7 +355,7 @@ func (self *StateObject) SetNonce(nonce uint64) {
|
|||||||
self.setNonce(nonce)
|
self.setNonce(nonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateObject) setNonce(nonce uint64) {
|
func (self *stateObject) setNonce(nonce uint64) {
|
||||||
self.data.Nonce = nonce
|
self.data.Nonce = nonce
|
||||||
if self.onDirty != nil {
|
if self.onDirty != nil {
|
||||||
self.onDirty(self.Address())
|
self.onDirty(self.Address())
|
||||||
@ -363,37 +363,21 @@ func (self *StateObject) setNonce(nonce uint64) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateObject) CodeHash() []byte {
|
func (self *stateObject) CodeHash() []byte {
|
||||||
return self.data.CodeHash
|
return self.data.CodeHash
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateObject) Balance() *big.Int {
|
func (self *stateObject) Balance() *big.Int {
|
||||||
return self.data.Balance
|
return self.data.Balance
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateObject) Nonce() uint64 {
|
func (self *stateObject) Nonce() uint64 {
|
||||||
return self.data.Nonce
|
return self.data.Nonce
|
||||||
}
|
}
|
||||||
|
|
||||||
// Never called, but must be present to allow StateObject to be used
|
// Never called, but must be present to allow stateObject to be used
|
||||||
// as a vm.Account interface that also satisfies the vm.ContractRef
|
// as a vm.Account interface that also satisfies the vm.ContractRef
|
||||||
// interface. Interfaces are awesome.
|
// interface. Interfaces are awesome.
|
||||||
func (self *StateObject) Value() *big.Int {
|
func (self *stateObject) Value() *big.Int {
|
||||||
panic("Value on StateObject should never be called")
|
panic("Value on stateObject should never be called")
|
||||||
}
|
|
||||||
|
|
||||||
func (self *StateObject) ForEachStorage(cb func(key, value common.Hash) bool) {
|
|
||||||
// When iterating over the storage check the cache first
|
|
||||||
for h, value := range self.cachedStorage {
|
|
||||||
cb(h, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
it := self.getTrie(self.db.db).Iterator()
|
|
||||||
for it.Next() {
|
|
||||||
// ignore cached values
|
|
||||||
key := common.BytesToHash(self.trie.GetKey(it.Key))
|
|
||||||
if _, ok := self.cachedStorage[key]; !ok {
|
|
||||||
cb(key, common.BytesToHash(it.Value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,7 @@ func TestSnapshot2(t *testing.T) {
|
|||||||
state.SetState(stateobjaddr1, storageaddr, data1)
|
state.SetState(stateobjaddr1, storageaddr, data1)
|
||||||
|
|
||||||
// db, trie are already non-empty values
|
// db, trie are already non-empty values
|
||||||
so0 := state.GetStateObject(stateobjaddr0)
|
so0 := state.getStateObject(stateobjaddr0)
|
||||||
so0.SetBalance(big.NewInt(42))
|
so0.SetBalance(big.NewInt(42))
|
||||||
so0.SetNonce(43)
|
so0.SetNonce(43)
|
||||||
so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'})
|
so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'})
|
||||||
@ -164,7 +164,7 @@ func TestSnapshot2(t *testing.T) {
|
|||||||
state.Reset(root)
|
state.Reset(root)
|
||||||
|
|
||||||
// and one with deleted == true
|
// and one with deleted == true
|
||||||
so1 := state.GetStateObject(stateobjaddr1)
|
so1 := state.getStateObject(stateobjaddr1)
|
||||||
so1.SetBalance(big.NewInt(52))
|
so1.SetBalance(big.NewInt(52))
|
||||||
so1.SetNonce(53)
|
so1.SetNonce(53)
|
||||||
so1.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e', '2'}), []byte{'c', 'a', 'f', 'e', '2'})
|
so1.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e', '2'}), []byte{'c', 'a', 'f', 'e', '2'})
|
||||||
@ -172,7 +172,7 @@ func TestSnapshot2(t *testing.T) {
|
|||||||
so1.deleted = true
|
so1.deleted = true
|
||||||
state.setStateObject(so1)
|
state.setStateObject(so1)
|
||||||
|
|
||||||
so1 = state.GetStateObject(stateobjaddr1)
|
so1 = state.getStateObject(stateobjaddr1)
|
||||||
if so1 != nil {
|
if so1 != nil {
|
||||||
t.Fatalf("deleted object not nil when getting")
|
t.Fatalf("deleted object not nil when getting")
|
||||||
}
|
}
|
||||||
@ -180,7 +180,7 @@ func TestSnapshot2(t *testing.T) {
|
|||||||
snapshot := state.Snapshot()
|
snapshot := state.Snapshot()
|
||||||
state.RevertToSnapshot(snapshot)
|
state.RevertToSnapshot(snapshot)
|
||||||
|
|
||||||
so0Restored := state.GetStateObject(stateobjaddr0)
|
so0Restored := state.getStateObject(stateobjaddr0)
|
||||||
// Update lazily-loaded values before comparing.
|
// Update lazily-loaded values before comparing.
|
||||||
so0Restored.GetState(db, storageaddr)
|
so0Restored.GetState(db, storageaddr)
|
||||||
so0Restored.Code(db)
|
so0Restored.Code(db)
|
||||||
@ -188,13 +188,13 @@ func TestSnapshot2(t *testing.T) {
|
|||||||
compareStateObjects(so0Restored, so0, t)
|
compareStateObjects(so0Restored, so0, t)
|
||||||
|
|
||||||
// deleted should be nil, both before and after restore of state copy
|
// deleted should be nil, both before and after restore of state copy
|
||||||
so1Restored := state.GetStateObject(stateobjaddr1)
|
so1Restored := state.getStateObject(stateobjaddr1)
|
||||||
if so1Restored != nil {
|
if so1Restored != nil {
|
||||||
t.Fatalf("deleted object not nil after restoring snapshot: %+v", so1Restored)
|
t.Fatalf("deleted object not nil after restoring snapshot: %+v", so1Restored)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareStateObjects(so0, so1 *StateObject, t *testing.T) {
|
func compareStateObjects(so0, so1 *stateObject, t *testing.T) {
|
||||||
if so0.Address() != so1.Address() {
|
if so0.Address() != so1.Address() {
|
||||||
t.Fatalf("Address mismatch: have %v, want %v", so0.address, so1.address)
|
t.Fatalf("Address mismatch: have %v, want %v", so0.address, so1.address)
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,6 @@ import (
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
@ -64,7 +63,7 @@ type StateDB struct {
|
|||||||
codeSizeCache *lru.Cache
|
codeSizeCache *lru.Cache
|
||||||
|
|
||||||
// This map holds 'live' objects, which will get modified while processing a state transition.
|
// This map holds 'live' objects, which will get modified while processing a state transition.
|
||||||
stateObjects map[common.Address]*StateObject
|
stateObjects map[common.Address]*stateObject
|
||||||
stateObjectsDirty map[common.Address]struct{}
|
stateObjectsDirty map[common.Address]struct{}
|
||||||
|
|
||||||
// The refund counter, also used by state transitioning.
|
// The refund counter, also used by state transitioning.
|
||||||
@ -97,7 +96,7 @@ func New(root common.Hash, db ethdb.Database) (*StateDB, error) {
|
|||||||
db: db,
|
db: db,
|
||||||
trie: tr,
|
trie: tr,
|
||||||
codeSizeCache: csc,
|
codeSizeCache: csc,
|
||||||
stateObjects: make(map[common.Address]*StateObject),
|
stateObjects: make(map[common.Address]*stateObject),
|
||||||
stateObjectsDirty: make(map[common.Address]struct{}),
|
stateObjectsDirty: make(map[common.Address]struct{}),
|
||||||
refund: new(big.Int),
|
refund: new(big.Int),
|
||||||
logs: make(map[common.Hash][]*types.Log),
|
logs: make(map[common.Hash][]*types.Log),
|
||||||
@ -119,7 +118,7 @@ func (self *StateDB) New(root common.Hash) (*StateDB, error) {
|
|||||||
db: self.db,
|
db: self.db,
|
||||||
trie: tr,
|
trie: tr,
|
||||||
codeSizeCache: self.codeSizeCache,
|
codeSizeCache: self.codeSizeCache,
|
||||||
stateObjects: make(map[common.Address]*StateObject),
|
stateObjects: make(map[common.Address]*stateObject),
|
||||||
stateObjectsDirty: make(map[common.Address]struct{}),
|
stateObjectsDirty: make(map[common.Address]struct{}),
|
||||||
refund: new(big.Int),
|
refund: new(big.Int),
|
||||||
logs: make(map[common.Hash][]*types.Log),
|
logs: make(map[common.Hash][]*types.Log),
|
||||||
@ -138,7 +137,7 @@ func (self *StateDB) Reset(root common.Hash) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
self.trie = tr
|
self.trie = tr
|
||||||
self.stateObjects = make(map[common.Address]*StateObject)
|
self.stateObjects = make(map[common.Address]*stateObject)
|
||||||
self.stateObjectsDirty = make(map[common.Address]struct{})
|
self.stateObjectsDirty = make(map[common.Address]struct{})
|
||||||
self.thash = common.Hash{}
|
self.thash = common.Hash{}
|
||||||
self.bhash = common.Hash{}
|
self.bhash = common.Hash{}
|
||||||
@ -227,23 +226,19 @@ func (self *StateDB) AddRefund(gas *big.Int) {
|
|||||||
// Exist reports whether the given account address exists in the state.
|
// Exist reports whether the given account address exists in the state.
|
||||||
// Notably this also returns true for suicided accounts.
|
// Notably this also returns true for suicided accounts.
|
||||||
func (self *StateDB) Exist(addr common.Address) bool {
|
func (self *StateDB) Exist(addr common.Address) bool {
|
||||||
return self.GetStateObject(addr) != nil
|
return self.getStateObject(addr) != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Empty returns whether the state object is either non-existent
|
// Empty returns whether the state object is either non-existent
|
||||||
// or empty according to the EIP161 specification (balance = nonce = code = 0)
|
// or empty according to the EIP161 specification (balance = nonce = code = 0)
|
||||||
func (self *StateDB) Empty(addr common.Address) bool {
|
func (self *StateDB) Empty(addr common.Address) bool {
|
||||||
so := self.GetStateObject(addr)
|
so := self.getStateObject(addr)
|
||||||
return so == nil || so.empty()
|
return so == nil || so.empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) GetAccount(addr common.Address) vm.Account {
|
|
||||||
return self.GetStateObject(addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
||||||
stateObject := self.GetStateObject(addr)
|
stateObject := self.getStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
return stateObject.Balance()
|
return stateObject.Balance()
|
||||||
}
|
}
|
||||||
@ -251,7 +246,7 @@ func (self *StateDB) GetBalance(addr common.Address) *big.Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) GetNonce(addr common.Address) uint64 {
|
func (self *StateDB) GetNonce(addr common.Address) uint64 {
|
||||||
stateObject := self.GetStateObject(addr)
|
stateObject := self.getStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
return stateObject.Nonce()
|
return stateObject.Nonce()
|
||||||
}
|
}
|
||||||
@ -260,7 +255,7 @@ func (self *StateDB) GetNonce(addr common.Address) uint64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) GetCode(addr common.Address) []byte {
|
func (self *StateDB) GetCode(addr common.Address) []byte {
|
||||||
stateObject := self.GetStateObject(addr)
|
stateObject := self.getStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
code := stateObject.Code(self.db)
|
code := stateObject.Code(self.db)
|
||||||
key := common.BytesToHash(stateObject.CodeHash())
|
key := common.BytesToHash(stateObject.CodeHash())
|
||||||
@ -271,7 +266,7 @@ func (self *StateDB) GetCode(addr common.Address) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) GetCodeSize(addr common.Address) int {
|
func (self *StateDB) GetCodeSize(addr common.Address) int {
|
||||||
stateObject := self.GetStateObject(addr)
|
stateObject := self.getStateObject(addr)
|
||||||
if stateObject == nil {
|
if stateObject == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@ -287,7 +282,7 @@ func (self *StateDB) GetCodeSize(addr common.Address) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) GetCodeHash(addr common.Address) common.Hash {
|
func (self *StateDB) GetCodeHash(addr common.Address) common.Hash {
|
||||||
stateObject := self.GetStateObject(addr)
|
stateObject := self.getStateObject(addr)
|
||||||
if stateObject == nil {
|
if stateObject == nil {
|
||||||
return common.Hash{}
|
return common.Hash{}
|
||||||
}
|
}
|
||||||
@ -295,7 +290,7 @@ func (self *StateDB) GetCodeHash(addr common.Address) common.Hash {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) GetState(a common.Address, b common.Hash) common.Hash {
|
func (self *StateDB) GetState(a common.Address, b common.Hash) common.Hash {
|
||||||
stateObject := self.GetStateObject(a)
|
stateObject := self.getStateObject(a)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
return stateObject.GetState(self.db, b)
|
return stateObject.GetState(self.db, b)
|
||||||
}
|
}
|
||||||
@ -303,7 +298,7 @@ func (self *StateDB) GetState(a common.Address, b common.Hash) common.Hash {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) HasSuicided(addr common.Address) bool {
|
func (self *StateDB) HasSuicided(addr common.Address) bool {
|
||||||
stateObject := self.GetStateObject(addr)
|
stateObject := self.getStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
return stateObject.suicided
|
return stateObject.suicided
|
||||||
}
|
}
|
||||||
@ -362,9 +357,9 @@ func (self *StateDB) SetState(addr common.Address, key common.Hash, value common
|
|||||||
// This clears the account balance.
|
// This clears the account balance.
|
||||||
//
|
//
|
||||||
// The account's state object is still available until the state is committed,
|
// The account's state object is still available until the state is committed,
|
||||||
// GetStateObject will return a non-nil account after Suicide.
|
// getStateObject will return a non-nil account after Suicide.
|
||||||
func (self *StateDB) Suicide(addr common.Address) bool {
|
func (self *StateDB) Suicide(addr common.Address) bool {
|
||||||
stateObject := self.GetStateObject(addr)
|
stateObject := self.getStateObject(addr)
|
||||||
if stateObject == nil {
|
if stateObject == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -383,7 +378,7 @@ func (self *StateDB) Suicide(addr common.Address) bool {
|
|||||||
//
|
//
|
||||||
|
|
||||||
// updateStateObject writes the given object to the trie.
|
// updateStateObject writes the given object to the trie.
|
||||||
func (self *StateDB) updateStateObject(stateObject *StateObject) {
|
func (self *StateDB) updateStateObject(stateObject *stateObject) {
|
||||||
addr := stateObject.Address()
|
addr := stateObject.Address()
|
||||||
data, err := rlp.EncodeToBytes(stateObject)
|
data, err := rlp.EncodeToBytes(stateObject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -393,14 +388,14 @@ func (self *StateDB) updateStateObject(stateObject *StateObject) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// deleteStateObject removes the given object from the state trie.
|
// deleteStateObject removes the given object from the state trie.
|
||||||
func (self *StateDB) deleteStateObject(stateObject *StateObject) {
|
func (self *StateDB) deleteStateObject(stateObject *stateObject) {
|
||||||
stateObject.deleted = true
|
stateObject.deleted = true
|
||||||
addr := stateObject.Address()
|
addr := stateObject.Address()
|
||||||
self.trie.Delete(addr[:])
|
self.trie.Delete(addr[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve a state object given my the address. Returns nil if not found.
|
// Retrieve a state object given my the address. Returns nil if not found.
|
||||||
func (self *StateDB) GetStateObject(addr common.Address) (stateObject *StateObject) {
|
func (self *StateDB) getStateObject(addr common.Address) (stateObject *stateObject) {
|
||||||
// Prefer 'live' objects.
|
// Prefer 'live' objects.
|
||||||
if obj := self.stateObjects[addr]; obj != nil {
|
if obj := self.stateObjects[addr]; obj != nil {
|
||||||
if obj.deleted {
|
if obj.deleted {
|
||||||
@ -425,13 +420,13 @@ func (self *StateDB) GetStateObject(addr common.Address) (stateObject *StateObje
|
|||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) setStateObject(object *StateObject) {
|
func (self *StateDB) setStateObject(object *stateObject) {
|
||||||
self.stateObjects[object.Address()] = object
|
self.stateObjects[object.Address()] = object
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 {
|
||||||
stateObject := self.GetStateObject(addr)
|
stateObject := self.getStateObject(addr)
|
||||||
if stateObject == nil || stateObject.deleted {
|
if stateObject == nil || stateObject.deleted {
|
||||||
stateObject, _ = self.createObject(addr)
|
stateObject, _ = self.createObject(addr)
|
||||||
}
|
}
|
||||||
@ -446,8 +441,8 @@ func (self *StateDB) MarkStateObjectDirty(addr common.Address) {
|
|||||||
|
|
||||||
// createObject creates a new state object. If there is an existing account with
|
// createObject creates a new state object. If there is an existing account with
|
||||||
// the given address, it is overwritten and returned as the second return value.
|
// the given address, it is overwritten and returned as the second return value.
|
||||||
func (self *StateDB) createObject(addr common.Address) (newobj, prev *StateObject) {
|
func (self *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) {
|
||||||
prev = self.GetStateObject(addr)
|
prev = self.getStateObject(addr)
|
||||||
newobj = newObject(self, addr, Account{}, self.MarkStateObjectDirty)
|
newobj = newObject(self, addr, Account{}, self.MarkStateObjectDirty)
|
||||||
newobj.setNonce(0) // sets the object to dirty
|
newobj.setNonce(0) // sets the object to dirty
|
||||||
if prev == nil {
|
if prev == nil {
|
||||||
@ -472,12 +467,32 @@ func (self *StateDB) createObject(addr common.Address) (newobj, prev *StateObjec
|
|||||||
// 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1)
|
// 2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1)
|
||||||
//
|
//
|
||||||
// Carrying over the balance ensures that Ether doesn't disappear.
|
// Carrying over the balance ensures that Ether doesn't disappear.
|
||||||
func (self *StateDB) CreateAccount(addr common.Address) vm.Account {
|
func (self *StateDB) CreateAccount(addr common.Address) {
|
||||||
new, prev := self.createObject(addr)
|
new, prev := self.createObject(addr)
|
||||||
if prev != nil {
|
if prev != nil {
|
||||||
new.setBalance(prev.data.Balance)
|
new.setBalance(prev.data.Balance)
|
||||||
}
|
}
|
||||||
return new
|
}
|
||||||
|
|
||||||
|
func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common.Hash) bool) {
|
||||||
|
so := db.getStateObject(addr)
|
||||||
|
if so == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// When iterating over the storage check the cache first
|
||||||
|
for h, value := range so.cachedStorage {
|
||||||
|
cb(h, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
it := so.getTrie(db.db).Iterator()
|
||||||
|
for it.Next() {
|
||||||
|
// ignore cached values
|
||||||
|
key := common.BytesToHash(db.trie.GetKey(it.Key))
|
||||||
|
if _, ok := so.cachedStorage[key]; !ok {
|
||||||
|
cb(key, common.BytesToHash(it.Value))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy creates a deep, independent copy of the state.
|
// Copy creates a deep, independent copy of the state.
|
||||||
@ -492,7 +507,7 @@ func (self *StateDB) Copy() *StateDB {
|
|||||||
trie: self.trie,
|
trie: self.trie,
|
||||||
pastTries: self.pastTries,
|
pastTries: self.pastTries,
|
||||||
codeSizeCache: self.codeSizeCache,
|
codeSizeCache: self.codeSizeCache,
|
||||||
stateObjects: make(map[common.Address]*StateObject, len(self.stateObjectsDirty)),
|
stateObjects: make(map[common.Address]*stateObject, len(self.stateObjectsDirty)),
|
||||||
stateObjectsDirty: make(map[common.Address]struct{}, len(self.stateObjectsDirty)),
|
stateObjectsDirty: make(map[common.Address]struct{}, len(self.stateObjectsDirty)),
|
||||||
refund: new(big.Int).Set(self.refund),
|
refund: new(big.Int).Set(self.refund),
|
||||||
logs: make(map[common.Hash][]*types.Log, len(self.logs)),
|
logs: make(map[common.Hash][]*types.Log, len(self.logs)),
|
||||||
|
@ -331,12 +331,11 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error {
|
|||||||
checkeq("GetCodeHash", state.GetCodeHash(addr), checkstate.GetCodeHash(addr))
|
checkeq("GetCodeHash", state.GetCodeHash(addr), checkstate.GetCodeHash(addr))
|
||||||
checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr))
|
checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr))
|
||||||
// Check storage.
|
// Check storage.
|
||||||
if obj := state.GetStateObject(addr); obj != nil {
|
if obj := state.getStateObject(addr); obj != nil {
|
||||||
obj.ForEachStorage(func(key, val common.Hash) bool {
|
state.ForEachStorage(addr, func(key, val common.Hash) bool {
|
||||||
return checkeq("GetState("+key.Hex()+")", val, checkstate.GetState(addr, key))
|
return checkeq("GetState("+key.Hex()+")", val, checkstate.GetState(addr, key))
|
||||||
})
|
})
|
||||||
checkobj := checkstate.GetStateObject(addr)
|
checkstate.ForEachStorage(addr, func(key, checkval common.Hash) bool {
|
||||||
checkobj.ForEachStorage(func(key, checkval common.Hash) bool {
|
|
||||||
return checkeq("GetState("+key.Hex()+")", state.GetState(addr, key), checkval)
|
return checkeq("GetState("+key.Hex()+")", state.GetState(addr, key), checkval)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
@ -28,7 +28,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
Big0 = big.NewInt(0)
|
Big0 = big.NewInt(0)
|
||||||
|
errInsufficientBalanceForGas = errors.New("insufficient balance to pay for gas")
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -136,27 +137,28 @@ func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, *big.Int, erro
|
|||||||
return ret, gasUsed, err
|
return ret, gasUsed, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateTransition) from() vm.Account {
|
func (self *StateTransition) from() vm.AccountRef {
|
||||||
f := self.msg.From()
|
f := self.msg.From()
|
||||||
if !self.state.Exist(f) {
|
if !self.state.Exist(f) {
|
||||||
return self.state.CreateAccount(f)
|
self.state.CreateAccount(f)
|
||||||
}
|
}
|
||||||
return self.state.GetAccount(f)
|
return vm.AccountRef(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateTransition) to() vm.Account {
|
func (self *StateTransition) to() vm.AccountRef {
|
||||||
if self.msg == nil {
|
if self.msg == nil {
|
||||||
return nil
|
return vm.AccountRef{}
|
||||||
}
|
}
|
||||||
to := self.msg.To()
|
to := self.msg.To()
|
||||||
if to == nil {
|
if to == nil {
|
||||||
return nil // contract creation
|
return vm.AccountRef{} // contract creation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reference := vm.AccountRef(*to)
|
||||||
if !self.state.Exist(*to) {
|
if !self.state.Exist(*to) {
|
||||||
return self.state.CreateAccount(*to)
|
self.state.CreateAccount(*to)
|
||||||
}
|
}
|
||||||
return self.state.GetAccount(*to)
|
return reference
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateTransition) useGas(amount uint64) error {
|
func (self *StateTransition) useGas(amount uint64) error {
|
||||||
@ -176,9 +178,12 @@ func (self *StateTransition) buyGas() error {
|
|||||||
|
|
||||||
mgval := new(big.Int).Mul(mgas, self.gasPrice)
|
mgval := new(big.Int).Mul(mgas, self.gasPrice)
|
||||||
|
|
||||||
sender := self.from()
|
var (
|
||||||
if sender.Balance().Cmp(mgval) < 0 {
|
state = self.state
|
||||||
return fmt.Errorf("insufficient ETH for gas (%x). Req %v, has %v", sender.Address().Bytes()[:4], mgval, sender.Balance())
|
sender = self.from()
|
||||||
|
)
|
||||||
|
if state.GetBalance(sender.Address()).Cmp(mgval) < 0 {
|
||||||
|
return errInsufficientBalanceForGas
|
||||||
}
|
}
|
||||||
if err := self.gp.SubGas(mgas); err != nil {
|
if err := self.gp.SubGas(mgas); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -186,7 +191,7 @@ func (self *StateTransition) buyGas() error {
|
|||||||
self.gas += mgas.Uint64()
|
self.gas += mgas.Uint64()
|
||||||
|
|
||||||
self.initialGas.Set(mgas)
|
self.initialGas.Set(mgas)
|
||||||
sender.SubBalance(mgval)
|
state.SubBalance(sender.Address(), mgval)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,7 +277,7 @@ func (self *StateTransition) refundGas() {
|
|||||||
// exchanged at the original rate.
|
// exchanged at the original rate.
|
||||||
sender := self.from() // err already checked
|
sender := self.from() // err already checked
|
||||||
remaining := new(big.Int).Mul(new(big.Int).SetUint64(self.gas), self.gasPrice)
|
remaining := new(big.Int).Mul(new(big.Int).SetUint64(self.gas), self.gasPrice)
|
||||||
sender.AddBalance(remaining)
|
self.state.AddBalance(sender.Address(), remaining)
|
||||||
|
|
||||||
// Apply refund counter, capped to half of the used gas.
|
// Apply refund counter, capped to half of the used gas.
|
||||||
uhalf := remaining.Div(self.gasUsed(), common.Big2)
|
uhalf := remaining.Div(self.gasUsed(), common.Big2)
|
||||||
|
@ -25,11 +25,20 @@ import (
|
|||||||
// ContractRef is a reference to the contract's backing object
|
// ContractRef is a reference to the contract's backing object
|
||||||
type ContractRef interface {
|
type ContractRef interface {
|
||||||
Address() common.Address
|
Address() common.Address
|
||||||
Value() *big.Int
|
|
||||||
SetCode(common.Hash, []byte)
|
|
||||||
ForEachStorage(callback func(key, value common.Hash) bool)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AccountRef implements ContractRef.
|
||||||
|
//
|
||||||
|
// Account references are used during EVM initialisation and
|
||||||
|
// it's primary use is to fetch addresses. Removing this object
|
||||||
|
// proves difficult because of the cached jump destinations which
|
||||||
|
// are fetched from the parent contract (i.e. the caller), which
|
||||||
|
// is a ContractRef.
|
||||||
|
type AccountRef common.Address
|
||||||
|
|
||||||
|
// Address casts AccountRef to a Address
|
||||||
|
func (ar AccountRef) Address() common.Address { return (common.Address)(ar) }
|
||||||
|
|
||||||
// Contract represents an ethereum contract in the state database. It contains
|
// Contract represents an ethereum contract in the state database. It contains
|
||||||
// the the contract code, calling arguments. Contract implements ContractRef
|
// the the contract code, calling arguments. Contract implements ContractRef
|
||||||
type Contract struct {
|
type Contract struct {
|
||||||
@ -69,7 +78,8 @@ func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uin
|
|||||||
// Gas should be a pointer so it can safely be reduced through the run
|
// Gas should be a pointer so it can safely be reduced through the run
|
||||||
// This pointer will be off the state transition
|
// This pointer will be off the state transition
|
||||||
c.Gas = gas
|
c.Gas = gas
|
||||||
c.value = new(big.Int).Set(value)
|
// ensures a value is set
|
||||||
|
c.value = value
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
@ -80,7 +90,10 @@ func (c *Contract) AsDelegate() *Contract {
|
|||||||
c.DelegateCall = true
|
c.DelegateCall = true
|
||||||
// NOTE: caller must, at all times be a contract. It should never happen
|
// NOTE: caller must, at all times be a contract. It should never happen
|
||||||
// that caller is something other than a Contract.
|
// that caller is something other than a Contract.
|
||||||
c.CallerAddress = c.caller.(*Contract).CallerAddress
|
parent := c.caller.(*Contract)
|
||||||
|
c.CallerAddress = parent.CallerAddress
|
||||||
|
c.value = parent.value
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,9 +151,3 @@ func (self *Contract) SetCallCode(addr *common.Address, hash common.Hash, code [
|
|||||||
self.CodeHash = hash
|
self.CodeHash = hash
|
||||||
self.CodeAddr = addr
|
self.CodeAddr = addr
|
||||||
}
|
}
|
||||||
|
|
||||||
// EachStorage iterates the contract's storage and calls a method for every key
|
|
||||||
// value pair.
|
|
||||||
func (self *Contract) ForEachStorage(cb func(key, value common.Hash) bool) {
|
|
||||||
self.caller.ForEachStorage(cb)
|
|
||||||
}
|
|
||||||
|
@ -116,7 +116,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
to Account
|
to = AccountRef(addr)
|
||||||
snapshot = evm.StateDB.Snapshot()
|
snapshot = evm.StateDB.Snapshot()
|
||||||
)
|
)
|
||||||
if !evm.StateDB.Exist(addr) {
|
if !evm.StateDB.Exist(addr) {
|
||||||
@ -124,9 +124,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
|||||||
return nil, gas, nil
|
return nil, gas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
to = evm.StateDB.CreateAccount(addr)
|
evm.StateDB.CreateAccount(addr)
|
||||||
} else {
|
|
||||||
to = evm.StateDB.GetAccount(addr)
|
|
||||||
}
|
}
|
||||||
evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)
|
evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)
|
||||||
|
|
||||||
@ -169,7 +167,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
snapshot = evm.StateDB.Snapshot()
|
snapshot = evm.StateDB.Snapshot()
|
||||||
to = evm.StateDB.GetAccount(caller.Address())
|
to = AccountRef(caller.Address())
|
||||||
)
|
)
|
||||||
// initialise a new contract and set the code that is to be used by the
|
// initialise a new contract and set the code that is to be used by the
|
||||||
// E The contract is a scoped evmironment for this execution context
|
// E The contract is a scoped evmironment for this execution context
|
||||||
@ -205,11 +203,11 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
snapshot = evm.StateDB.Snapshot()
|
snapshot = evm.StateDB.Snapshot()
|
||||||
to = evm.StateDB.GetAccount(caller.Address())
|
to = AccountRef(caller.Address())
|
||||||
)
|
)
|
||||||
|
|
||||||
// Iinitialise a new contract and make initialise the delegate values
|
// Iinitialise a new contract and make initialise the delegate values
|
||||||
contract := NewContract(caller, to, caller.Value(), gas).AsDelegate()
|
contract := NewContract(caller, to, nil, gas).AsDelegate()
|
||||||
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
|
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
|
||||||
|
|
||||||
ret, err = evm.interpreter.Run(contract, input)
|
ret, err = evm.interpreter.Run(contract, input)
|
||||||
@ -243,16 +241,16 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
|
|||||||
|
|
||||||
snapshot := evm.StateDB.Snapshot()
|
snapshot := evm.StateDB.Snapshot()
|
||||||
contractAddr = crypto.CreateAddress(caller.Address(), nonce)
|
contractAddr = crypto.CreateAddress(caller.Address(), nonce)
|
||||||
to := evm.StateDB.CreateAccount(contractAddr)
|
evm.StateDB.CreateAccount(contractAddr)
|
||||||
if evm.ChainConfig().IsEIP158(evm.BlockNumber) {
|
if evm.ChainConfig().IsEIP158(evm.BlockNumber) {
|
||||||
evm.StateDB.SetNonce(contractAddr, 1)
|
evm.StateDB.SetNonce(contractAddr, 1)
|
||||||
}
|
}
|
||||||
evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)
|
evm.Transfer(evm.StateDB, caller.Address(), contractAddr, value)
|
||||||
|
|
||||||
// initialise a new contract and set the code that is to be used by the
|
// initialise a new contract and set the code that is to be used by the
|
||||||
// E The contract is a scoped evmironment for this execution context
|
// E The contract is a scoped evmironment for this execution context
|
||||||
// only.
|
// only.
|
||||||
contract := NewContract(caller, to, value, gas)
|
contract := NewContract(caller, AccountRef(contractAddr), value, gas)
|
||||||
contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code)
|
contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code)
|
||||||
|
|
||||||
ret, err = evm.interpreter.Run(contract, nil)
|
ret, err = evm.interpreter.Run(contract, nil)
|
||||||
|
@ -25,8 +25,7 @@ import (
|
|||||||
|
|
||||||
// StateDB is an EVM database for full state querying.
|
// StateDB is an EVM database for full state querying.
|
||||||
type StateDB interface {
|
type StateDB interface {
|
||||||
GetAccount(common.Address) Account
|
CreateAccount(common.Address)
|
||||||
CreateAccount(common.Address) Account
|
|
||||||
|
|
||||||
SubBalance(common.Address, *big.Int)
|
SubBalance(common.Address, *big.Int)
|
||||||
AddBalance(common.Address, *big.Int)
|
AddBalance(common.Address, *big.Int)
|
||||||
@ -61,20 +60,8 @@ type StateDB interface {
|
|||||||
|
|
||||||
AddLog(*types.Log)
|
AddLog(*types.Log)
|
||||||
AddPreimage(common.Hash, []byte)
|
AddPreimage(common.Hash, []byte)
|
||||||
}
|
|
||||||
|
|
||||||
// Account represents a contract or basic ethereum account.
|
ForEachStorage(common.Address, func(common.Hash, common.Hash) bool)
|
||||||
type Account interface {
|
|
||||||
SubBalance(amount *big.Int)
|
|
||||||
AddBalance(amount *big.Int)
|
|
||||||
SetBalance(*big.Int)
|
|
||||||
SetNonce(uint64)
|
|
||||||
Balance() *big.Int
|
|
||||||
Address() common.Address
|
|
||||||
ReturnGas(*big.Int)
|
|
||||||
SetCode(common.Hash, []byte)
|
|
||||||
ForEachStorage(cb func(key, value common.Hash) bool)
|
|
||||||
Value() *big.Int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CallContext provides a basic interface for the EVM calling conventions. The EVM EVM
|
// CallContext provides a basic interface for the EVM calling conventions. The EVM EVM
|
||||||
|
@ -144,7 +144,8 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost *b
|
|||||||
storage = make(Storage)
|
storage = make(Storage)
|
||||||
// Get the contract account and loop over each storage entry. This may involve looping over
|
// Get the contract account and loop over each storage entry. This may involve looping over
|
||||||
// the trie and is a very expensive process.
|
// the trie and is a very expensive process.
|
||||||
env.StateDB.GetAccount(contract.Address()).ForEachStorage(func(key, value common.Hash) bool {
|
|
||||||
|
env.StateDB.ForEachStorage(contract.Address(), func(key, value common.Hash) bool {
|
||||||
storage[key] = value
|
storage[key] = value
|
||||||
// Return true, indicating we'd like to continue.
|
// Return true, indicating we'd like to continue.
|
||||||
return true
|
return true
|
||||||
|
@ -46,10 +46,6 @@ type dummyStateDB struct {
|
|||||||
ref *dummyContractRef
|
ref *dummyContractRef
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d dummyStateDB) GetAccount(common.Address) Account {
|
|
||||||
return d.ref
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStoreCapture(t *testing.T) {
|
func TestStoreCapture(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false})
|
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{EnableJit: false, ForceJit: false})
|
||||||
|
@ -45,26 +45,26 @@ func (NoopEVMCallContext) DelegateCall(me ContractRef, addr common.Address, data
|
|||||||
|
|
||||||
type NoopStateDB struct{}
|
type NoopStateDB struct{}
|
||||||
|
|
||||||
func (NoopStateDB) GetAccount(common.Address) Account { return nil }
|
func (NoopStateDB) CreateAccount(common.Address) {}
|
||||||
func (NoopStateDB) CreateAccount(common.Address) Account { return nil }
|
func (NoopStateDB) SubBalance(common.Address, *big.Int) {}
|
||||||
func (NoopStateDB) SubBalance(common.Address, *big.Int) {}
|
func (NoopStateDB) AddBalance(common.Address, *big.Int) {}
|
||||||
func (NoopStateDB) AddBalance(common.Address, *big.Int) {}
|
func (NoopStateDB) GetBalance(common.Address) *big.Int { return nil }
|
||||||
func (NoopStateDB) GetBalance(common.Address) *big.Int { return nil }
|
func (NoopStateDB) GetNonce(common.Address) uint64 { return 0 }
|
||||||
func (NoopStateDB) GetNonce(common.Address) uint64 { return 0 }
|
func (NoopStateDB) SetNonce(common.Address, uint64) {}
|
||||||
func (NoopStateDB) SetNonce(common.Address, uint64) {}
|
func (NoopStateDB) GetCodeHash(common.Address) common.Hash { return common.Hash{} }
|
||||||
func (NoopStateDB) GetCodeHash(common.Address) common.Hash { return common.Hash{} }
|
func (NoopStateDB) GetCode(common.Address) []byte { return nil }
|
||||||
func (NoopStateDB) GetCode(common.Address) []byte { return nil }
|
func (NoopStateDB) SetCode(common.Address, []byte) {}
|
||||||
func (NoopStateDB) SetCode(common.Address, []byte) {}
|
func (NoopStateDB) GetCodeSize(common.Address) int { return 0 }
|
||||||
func (NoopStateDB) GetCodeSize(common.Address) int { return 0 }
|
func (NoopStateDB) AddRefund(*big.Int) {}
|
||||||
func (NoopStateDB) AddRefund(*big.Int) {}
|
func (NoopStateDB) GetRefund() *big.Int { return nil }
|
||||||
func (NoopStateDB) GetRefund() *big.Int { return nil }
|
func (NoopStateDB) GetState(common.Address, common.Hash) common.Hash { return common.Hash{} }
|
||||||
func (NoopStateDB) GetState(common.Address, common.Hash) common.Hash { return common.Hash{} }
|
func (NoopStateDB) SetState(common.Address, common.Hash, common.Hash) {}
|
||||||
func (NoopStateDB) SetState(common.Address, common.Hash, common.Hash) {}
|
func (NoopStateDB) Suicide(common.Address) bool { return false }
|
||||||
func (NoopStateDB) Suicide(common.Address) bool { return false }
|
func (NoopStateDB) HasSuicided(common.Address) bool { return false }
|
||||||
func (NoopStateDB) HasSuicided(common.Address) bool { return false }
|
func (NoopStateDB) Exist(common.Address) bool { return false }
|
||||||
func (NoopStateDB) Exist(common.Address) bool { return false }
|
func (NoopStateDB) Empty(common.Address) bool { return false }
|
||||||
func (NoopStateDB) Empty(common.Address) bool { return false }
|
func (NoopStateDB) RevertToSnapshot(int) {}
|
||||||
func (NoopStateDB) RevertToSnapshot(int) {}
|
func (NoopStateDB) Snapshot() int { return 0 }
|
||||||
func (NoopStateDB) Snapshot() int { return 0 }
|
func (NoopStateDB) AddLog(*types.Log) {}
|
||||||
func (NoopStateDB) AddLog(*types.Log) {}
|
func (NoopStateDB) AddPreimage(common.Hash, []byte) {}
|
||||||
func (NoopStateDB) AddPreimage(common.Hash, []byte) {}
|
func (NoopStateDB) ForEachStorage(common.Address, func(common.Hash, common.Hash) bool) {}
|
||||||
|
@ -105,17 +105,17 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
|
|||||||
cfg.State, _ = state.New(common.Hash{}, db)
|
cfg.State, _ = state.New(common.Hash{}, db)
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
vmenv = NewEnv(cfg, cfg.State)
|
address = common.StringToAddress("contract")
|
||||||
sender = cfg.State.CreateAccount(cfg.Origin)
|
vmenv = NewEnv(cfg, cfg.State)
|
||||||
receiver = cfg.State.CreateAccount(common.StringToAddress("contract"))
|
sender = vm.AccountRef(cfg.Origin)
|
||||||
)
|
)
|
||||||
|
cfg.State.CreateAccount(address)
|
||||||
// set the receiver's (the executing contract) code for execution.
|
// set the receiver's (the executing contract) code for execution.
|
||||||
receiver.SetCode(crypto.Keccak256Hash(code), code)
|
cfg.State.SetCode(address, code)
|
||||||
|
|
||||||
// Call the code with the given configuration.
|
// Call the code with the given configuration.
|
||||||
ret, _, err := vmenv.Call(
|
ret, _, err := vmenv.Call(
|
||||||
sender,
|
sender,
|
||||||
receiver.Address(),
|
common.StringToAddress("contract"),
|
||||||
input,
|
input,
|
||||||
cfg.GasLimit,
|
cfg.GasLimit,
|
||||||
cfg.Value,
|
cfg.Value,
|
||||||
@ -137,7 +137,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, error) {
|
|||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
vmenv = NewEnv(cfg, cfg.State)
|
vmenv = NewEnv(cfg, cfg.State)
|
||||||
sender = cfg.State.CreateAccount(cfg.Origin)
|
sender = vm.AccountRef(cfg.Origin)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Call the code with the given configuration.
|
// Call the code with the given configuration.
|
||||||
|
@ -268,6 +268,26 @@ func (self *LightState) CreateStateObject(ctx context.Context, addr common.Addre
|
|||||||
return newSo, nil
|
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
|
// Setting, copying of the state methods
|
||||||
//
|
//
|
||||||
|
@ -21,7 +21,6 @@ import (
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
@ -64,27 +63,10 @@ func (self *VMState) RevertToSnapshot(idx int) {
|
|||||||
self.snapshots = self.snapshots[:idx]
|
self.snapshots = self.snapshots[:idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAccount returns the account object of the given account or nil if the
|
|
||||||
// account does not exist
|
|
||||||
func (s *VMState) GetAccount(addr common.Address) vm.Account {
|
|
||||||
so, err := s.state.GetStateObject(s.ctx, addr)
|
|
||||||
s.errHandler(err)
|
|
||||||
if err != nil {
|
|
||||||
// return a dummy state object to avoid panics
|
|
||||||
so = s.state.newStateObject(addr)
|
|
||||||
}
|
|
||||||
return so
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateAccount creates creates a new account object and takes ownership.
|
// CreateAccount creates creates a new account object and takes ownership.
|
||||||
func (s *VMState) CreateAccount(addr common.Address) vm.Account {
|
func (s *VMState) CreateAccount(addr common.Address) {
|
||||||
so, err := s.state.CreateStateObject(s.ctx, addr)
|
_, err := s.state.CreateStateObject(s.ctx, addr)
|
||||||
s.errHandler(err)
|
s.errHandler(err)
|
||||||
if err != nil {
|
|
||||||
// return a dummy state object to avoid panics
|
|
||||||
so = s.state.newStateObject(addr)
|
|
||||||
}
|
|
||||||
return so
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddBalance adds the given amount to the balance of the specified account
|
// AddBalance adds the given amount to the balance of the specified account
|
||||||
@ -99,6 +81,15 @@ func (s *VMState) SubBalance(addr common.Address, amount *big.Int) {
|
|||||||
s.errHandler(err)
|
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
|
// GetBalance retrieves the balance from the given address or 0 if the account does
|
||||||
// not exist
|
// not exist
|
||||||
func (s *VMState) GetBalance(addr common.Address) *big.Int {
|
func (s *VMState) GetBalance(addr common.Address) *big.Int {
|
||||||
|
@ -32,7 +32,6 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
@ -222,10 +221,12 @@ func (t *BlockTest) InsertPreState(db ethdb.Database) (*state.StateDB, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
obj := statedb.CreateAccount(common.HexToAddress(addrString))
|
|
||||||
obj.SetCode(crypto.Keccak256Hash(code), code)
|
addr := common.HexToAddress(addrString)
|
||||||
obj.SetBalance(balance)
|
statedb.CreateAccount(addr)
|
||||||
obj.SetNonce(nonce)
|
statedb.SetCode(addr, code)
|
||||||
|
statedb.SetBalance(addr, balance)
|
||||||
|
statedb.SetNonce(addr, nonce)
|
||||||
for k, v := range acct.Storage {
|
for k, v := range acct.Storage {
|
||||||
statedb.SetState(common.HexToAddress(addrString), common.HexToHash(k), common.HexToHash(v))
|
statedb.SetState(common.HexToAddress(addrString), common.HexToHash(k), common.HexToHash(v))
|
||||||
}
|
}
|
||||||
|
@ -165,25 +165,25 @@ func runStateTest(chainConfig *params.ChainConfig, test VmTest) error {
|
|||||||
|
|
||||||
// check post state
|
// check post state
|
||||||
for addr, account := range test.Post {
|
for addr, account := range test.Post {
|
||||||
obj := statedb.GetStateObject(common.HexToAddress(addr))
|
address := common.HexToAddress(addr)
|
||||||
if obj == nil {
|
if !statedb.Exist(address) {
|
||||||
return fmt.Errorf("did not find expected post-state account: %s", addr)
|
return fmt.Errorf("did not find expected post-state account: %s", addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj.Balance().Cmp(common.Big(account.Balance)) != 0 {
|
if balance := statedb.GetBalance(address); balance.Cmp(common.Big(account.Balance)) != 0 {
|
||||||
return fmt.Errorf("(%x) balance failed. Expected: %v have: %v\n", obj.Address().Bytes()[:4], common.String2Big(account.Balance), obj.Balance())
|
return fmt.Errorf("(%x) balance failed. Expected: %v have: %v\n", address[:4], common.String2Big(account.Balance), balance)
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj.Nonce() != common.String2Big(account.Nonce).Uint64() {
|
if nonce := statedb.GetNonce(address); nonce != common.String2Big(account.Nonce).Uint64() {
|
||||||
return fmt.Errorf("(%x) nonce failed. Expected: %v have: %v\n", obj.Address().Bytes()[:4], account.Nonce, obj.Nonce())
|
return fmt.Errorf("(%x) nonce failed. Expected: %v have: %v\n", address[:4], account.Nonce, nonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
for addr, value := range account.Storage {
|
for addr, value := range account.Storage {
|
||||||
v := statedb.GetState(obj.Address(), common.HexToHash(addr))
|
v := statedb.GetState(address, common.HexToHash(addr))
|
||||||
vexp := common.HexToHash(value)
|
vexp := common.HexToHash(value)
|
||||||
|
|
||||||
if v != vexp {
|
if v != vexp {
|
||||||
return fmt.Errorf("storage failed:\n%x: %s:\nexpected: %x\nhave: %x\n(%v %v)\n", obj.Address().Bytes(), addr, vexp, v, vexp.Big(), v.Big())
|
return fmt.Errorf("storage failed:\n%x: %s:\nexpected: %x\nhave: %x\n(%v %v)\n", address[:4], addr, vexp, v, vexp.Big(), v.Big())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,16 +187,16 @@ func runVmTest(test VmTest) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check post state
|
// check post state
|
||||||
for addr, account := range test.Post {
|
for address, account := range test.Post {
|
||||||
obj := statedb.GetStateObject(common.HexToAddress(addr))
|
accountAddr := common.HexToAddress(address)
|
||||||
if obj == nil {
|
if !statedb.Exist(accountAddr) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for addr, value := range account.Storage {
|
for addr, value := range account.Storage {
|
||||||
v := statedb.GetState(obj.Address(), common.HexToHash(addr))
|
v := statedb.GetState(accountAddr, common.HexToHash(addr))
|
||||||
vexp := common.HexToHash(value)
|
vexp := common.HexToHash(value)
|
||||||
if v != vexp {
|
if v != vexp {
|
||||||
return fmt.Errorf("(%x: %s) storage failed. Expected %x, got %x (%v %v)\n", obj.Address().Bytes()[0:4], addr, vexp, v, vexp.Big(), v.Big())
|
return fmt.Errorf("(%x: %s) storage failed. Expected %x, got %x (%v %v)\n", addr[:4], addr, vexp, v, vexp.Big(), v.Big())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user