mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 06:36:43 +00:00
Merge ec9b582fe1 into 07caa3fccd
This commit is contained in:
commit
dd71d67333
17 changed files with 381 additions and 181 deletions
|
|
@ -128,7 +128,7 @@ func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *stat
|
||||||
}
|
}
|
||||||
// Validate the state root against the received state root and throw
|
// Validate the state root against the received state root and throw
|
||||||
// an error if they don't match.
|
// an error if they don't match.
|
||||||
if root := statedb.IntermediateRoot(); header.Root != root {
|
if root := state.IntermediateRoot(statedb); header.Root != root {
|
||||||
return fmt.Errorf("invalid merkle root: header=%x computed=%x", header.Root, root)
|
return fmt.Errorf("invalid merkle root: header=%x computed=%x", header.Root, root)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -929,7 +929,8 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
// Write state changes to database
|
// Write state changes to database
|
||||||
_, err = self.stateCache.Commit()
|
_, err = state.Commit(self.stateCache)
|
||||||
|
//_, err = self.stateCache.Commit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,8 +105,8 @@ func (b *BlockGen) AddTx(tx *types.Transaction) {
|
||||||
if b.gasPool == nil {
|
if b.gasPool == nil {
|
||||||
b.SetCoinbase(common.Address{})
|
b.SetCoinbase(common.Address{})
|
||||||
}
|
}
|
||||||
b.statedb.StartRecord(tx.Hash(), common.Hash{}, len(b.txs))
|
b.statedb.TransitionState(tx.Hash(), common.Hash{}, len(b.txs))
|
||||||
receipt, _, _, err := ApplyTransaction(MakeChainConfig(), nil, b.gasPool, b.statedb, b.header, tx, b.header.GasUsed, vm.Config{})
|
_, receipt, _, _, err := ApplyTransaction(MakeChainConfig(), nil, b.gasPool, b.statedb, b.header, tx, b.header.GasUsed, vm.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -203,7 +203,8 @@ func GenerateChain(config *ChainConfig, parent *types.Block, db ethdb.Database,
|
||||||
gen(i, b)
|
gen(i, b)
|
||||||
}
|
}
|
||||||
AccumulateRewards(statedb, h, b.uncles)
|
AccumulateRewards(statedb, h, b.uncles)
|
||||||
root, err := statedb.Commit()
|
//root, err := statedb.Commit()
|
||||||
|
root, err := state.Commit(statedb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("state write error: %v", err))
|
panic(fmt.Sprintf("state write error: %v", err))
|
||||||
}
|
}
|
||||||
|
|
@ -224,7 +225,7 @@ func GenerateChain(config *ChainConfig, parent *types.Block, db ethdb.Database,
|
||||||
return blocks, receipts
|
return blocks, receipts
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeHeader(parent *types.Block, state *state.StateDB) *types.Header {
|
func makeHeader(parent *types.Block, st *state.StateDB) *types.Header {
|
||||||
var time *big.Int
|
var time *big.Int
|
||||||
if parent.Time() == nil {
|
if parent.Time() == nil {
|
||||||
time = big.NewInt(10)
|
time = big.NewInt(10)
|
||||||
|
|
@ -232,7 +233,7 @@ func makeHeader(parent *types.Block, state *state.StateDB) *types.Header {
|
||||||
time = new(big.Int).Add(parent.Time(), big.NewInt(10)) // block time is fixed at 10 seconds
|
time = new(big.Int).Add(parent.Time(), big.NewInt(10)) // block time is fixed at 10 seconds
|
||||||
}
|
}
|
||||||
return &types.Header{
|
return &types.Header{
|
||||||
Root: state.IntermediateRoot(),
|
Root: state.IntermediateRoot(st),
|
||||||
ParentHash: parent.Hash(),
|
ParentHash: parent.Hash(),
|
||||||
Coinbase: parent.Coinbase(),
|
Coinbase: parent.Coinbase(),
|
||||||
Difficulty: CalcDifficulty(MakeChainConfig(), time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()),
|
Difficulty: CalcDifficulty(MakeChainConfig(), time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()),
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"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/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
|
@ -169,7 +170,7 @@ func execDelegateCall(env vm.Environment, caller vm.ContractRef, originAddr, toA
|
||||||
}
|
}
|
||||||
|
|
||||||
// generic transfer method
|
// generic transfer method
|
||||||
func Transfer(from, to vm.Account, amount *big.Int) {
|
func Transfer(statedb *state.StateDB, from, to common.Address, amount *big.Int) {
|
||||||
from.SubBalance(amount)
|
statedb.SubBalance(from, amount)
|
||||||
to.AddBalance(amount)
|
statedb.AddBalance(to, amount)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,8 @@ func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block,
|
||||||
statedb.SetState(address, common.HexToHash(key), common.HexToHash(value))
|
statedb.SetState(address, common.HexToHash(key), common.HexToHash(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
root, stateBatch := statedb.CommitBatch()
|
root, stateBatch := state.CommitBatch(statedb)
|
||||||
|
//root, stateBatch := statedb.CommitBatch()
|
||||||
|
|
||||||
difficulty := common.String2Big(genesis.Difficulty)
|
difficulty := common.String2Big(genesis.Difficulty)
|
||||||
block := types.NewBlock(&types.Header{
|
block := types.NewBlock(&types.Header{
|
||||||
|
|
@ -128,7 +129,8 @@ func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big
|
||||||
statedb, _ := state.New(common.Hash{}, db)
|
statedb, _ := state.New(common.Hash{}, db)
|
||||||
obj := statedb.GetOrNewStateObject(addr)
|
obj := statedb.GetOrNewStateObject(addr)
|
||||||
obj.SetBalance(balance)
|
obj.SetBalance(balance)
|
||||||
root, err := statedb.Commit()
|
root, err := state.Commit(statedb)
|
||||||
|
//root, err := statedb.Commit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("cannot write state: %v", err))
|
panic(fmt.Sprintf("cannot write state: %v", err))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,24 @@ func (self *StateDB) RawDump() Dump {
|
||||||
}
|
}
|
||||||
dump.Accounts[common.Bytes2Hex(addr)] = account
|
dump.Accounts[common.Bytes2Hex(addr)] = account
|
||||||
}
|
}
|
||||||
|
for addr, stateObject := range self.stateObjects {
|
||||||
|
account := DumpAccount{
|
||||||
|
Balance: stateObject.data.Balance.String(),
|
||||||
|
Nonce: stateObject.data.Nonce,
|
||||||
|
Root: common.Bytes2Hex(stateObject.data.Root[:]),
|
||||||
|
CodeHash: common.Bytes2Hex(stateObject.data.CodeHash),
|
||||||
|
Code: common.Bytes2Hex(stateObject.Code(self.db)),
|
||||||
|
Storage: make(map[string]string),
|
||||||
|
}
|
||||||
|
storageIt := stateObject.getTrie(self.db).Iterator()
|
||||||
|
for storageIt.Next() {
|
||||||
|
account.Storage[common.Bytes2Hex(self.trie.GetKey(storageIt.Key))] = common.Bytes2Hex(storageIt.Value)
|
||||||
|
}
|
||||||
|
for storageAddr, value := range stateObject.cachedStorage {
|
||||||
|
account.Storage[storageAddr.Hex()] = value.Hex()
|
||||||
|
}
|
||||||
|
dump.Accounts[addr.Hex()] = account
|
||||||
|
}
|
||||||
return dump
|
return dump
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ type ManagedState struct {
|
||||||
// ManagedState returns a new managed state with the statedb as it's backing layer
|
// ManagedState returns a new managed state with the statedb as it's backing layer
|
||||||
func ManageState(statedb *StateDB) *ManagedState {
|
func ManageState(statedb *StateDB) *ManagedState {
|
||||||
return &ManagedState{
|
return &ManagedState{
|
||||||
StateDB: statedb.Copy(),
|
StateDB: Fork(statedb),
|
||||||
accounts: make(map[common.Address]*account),
|
accounts: make(map[common.Address]*account),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,11 @@ const (
|
||||||
codeSizeCacheSize = 100000
|
codeSizeCacheSize = 100000
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type intermediateInfo struct {
|
||||||
|
txHash, blockHash common.Hash
|
||||||
|
txIdx uint
|
||||||
|
}
|
||||||
|
|
||||||
// StateDBs within the ethereum protocol are used to store anything
|
// StateDBs within the ethereum protocol are used to store anything
|
||||||
// within the merkle trie. StateDBs take care of caching and storing
|
// within the merkle trie. StateDBs take care of caching and storing
|
||||||
// nested states. It's the general query interface to retrieve:
|
// nested states. It's the general query interface to retrieve:
|
||||||
|
|
@ -56,22 +61,70 @@ type StateDB struct {
|
||||||
trie *trie.SecureTrie
|
trie *trie.SecureTrie
|
||||||
pastTries []*trie.SecureTrie
|
pastTries []*trie.SecureTrie
|
||||||
codeSizeCache *lru.Cache
|
codeSizeCache *lru.Cache
|
||||||
|
parent *StateDB
|
||||||
|
|
||||||
// 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{}
|
||||||
|
|
||||||
|
localStateObjects map[common.Address]bool
|
||||||
|
|
||||||
// The refund counter, also used by state transitioning.
|
// The refund counter, also used by state transitioning.
|
||||||
refund *big.Int
|
refund *big.Int
|
||||||
|
|
||||||
thash, bhash common.Hash
|
logIdx uint
|
||||||
txIndex int
|
logs []*vm.Log
|
||||||
logs map[common.Hash]vm.Logs
|
|
||||||
logSize uint
|
interInfo intermediateInfo
|
||||||
|
MarkedTransition bool // marks the transition between transactions
|
||||||
|
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *StateDB) TransitionState(txHash, blockHash common.Hash, txIdx int) {
|
||||||
|
if s.parent != nil {
|
||||||
|
s.parent.MarkedTransition = true
|
||||||
|
}
|
||||||
|
s.interInfo = intermediateInfo{txHash: txHash, blockHash: blockHash, txIdx: uint(txIdx)}
|
||||||
|
s.refund = new(big.Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read fetches the state object with the given address by first checking its own cache of state objects. If that didn't result in an object it will attempt to check it's line of ancestors.
|
||||||
|
func (s *StateDB) Read(address common.Address) (object *StateObject, inCache bool) {
|
||||||
|
stateObject := s.stateObjects[address]
|
||||||
|
if stateObject == nil && s.parent != nil {
|
||||||
|
stateObject, _ = s.parent.Read(address)
|
||||||
|
if stateObject != nil {
|
||||||
|
s.SetStateObject(stateObject)
|
||||||
|
}
|
||||||
|
} else if stateObject != nil {
|
||||||
|
inCache = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if stateObject != nil {
|
||||||
|
if stateObject.deleted {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return stateObject, inCache
|
||||||
|
}
|
||||||
|
|
||||||
|
enc := s.trie.Get(address[:])
|
||||||
|
if len(enc) == 0 {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
var data Account
|
||||||
|
if err := rlp.DecodeBytes(enc, &data); err != nil {
|
||||||
|
glog.Errorf("can't decode object at %x: %v", address[:], err)
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
// Insert into the live set.
|
||||||
|
obj := NewObject(address, data, s.MarkStateObjectDirty)
|
||||||
|
s.SetStateObject(obj)
|
||||||
|
//s.stateObjects[address] = obj
|
||||||
|
return obj, false
|
||||||
|
}
|
||||||
|
|
||||||
// Create a new state from a given trie
|
// Create a new state from a given trie
|
||||||
func New(root common.Hash, db ethdb.Database) (*StateDB, error) {
|
func New(root common.Hash, db ethdb.Database) (*StateDB, error) {
|
||||||
tr, err := trie.NewSecure(root, db)
|
tr, err := trie.NewSecure(root, db)
|
||||||
|
|
@ -85,8 +138,8 @@ func New(root common.Hash, db ethdb.Database) (*StateDB, error) {
|
||||||
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{}),
|
||||||
|
localStateObjects: make(map[common.Address]bool),
|
||||||
refund: new(big.Int),
|
refund: new(big.Int),
|
||||||
logs: make(map[common.Hash]vm.Logs),
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,30 +159,27 @@ func (self *StateDB) New(root common.Hash) (*StateDB, error) {
|
||||||
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{}),
|
||||||
|
localStateObjects: make(map[common.Address]bool),
|
||||||
refund: new(big.Int),
|
refund: new(big.Int),
|
||||||
logs: make(map[common.Hash]vm.Logs),
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset clears out all emphemeral state objects from the state db, but keeps
|
// Reset clears out all emphemeral state objects from the state db, but keeps
|
||||||
// the underlying state trie to avoid reloading data for the next operations.
|
// the underlying state trie to avoid reloading data for the next operations.
|
||||||
func (self *StateDB) Reset(root common.Hash) error {
|
func (s *StateDB) Reset(root common.Hash) error {
|
||||||
self.lock.Lock()
|
s.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer s.lock.Unlock()
|
||||||
|
|
||||||
tr, err := self.openTrie(root)
|
tr, err := s.openTrie(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
self.trie = tr
|
s.trie = tr
|
||||||
self.stateObjects = make(map[common.Address]*StateObject)
|
s.stateObjects = make(map[common.Address]*StateObject)
|
||||||
self.stateObjectsDirty = make(map[common.Address]struct{})
|
s.stateObjectsDirty = make(map[common.Address]struct{})
|
||||||
self.refund = new(big.Int)
|
s.localStateObjects = make(map[common.Address]bool)
|
||||||
self.thash = common.Hash{}
|
s.refund = new(big.Int)
|
||||||
self.bhash = common.Hash{}
|
s.logs = nil
|
||||||
self.txIndex = 0
|
|
||||||
self.logs = make(map[common.Hash]vm.Logs)
|
|
||||||
self.logSize = 0
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -158,37 +208,45 @@ func (self *StateDB) pushTrie(t *trie.SecureTrie) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) StartRecord(thash, bhash common.Hash, ti int) {
|
func (s *StateDB) AddLog(log *vm.Log) {
|
||||||
self.thash = thash
|
log.TxIndex = s.interInfo.txIdx
|
||||||
self.bhash = bhash
|
log.TxHash = s.interInfo.txHash
|
||||||
self.txIndex = ti
|
log.BlockHash = s.interInfo.blockHash
|
||||||
|
log.Index = s.logIdx
|
||||||
|
|
||||||
|
s.logs = append(s.logs, log)
|
||||||
|
|
||||||
|
s.logIdx++
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) AddLog(log *vm.Log) {
|
// Logs returns the logs of it's entire ancestory chain or until
|
||||||
log.TxHash = self.thash
|
// the marked transition is found (state between transactions).
|
||||||
log.BlockHash = self.bhash
|
func (s *StateDB) Logs() []*vm.Log {
|
||||||
log.TxIndex = uint(self.txIndex)
|
var logs []*vm.Log
|
||||||
log.Index = self.logSize
|
if s.MarkedTransition {
|
||||||
self.logs[self.thash] = append(self.logs[self.thash], log)
|
return nil
|
||||||
self.logSize++
|
} else if s.parent != nil {
|
||||||
|
logs = s.parent.Logs()
|
||||||
}
|
}
|
||||||
|
return append(logs, s.logs...)
|
||||||
func (self *StateDB) GetLogs(hash common.Hash) vm.Logs {
|
|
||||||
return self.logs[hash]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *StateDB) Logs() vm.Logs {
|
|
||||||
var logs vm.Logs
|
|
||||||
for _, lgs := range self.logs {
|
|
||||||
logs = append(logs, lgs...)
|
|
||||||
}
|
|
||||||
return logs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateDB) AddRefund(gas *big.Int) {
|
func (self *StateDB) AddRefund(gas *big.Int) {
|
||||||
self.refund.Add(self.refund, gas)
|
self.refund.Add(self.refund, gas)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *StateDB) GetRefund() *big.Int {
|
||||||
|
var refund *big.Int
|
||||||
|
if s.MarkedTransition {
|
||||||
|
return new(big.Int)
|
||||||
|
} else if s.parent == nil {
|
||||||
|
refund = new(big.Int)
|
||||||
|
} else {
|
||||||
|
refund = s.parent.GetRefund()
|
||||||
|
}
|
||||||
|
return refund.Add(refund, s.refund)
|
||||||
|
}
|
||||||
|
|
||||||
func (self *StateDB) HasAccount(addr common.Address) bool {
|
func (self *StateDB) HasAccount(addr common.Address) bool {
|
||||||
return self.GetStateObject(addr) != nil
|
return self.GetStateObject(addr) != nil
|
||||||
}
|
}
|
||||||
|
|
@ -282,6 +340,13 @@ func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *StateDB) SubBalance(addr common.Address, amount *big.Int) {
|
||||||
|
stateObject := self.GetOrNewStateObject(addr)
|
||||||
|
if stateObject != nil {
|
||||||
|
stateObject.SubBalance(amount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (self *StateDB) SetNonce(addr common.Address, nonce uint64) {
|
func (self *StateDB) SetNonce(addr common.Address, nonce uint64) {
|
||||||
stateObject := self.GetOrNewStateObject(addr)
|
stateObject := self.GetOrNewStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
|
|
@ -336,46 +401,51 @@ func (self *StateDB) DeleteStateObject(stateObject *StateObject) {
|
||||||
self.trie.Delete(addr[:])
|
self.trie.Delete(addr[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve a state object given my the address. Returns nil if not found.
|
|
||||||
func (self *StateDB) GetStateObject(addr common.Address) (stateObject *StateObject) {
|
|
||||||
// Prefer 'live' objects.
|
|
||||||
if obj := self.stateObjects[addr]; obj != nil {
|
|
||||||
if obj.deleted {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return obj
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the object from the database.
|
|
||||||
enc := self.trie.Get(addr[:])
|
|
||||||
if len(enc) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var data Account
|
|
||||||
if err := rlp.DecodeBytes(enc, &data); err != nil {
|
|
||||||
glog.Errorf("can't decode object at %x: %v", addr[:], err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// Insert into the live set.
|
|
||||||
obj := NewObject(addr, data, self.MarkStateObjectDirty)
|
|
||||||
self.SetStateObject(obj)
|
|
||||||
return obj
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *StateDB) SetStateObject(object *StateObject) {
|
func (self *StateDB) SetStateObject(object *StateObject) {
|
||||||
|
if object == nil {
|
||||||
|
panic("is nil")
|
||||||
|
}
|
||||||
self.stateObjects[object.Address()] = object
|
self.stateObjects[object.Address()] = object
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve a state object or create a new state object if nil
|
func (s *StateDB) SetOwnedStateObject(address common.Address, object *StateObject) {
|
||||||
func (self *StateDB) GetOrNewStateObject(addr common.Address) *StateObject {
|
if object == nil {
|
||||||
stateObject := self.GetStateObject(addr)
|
panic("is nil")
|
||||||
if stateObject == nil || stateObject.deleted {
|
}
|
||||||
stateObject = self.CreateStateObject(addr)
|
s.stateObjects[address] = object
|
||||||
|
s.localStateObjects[address] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *StateDB) GetOrNewStateObject(address common.Address) *StateObject {
|
||||||
|
stateObject, _ := s.Read(address)
|
||||||
|
if stateObject != nil {
|
||||||
|
if !s.localStateObjects[address] {
|
||||||
|
stateObject = stateObject.Copy(s.db, s.MarkStateObjectDirty)
|
||||||
|
s.SetOwnedStateObject(address, stateObject)
|
||||||
|
}
|
||||||
return stateObject
|
return stateObject
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if stateObject == nil || stateObject.deleted {
|
||||||
|
stateObject = NewObject(address, Account{}, s.MarkStateObjectDirty)
|
||||||
|
stateObject.SetNonce(StartingNonce)
|
||||||
|
|
||||||
|
s.SetOwnedStateObject(address, stateObject)
|
||||||
|
}
|
||||||
|
return stateObject
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StateDB) GetStateObject(address common.Address) *StateObject {
|
||||||
|
account, _ := s.Read(address)
|
||||||
|
if account != nil {
|
||||||
|
if s.stateObjects[address] == nil {
|
||||||
|
s.SetStateObject(account)
|
||||||
|
}
|
||||||
|
return account
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// NewStateObject create a state object whether it exist in the trie or not
|
// NewStateObject create a state object whether it exist in the trie or not
|
||||||
func (self *StateDB) newStateObject(addr common.Address) *StateObject {
|
func (self *StateDB) newStateObject(addr common.Address) *StateObject {
|
||||||
if glog.V(logger.Core) {
|
if glog.V(logger.Core) {
|
||||||
|
|
@ -383,7 +453,8 @@ func (self *StateDB) newStateObject(addr common.Address) *StateObject {
|
||||||
}
|
}
|
||||||
obj := NewObject(addr, Account{}, self.MarkStateObjectDirty)
|
obj := NewObject(addr, Account{}, self.MarkStateObjectDirty)
|
||||||
obj.SetNonce(StartingNonce) // sets the object to dirty
|
obj.SetNonce(StartingNonce) // sets the object to dirty
|
||||||
self.stateObjects[addr] = obj
|
//self.stateObjects[addr] = obj
|
||||||
|
self.SetOwnedStateObject(addr, obj)
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -412,42 +483,12 @@ func (self *StateDB) CreateAccount(addr common.Address) vm.Account {
|
||||||
return self.CreateStateObject(addr)
|
return self.CreateStateObject(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Setting, copying of the state methods
|
|
||||||
//
|
|
||||||
|
|
||||||
func (self *StateDB) Copy() *StateDB {
|
|
||||||
self.lock.Lock()
|
|
||||||
defer self.lock.Unlock()
|
|
||||||
|
|
||||||
// Copy all the basic fields, initialize the memory ones
|
|
||||||
state := &StateDB{
|
|
||||||
db: self.db,
|
|
||||||
trie: self.trie,
|
|
||||||
pastTries: self.pastTries,
|
|
||||||
codeSizeCache: self.codeSizeCache,
|
|
||||||
stateObjects: make(map[common.Address]*StateObject, len(self.stateObjectsDirty)),
|
|
||||||
stateObjectsDirty: make(map[common.Address]struct{}, len(self.stateObjectsDirty)),
|
|
||||||
refund: new(big.Int).Set(self.refund),
|
|
||||||
logs: make(map[common.Hash]vm.Logs, len(self.logs)),
|
|
||||||
logSize: self.logSize,
|
|
||||||
}
|
|
||||||
// Copy the dirty states and logs
|
|
||||||
for addr, _ := range self.stateObjectsDirty {
|
|
||||||
state.stateObjects[addr] = self.stateObjects[addr].Copy(self.db, state.MarkStateObjectDirty)
|
|
||||||
state.stateObjectsDirty[addr] = struct{}{}
|
|
||||||
}
|
|
||||||
for hash, logs := range self.logs {
|
|
||||||
state.logs[hash] = make(vm.Logs, len(logs))
|
|
||||||
copy(state.logs[hash], logs)
|
|
||||||
}
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *StateDB) Set(state *StateDB) {
|
func (self *StateDB) Set(state *StateDB) {
|
||||||
self.lock.Lock()
|
//self.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
//defer self.lock.Unlock()
|
||||||
|
|
||||||
|
*self = *state
|
||||||
|
/*
|
||||||
self.db = state.db
|
self.db = state.db
|
||||||
self.trie = state.trie
|
self.trie = state.trie
|
||||||
self.pastTries = state.pastTries
|
self.pastTries = state.pastTries
|
||||||
|
|
@ -456,11 +497,7 @@ func (self *StateDB) Set(state *StateDB) {
|
||||||
self.codeSizeCache = state.codeSizeCache
|
self.codeSizeCache = state.codeSizeCache
|
||||||
self.refund = state.refund
|
self.refund = state.refund
|
||||||
self.logs = state.logs
|
self.logs = state.logs
|
||||||
self.logSize = state.logSize
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
func (self *StateDB) GetRefund() *big.Int {
|
|
||||||
return self.refund
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IntermediateRoot computes the current root hash of the state trie.
|
// IntermediateRoot computes the current root hash of the state trie.
|
||||||
|
|
@ -501,7 +538,8 @@ func (s *StateDB) DeleteSuicides() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commit commits all state changes to the database.
|
/*
|
||||||
|
// commit commits all state changes to the database.
|
||||||
func (s *StateDB) Commit() (root common.Hash, err error) {
|
func (s *StateDB) Commit() (root common.Hash, err error) {
|
||||||
root, batch := s.CommitBatch()
|
root, batch := s.CommitBatch()
|
||||||
return root, batch.Write()
|
return root, batch.Write()
|
||||||
|
|
@ -549,7 +587,120 @@ func (s *StateDB) commit(dbw trie.DatabaseWriter) (root common.Hash, err error)
|
||||||
}
|
}
|
||||||
return root, err
|
return root, err
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
func (self *StateDB) Refunds() *big.Int {
|
func (self *StateDB) Refunds() *big.Int {
|
||||||
return self.refund
|
return self.refund
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fork preserve the given state and returns a handle to a new modifiable state
|
||||||
|
// that does not affect the preserved state.
|
||||||
|
func Fork(parent *StateDB) *StateDB {
|
||||||
|
return &StateDB{
|
||||||
|
db: parent.db,
|
||||||
|
trie: parent.trie,
|
||||||
|
pastTries: parent.pastTries,
|
||||||
|
codeSizeCache: parent.codeSizeCache,
|
||||||
|
|
||||||
|
parent: parent,
|
||||||
|
stateObjects: make(map[common.Address]*StateObject),
|
||||||
|
localStateObjects: make(map[common.Address]bool),
|
||||||
|
stateObjectsDirty: make(map[common.Address]struct{}),
|
||||||
|
refund: new(big.Int),
|
||||||
|
logIdx: parent.logIdx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce flattens the state in to a single new state, including all changes of all ancestors.
|
||||||
|
func Reduce(s *StateDB) *StateDB {
|
||||||
|
if s.parent == nil {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
state := Reduce(s.parent)
|
||||||
|
|
||||||
|
for address, object := range s.stateObjects {
|
||||||
|
if s.localStateObjects[address] {
|
||||||
|
state.SetOwnedStateObject(address, object)
|
||||||
|
} else {
|
||||||
|
state.SetStateObject(object)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, isDirty := s.stateObjectsDirty[address]; isDirty {
|
||||||
|
state.stateObjectsDirty[address] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state.logs = append(state.logs, s.logs...)
|
||||||
|
state.refund.Add(state.refund, s.refund)
|
||||||
|
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
func IntermediateRoot(state *StateDB) common.Hash {
|
||||||
|
for address, _ := range state.localStateObjects {
|
||||||
|
stateObject := state.stateObjects[address]
|
||||||
|
if _, isdirty := state.stateObjectsDirty[address]; isdirty {
|
||||||
|
if stateObject.remove {
|
||||||
|
state.DeleteStateObject(stateObject)
|
||||||
|
} else {
|
||||||
|
stateObject.UpdateRoot(state.db)
|
||||||
|
state.UpdateStateObject(stateObject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//state.stateObjectsDirty = make(map[common.Address]struct{})
|
||||||
|
return state.trie.Hash()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit commits all state changes to the database.
|
||||||
|
func Commit(state *StateDB) (common.Hash, error) {
|
||||||
|
root, batch := CommitBatch(state)
|
||||||
|
return root, batch.Write()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommitBatch commits all state changes to a write batch but does not
|
||||||
|
// execute the batch. It is used to validate state changes against
|
||||||
|
// the root hash stored in a block.
|
||||||
|
func CommitBatch(state *StateDB) (common.Hash, ethdb.Batch) {
|
||||||
|
batch := state.db.NewBatch()
|
||||||
|
root, _ := stateCommit(state, batch)
|
||||||
|
return root, batch
|
||||||
|
}
|
||||||
|
|
||||||
|
func stateCommit(state *StateDB, dbw trie.DatabaseWriter) (root common.Hash, err error) {
|
||||||
|
// make sure the state is flattened before committing
|
||||||
|
state = Reduce(state)
|
||||||
|
state.refund = new(big.Int)
|
||||||
|
|
||||||
|
for address, _ := range state.localStateObjects {
|
||||||
|
stateObject := state.stateObjects[address]
|
||||||
|
//for _, stateObject := range state.stateObjects {
|
||||||
|
if stateObject.remove {
|
||||||
|
// If the object has been removed, don't bother syncing it
|
||||||
|
// and just mark it for deletion in the trie.
|
||||||
|
stateObject.deleted = true
|
||||||
|
state.trie.Delete(stateObject.Address().Bytes()[:])
|
||||||
|
} else {
|
||||||
|
// Write any contract code associated with the state object
|
||||||
|
if stateObject.code != nil && stateObject.dirtyCode {
|
||||||
|
if err := dbw.Put(stateObject.CodeHash(), stateObject.code); err != nil {
|
||||||
|
return common.Hash{}, err
|
||||||
|
}
|
||||||
|
stateObject.dirtyCode = false
|
||||||
|
}
|
||||||
|
// Write any storage changes in the state object to its storage trie.
|
||||||
|
if err := stateObject.CommitTrie(state.db, dbw); err != nil {
|
||||||
|
return common.Hash{}, err
|
||||||
|
}
|
||||||
|
// Update the object in the main account trie.
|
||||||
|
state.UpdateStateObject(stateObject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.stateObjectsDirty = make(map[common.Address]struct{})
|
||||||
|
// Write trie changes.
|
||||||
|
root, err = state.trie.CommitTo(dbw)
|
||||||
|
if err == nil {
|
||||||
|
state.pushTrie(state.trie)
|
||||||
|
}
|
||||||
|
return root, err
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,17 +69,27 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
|
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
|
||||||
ApplyDAOHardFork(statedb)
|
ApplyDAOHardFork(statedb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forkState := state.Fork(statedb)
|
||||||
// Iterate over and process the individual transactions
|
// Iterate over and process the individual transactions
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
statedb.StartRecord(tx.Hash(), block.Hash(), i)
|
forkState.TransitionState(tx.Hash(), block.Hash(), i)
|
||||||
receipt, logs, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg)
|
|
||||||
|
txPostState, receipt, logs, _, err := ApplyTransaction(p.config, p.bc, gp, forkState, header, tx, totalUsedGas, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, totalUsedGas, err
|
return nil, nil, totalUsedGas, err
|
||||||
}
|
}
|
||||||
receipts = append(receipts, receipt)
|
receipts = append(receipts, receipt)
|
||||||
allLogs = append(allLogs, logs...)
|
allLogs = append(allLogs, logs...)
|
||||||
|
|
||||||
|
forkState = state.Fork(txPostState)
|
||||||
}
|
}
|
||||||
AccumulateRewards(statedb, header, block.Uncles())
|
//fmt.Printf("before %x\n", state.IntermediateRoot(state.Reduce(forkState)))
|
||||||
|
//fmt.Println(string(forkState.Dump()))
|
||||||
|
AccumulateRewards(forkState, header, block.Uncles())
|
||||||
|
//fmt.Println(string(forkState.Dump()))
|
||||||
|
//fmt.Printf("after %x\n", state.IntermediateRoot(state.Reduce(forkState)))
|
||||||
|
statedb.Set(state.Reduce(forkState))
|
||||||
|
|
||||||
return receipts, allLogs, totalUsedGas, err
|
return receipts, allLogs, totalUsedGas, err
|
||||||
}
|
}
|
||||||
|
|
@ -89,15 +99,18 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
//
|
//
|
||||||
// ApplyTransactions returns the generated receipts and vm logs during the
|
// ApplyTransactions returns the generated receipts and vm logs during the
|
||||||
// execution of the state transition phase.
|
// execution of the state transition phase.
|
||||||
func ApplyTransaction(config *ChainConfig, bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*types.Receipt, vm.Logs, *big.Int, error) {
|
func ApplyTransaction(config *ChainConfig, bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*state.StateDB, *types.Receipt, vm.Logs, *big.Int, error) {
|
||||||
_, gas, err := ApplyMessage(NewEnv(statedb, config, bc, tx, header, cfg), tx, gp)
|
env := NewEnv(statedb, config, bc, tx, header, cfg)
|
||||||
|
_, gas, err := ApplyMessage(env, tx, gp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return statedb, nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
statedb = env.Db().(*state.StateDB)
|
||||||
|
|
||||||
// Update the state with pending changes
|
// Update the state with pending changes
|
||||||
usedGas.Add(usedGas, gas)
|
usedGas.Add(usedGas, gas)
|
||||||
receipt := types.NewReceipt(statedb.IntermediateRoot().Bytes(), usedGas)
|
receipt := types.NewReceipt(state.IntermediateRoot(statedb).Bytes(), usedGas)
|
||||||
receipt.TxHash = tx.Hash()
|
receipt.TxHash = tx.Hash()
|
||||||
receipt.GasUsed = new(big.Int).Set(gas)
|
receipt.GasUsed = new(big.Int).Set(gas)
|
||||||
if MessageCreatesContract(tx) {
|
if MessageCreatesContract(tx) {
|
||||||
|
|
@ -105,13 +118,12 @@ func ApplyTransaction(config *ChainConfig, bc *BlockChain, gp *GasPool, statedb
|
||||||
receipt.ContractAddress = crypto.CreateAddress(from, tx.Nonce())
|
receipt.ContractAddress = crypto.CreateAddress(from, tx.Nonce())
|
||||||
}
|
}
|
||||||
|
|
||||||
logs := statedb.GetLogs(tx.Hash())
|
receipt.Logs = statedb.Logs()
|
||||||
receipt.Logs = logs
|
|
||||||
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
|
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
|
||||||
|
|
||||||
glog.V(logger.Debug).Infoln(receipt)
|
glog.V(logger.Debug).Infoln(receipt)
|
||||||
|
|
||||||
return receipt, logs, gas, err
|
return statedb, receipt, receipt.Logs, gas, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// AccumulateRewards credits the coinbase of the given block with the
|
// AccumulateRewards credits the coinbase of the given block with the
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"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/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
|
|
@ -197,7 +198,9 @@ func (self *StateTransition) buyGas() error {
|
||||||
}
|
}
|
||||||
self.addGas(mgas)
|
self.addGas(mgas)
|
||||||
self.initialGas.Set(mgas)
|
self.initialGas.Set(mgas)
|
||||||
sender.SubBalance(mgval)
|
|
||||||
|
self.state.(*state.StateDB).SubBalance(sender.Address(), mgval)
|
||||||
|
// sender.SubBalance(mgval)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -273,24 +276,24 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b
|
||||||
|
|
||||||
requiredGas = new(big.Int).Set(self.gasUsed())
|
requiredGas = new(big.Int).Set(self.gasUsed())
|
||||||
|
|
||||||
self.refundGas()
|
self.refundGas(vmenv.Db().(*state.StateDB))
|
||||||
self.state.AddBalance(self.env.Coinbase(), new(big.Int).Mul(self.gasUsed(), self.gasPrice))
|
vmenv.Db().AddBalance(self.env.Coinbase(), new(big.Int).Mul(self.gasUsed(), self.gasPrice))
|
||||||
|
|
||||||
return ret, requiredGas, self.gasUsed(), err
|
return ret, requiredGas, self.gasUsed(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateTransition) refundGas() {
|
func (self *StateTransition) refundGas(state *state.StateDB) {
|
||||||
// Return eth for remaining gas to the sender account,
|
// Return eth for remaining gas to the sender account,
|
||||||
// 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(self.gas, self.gasPrice)
|
remaining := new(big.Int).Mul(self.gas, self.gasPrice)
|
||||||
sender.AddBalance(remaining)
|
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)
|
||||||
refund := common.BigMin(uhalf, self.state.GetRefund())
|
refund := common.BigMin(uhalf, state.GetRefund())
|
||||||
self.gas.Add(self.gas, refund)
|
self.gas.Add(self.gas, refund)
|
||||||
self.state.AddBalance(sender.Address(), refund.Mul(refund, self.gasPrice))
|
state.AddBalance(sender.Address(), refund.Mul(refund, self.gasPrice))
|
||||||
|
|
||||||
// Also return remaining gas to the block gas counter so it is
|
// Also return remaining gas to the block gas counter so it is
|
||||||
// available for the next transaction.
|
// available for the next transaction.
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,6 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
|
||||||
op OpCode // current opcode
|
op OpCode // current opcode
|
||||||
mem = NewMemory() // bound memory
|
mem = NewMemory() // bound memory
|
||||||
stack = newstack() // local stack
|
stack = newstack() // local stack
|
||||||
statedb = evm.env.Db() // current state
|
|
||||||
// For optimisation reason we're using uint64 as the program counter.
|
// For optimisation reason we're using uint64 as the program counter.
|
||||||
// It's theoretically possible to go above 2^64. The YP defines the PC to be uint256. Practically much less so feasible.
|
// It's theoretically possible to go above 2^64. The YP defines the PC to be uint256. Practically much less so feasible.
|
||||||
pc = uint64(0) // program counter
|
pc = uint64(0) // program counter
|
||||||
|
|
@ -169,7 +168,7 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
|
||||||
// Get the memory location of pc
|
// Get the memory location of pc
|
||||||
op = contract.GetOp(pc)
|
op = contract.GetOp(pc)
|
||||||
// calculate the new memory size and gas price for the current executing opcode
|
// calculate the new memory size and gas price for the current executing opcode
|
||||||
newMemSize, cost, err = calculateGasAndSize(evm.env, contract, caller, op, statedb, mem, stack)
|
newMemSize, cost, err = calculateGasAndSize(evm.env, contract, caller, op, evm.env.Db(), mem, stack)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,15 +90,17 @@ func (self *VMEnv) CanTransfer(from common.Address, balance *big.Int) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *VMEnv) MakeSnapshot() vm.Database {
|
func (self *VMEnv) MakeSnapshot() vm.Database {
|
||||||
return self.state.Copy()
|
pstate := self.state
|
||||||
|
self.state = state.Fork(pstate)
|
||||||
|
return pstate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *VMEnv) SetSnapshot(copy vm.Database) {
|
func (self *VMEnv) SetSnapshot(copy vm.Database) {
|
||||||
self.state.Set(copy.(*state.StateDB))
|
self.state = copy.(*state.StateDB)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) {
|
func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) {
|
||||||
Transfer(from, to, amount)
|
Transfer(self.state, from.Address(), to.Address(), amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *VMEnv) Call(me vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
|
func (self *VMEnv) Call(me vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
|
||||||
|
|
|
||||||
|
|
@ -97,8 +97,8 @@ func (b *EthApiBackend) GetTd(blockHash common.Hash) *big.Int {
|
||||||
return b.eth.blockchain.GetTdByHash(blockHash)
|
return b.eth.blockchain.GetTdByHash(blockHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (vm.Environment, func() error, error) {
|
func (b *EthApiBackend) GetVMEnv(ctx context.Context, msg core.Message, st ethapi.State, header *types.Header) (vm.Environment, func() error, error) {
|
||||||
stateDb := state.(EthApiState).state.Copy()
|
stateDb := state.Fork(st.(EthApiState).state)
|
||||||
addr, _ := msg.From()
|
addr, _ := msg.From()
|
||||||
from := stateDb.GetOrNewStateObject(addr)
|
from := stateDb.GetOrNewStateObject(addr)
|
||||||
from.SetBalance(common.MaxBig)
|
from.SetBalance(common.MaxBig)
|
||||||
|
|
|
||||||
|
|
@ -276,7 +276,7 @@ func (self *worker) wait() {
|
||||||
}
|
}
|
||||||
go self.mux.Post(core.NewMinedBlockEvent{Block: block})
|
go self.mux.Post(core.NewMinedBlockEvent{Block: block})
|
||||||
} else {
|
} else {
|
||||||
work.state.Commit()
|
state.Commit(work.state)
|
||||||
parent := self.chain.GetBlock(block.ParentHash(), block.NumberU64()-1)
|
parent := self.chain.GetBlock(block.ParentHash(), block.NumberU64()-1)
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
glog.V(logger.Error).Infoln("Invalid block found during mining")
|
glog.V(logger.Error).Infoln("Invalid block found during mining")
|
||||||
|
|
@ -583,7 +583,7 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Start executing the transaction
|
// Start executing the transaction
|
||||||
env.state.StartRecord(tx.Hash(), common.Hash{}, env.tcount)
|
env.state.TransitionState(tx.Hash(), common.Hash{}, env.tcount)
|
||||||
|
|
||||||
err, logs := env.commitTransaction(tx, bc, gp)
|
err, logs := env.commitTransaction(tx, bc, gp)
|
||||||
switch {
|
switch {
|
||||||
|
|
@ -618,8 +618,6 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB
|
||||||
}
|
}
|
||||||
|
|
||||||
func (env *Work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, gp *core.GasPool) (error, vm.Logs) {
|
func (env *Work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, gp *core.GasPool) (error, vm.Logs) {
|
||||||
snap := env.state.Copy()
|
|
||||||
|
|
||||||
// this is a bit of a hack to force jit for the miners
|
// this is a bit of a hack to force jit for the miners
|
||||||
config := env.config.VmConfig
|
config := env.config.VmConfig
|
||||||
if !(config.EnableJit && config.ForceJit) {
|
if !(config.EnableJit && config.ForceJit) {
|
||||||
|
|
@ -627,9 +625,10 @@ func (env *Work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, g
|
||||||
}
|
}
|
||||||
config.ForceJit = false // disable forcing jit
|
config.ForceJit = false // disable forcing jit
|
||||||
|
|
||||||
receipt, logs, _, err := core.ApplyTransaction(env.config, bc, gp, env.state, env.header, tx, env.header.GasUsed, config)
|
state, receipt, logs, _, err := core.ApplyTransaction(env.config, bc, gp, env.state, env.header, tx, env.header.GasUsed, config)
|
||||||
|
defer func() { env.state = state }()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
env.state.Set(snap)
|
|
||||||
return err, nil
|
return err, nil
|
||||||
}
|
}
|
||||||
env.txs = append(env.txs, tx)
|
env.txs = append(env.txs, tx)
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ func runBlockTests(homesteadBlock, daoForkBlock *big.Int, bt map[string]*BlockTe
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, test := range bt {
|
for name, test := range bt {
|
||||||
if skipTest[name] {
|
if skipTest[name] || name != "OOGStateCopyContainingDeletedContract" {
|
||||||
glog.Infoln("Skipping block test", name)
|
glog.Infoln("Skipping block test", name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -228,7 +228,8 @@ func (t *BlockTest) InsertPreState(db ethdb.Database) (*state.StateDB, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
root, err := statedb.Commit()
|
//root, err := statedb.Commit()
|
||||||
|
root, err := state.Commit(statedb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error writing state: %v", err)
|
return nil, fmt.Errorf("error writing state: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ func benchStateTest(ruleSet RuleSet, test VmTest, env map[string]string, b *test
|
||||||
statedb, _ := state.New(common.Hash{}, db)
|
statedb, _ := state.New(common.Hash{}, db)
|
||||||
for addr, account := range test.Pre {
|
for addr, account := range test.Pre {
|
||||||
obj := StateObjectFromAccount(db, addr, account, statedb.MarkStateObjectDirty)
|
obj := StateObjectFromAccount(db, addr, account, statedb.MarkStateObjectDirty)
|
||||||
statedb.SetStateObject(obj)
|
statedb.SetOwnedStateObject(common.HexToAddress(addr), obj)
|
||||||
for a, v := range account.Storage {
|
for a, v := range account.Storage {
|
||||||
obj.SetState(common.HexToHash(a), common.HexToHash(v))
|
obj.SetState(common.HexToHash(a), common.HexToHash(v))
|
||||||
}
|
}
|
||||||
|
|
@ -109,13 +109,16 @@ func benchStateTest(ruleSet RuleSet, test VmTest, env map[string]string, b *test
|
||||||
}
|
}
|
||||||
|
|
||||||
func runStateTests(ruleSet RuleSet, tests map[string]VmTest, skipTests []string) error {
|
func runStateTests(ruleSet RuleSet, tests map[string]VmTest, skipTests []string) error {
|
||||||
|
//glog.SetToStderr(true)
|
||||||
|
//glog.SetV(6)
|
||||||
|
|
||||||
skipTest := make(map[string]bool, len(skipTests))
|
skipTest := make(map[string]bool, len(skipTests))
|
||||||
for _, name := range skipTests {
|
for _, name := range skipTests {
|
||||||
skipTest[name] = true
|
skipTest[name] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, test := range tests {
|
for name, test := range tests {
|
||||||
if skipTest[name] /*|| name != "callcodecallcode_11" */ {
|
if skipTest[name] /*|| name != "log1_logMemsizeTooHigh"*/ {
|
||||||
glog.Infoln("Skipping state test", name)
|
glog.Infoln("Skipping state test", name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -137,7 +140,7 @@ func runStateTest(ruleSet RuleSet, test VmTest) error {
|
||||||
statedb, _ := state.New(common.Hash{}, db)
|
statedb, _ := state.New(common.Hash{}, db)
|
||||||
for addr, account := range test.Pre {
|
for addr, account := range test.Pre {
|
||||||
obj := StateObjectFromAccount(db, addr, account, statedb.MarkStateObjectDirty)
|
obj := StateObjectFromAccount(db, addr, account, statedb.MarkStateObjectDirty)
|
||||||
statedb.SetStateObject(obj)
|
statedb.SetOwnedStateObject(common.HexToAddress(addr), obj)
|
||||||
for a, v := range account.Storage {
|
for a, v := range account.Storage {
|
||||||
obj.SetState(common.HexToHash(a), common.HexToHash(v))
|
obj.SetState(common.HexToHash(a), common.HexToHash(v))
|
||||||
}
|
}
|
||||||
|
|
@ -196,7 +199,7 @@ func runStateTest(ruleSet RuleSet, test VmTest) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
root, _ := statedb.Commit()
|
root, _ := state.Commit(statedb)
|
||||||
if common.HexToHash(test.PostStateRoot) != root {
|
if common.HexToHash(test.PostStateRoot) != root {
|
||||||
return fmt.Errorf("Post state root error. Expected: %s have: %x", test.PostStateRoot, root)
|
return fmt.Errorf("Post state root error. Expected: %s have: %x", test.PostStateRoot, root)
|
||||||
}
|
}
|
||||||
|
|
@ -227,19 +230,22 @@ func RunState(ruleSet RuleSet, statedb *state.StateDB, env, tx map[string]string
|
||||||
}
|
}
|
||||||
// Set pre compiled contracts
|
// Set pre compiled contracts
|
||||||
vm.Precompiled = vm.PrecompiledContracts()
|
vm.Precompiled = vm.PrecompiledContracts()
|
||||||
snapshot := statedb.Copy()
|
snapshot := statedb
|
||||||
|
nstatedb := state.Fork(snapshot)
|
||||||
|
|
||||||
gaspool := new(core.GasPool).AddGas(common.Big(env["currentGasLimit"]))
|
gaspool := new(core.GasPool).AddGas(common.Big(env["currentGasLimit"]))
|
||||||
|
|
||||||
key, _ := hex.DecodeString(tx["secretKey"])
|
key, _ := hex.DecodeString(tx["secretKey"])
|
||||||
addr := crypto.PubkeyToAddress(crypto.ToECDSA(key).PublicKey)
|
addr := crypto.PubkeyToAddress(crypto.ToECDSA(key).PublicKey)
|
||||||
message := NewMessage(addr, to, data, value, gas, price, nonce)
|
message := NewMessage(addr, to, data, value, gas, price, nonce)
|
||||||
vmenv := NewEnvFromMap(ruleSet, statedb, env, tx)
|
vmenv := NewEnvFromMap(ruleSet, nstatedb, env, tx)
|
||||||
vmenv.origin = addr
|
vmenv.origin = addr
|
||||||
ret, _, err := core.ApplyMessage(vmenv, message, gaspool)
|
ret, _, err := core.ApplyMessage(vmenv, message, gaspool)
|
||||||
if core.IsNonceErr(err) || core.IsInvalidTxErr(err) || core.IsGasLimitErr(err) {
|
if core.IsNonceErr(err) || core.IsInvalidTxErr(err) || core.IsGasLimitErr(err) {
|
||||||
statedb.Set(snapshot)
|
vmenv.SetSnapshot(snapshot)
|
||||||
}
|
}
|
||||||
statedb.Commit()
|
statedb.Set(state.Reduce(vmenv.Db().(*state.StateDB)))
|
||||||
|
state.Commit(statedb)
|
||||||
|
|
||||||
return ret, vmenv.state.Logs(), vmenv.Gas, err
|
return ret, statedb.Logs(), vmenv.Gas, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -229,18 +229,22 @@ func (self *Env) CanTransfer(from common.Address, balance *big.Int) bool {
|
||||||
|
|
||||||
return self.state.GetBalance(from).Cmp(balance) >= 0
|
return self.state.GetBalance(from).Cmp(balance) >= 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Env) MakeSnapshot() vm.Database {
|
func (self *Env) MakeSnapshot() vm.Database {
|
||||||
return self.state.Copy()
|
pstate := self.state
|
||||||
|
self.state = state.Fork(pstate)
|
||||||
|
return pstate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Env) SetSnapshot(copy vm.Database) {
|
func (self *Env) SetSnapshot(copy vm.Database) {
|
||||||
self.state.Set(copy.(*state.StateDB))
|
self.state = copy.(*state.StateDB)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Env) Transfer(from, to vm.Account, amount *big.Int) {
|
func (self *Env) Transfer(from, to vm.Account, amount *big.Int) {
|
||||||
if self.skipTransfer {
|
if self.skipTransfer {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
core.Transfer(from, to, amount)
|
core.Transfer(self.state, from.Address(), to.Address(), amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Env) Call(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
|
func (self *Env) Call(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue