core, core/state, core/vm: removal of exported account getters

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:
Jeffrey Wilcke 2017-01-27 11:33:47 +01:00
parent 94334c233e
commit 9f1bdae638
22 changed files with 168 additions and 200 deletions

View file

@ -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.Reference(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(),

View file

@ -214,7 +214,8 @@ func (self *BlockChain) loadLastState() error {
return err return err
} }
self.stateCache = statedb self.stateCache = statedb
self.stateCache.GetAccount(common.Address{}) // XXX Reviewers: what's this for? I need to know if I need to backport this somehow
//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())

View file

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

View file

@ -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) {

View file

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

View file

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

View file

@ -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,26 +363,26 @@ 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) { func (self *stateObject) ForEachStorage(cb func(key, value common.Hash) bool) {
// When iterating over the storage check the cache first // When iterating over the storage check the cache first
for h, value := range self.cachedStorage { for h, value := range self.cachedStorage {
cb(h, value) cb(h, value)

View file

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

View file

@ -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,11 @@ 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
} }
// Copy creates a deep, independent copy of the state. // Copy creates a deep, independent copy of the state.
@ -492,7 +486,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)),

View file

@ -331,11 +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 { obj.ForEachStorage(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) checkobj := checkstate.getStateObject(addr)
checkobj.ForEachStorage(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)
}) })

View file

@ -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"
@ -29,6 +29,7 @@ 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.Reference(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.Reference(*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)

View file

@ -25,11 +25,13 @@ 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)
} }
type AccountRef common.Address
func (ar AccountRef) Address() common.Address { return (common.Address)(ar) }
func Reference(addr common.Address) AccountRef { return (AccountRef)(addr) }
// 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 +71,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 +83,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 +144,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)
}

View file

@ -116,7 +116,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
} }
var ( var (
to Account to = Reference(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 = Reference(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 = Reference(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, Reference(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)

View file

@ -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)
@ -63,20 +62,6 @@ type StateDB interface {
AddPreimage(common.Hash, []byte) AddPreimage(common.Hash, []byte)
} }
// Account represents a contract or basic ethereum account.
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
// depends on this context being implemented for doing subcalls and initialising new EVM contracts. // depends on this context being implemented for doing subcalls and initialising new EVM contracts.
type CallContext interface { type CallContext interface {

View file

@ -144,11 +144,14 @@ 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.
/* TODO
env.StateDB.GetAccount(contract.Address()).ForEachStorage(func(key, value common.Hash) bool { env.StateDB.GetAccount(contract.Address()).ForEachStorage(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
}) })
*/
} else { } else {
// copy a snapshot of the current storage to a new container. // copy a snapshot of the current storage to a new container.
storage = l.changedValues[contract.Address()].Copy() storage = l.changedValues[contract.Address()].Copy()

View file

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

View file

@ -45,8 +45,7 @@ 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 }

View file

@ -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 (
address = common.StringToAddress("contract")
vmenv = NewEnv(cfg, cfg.State) vmenv = NewEnv(cfg, cfg.State)
sender = cfg.State.CreateAccount(cfg.Origin) sender = vm.Reference(cfg.Origin)
receiver = cfg.State.CreateAccount(common.StringToAddress("contract"))
) )
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.Reference(cfg.Origin)
) )
// Call the code with the given configuration. // Call the code with the given configuration.

View file

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

View file

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

View file

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

View file

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