Blocktest fixed, Execution fixed

* Added new CreateAccount method which properly overwrites previous
  accounts (excluding balance)
* Fixed block tests (100% success)
This commit is contained in:
obscuren 2015-04-01 10:53:32 +02:00
parent d3e86f9208
commit 0a554a1f27
8 changed files with 77 additions and 43 deletions

View File

@ -60,7 +60,7 @@ func runblocktest(ctx *cli.Context) {
// insert the test blocks, which will execute all transactions // insert the test blocks, which will execute all transactions
chain := ethereum.ChainManager() chain := ethereum.ChainManager()
if err := chain.InsertChain(test.Blocks); err != nil { if err := chain.InsertChain(test.Blocks); err != nil {
utils.Fatalf("Block Test load error: %v", err) utils.Fatalf("Block Test load error: %v %T", err, err)
} else { } else {
fmt.Println("Block Test chain loaded") fmt.Println("Block Test chain loaded")
} }

View File

@ -326,8 +326,12 @@ func (sm *BlockProcessor) AccumulateRewards(statedb *state.StateDB, block, paren
return ValidationError(fmt.Sprintf("%v", err)) return ValidationError(fmt.Sprintf("%v", err))
} }
num := new(big.Int).Add(big.NewInt(8), uncle.Number)
num.Sub(num, block.Number())
r := new(big.Int) r := new(big.Int)
r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16)) r.Mul(BlockReward, num)
r.Div(r, big.NewInt(8))
statedb.AddBalance(uncle.Coinbase, r) statedb.AddBalance(uncle.Coinbase, r)

View File

@ -50,16 +50,29 @@ func (self *Execution) exec(contextAddr *common.Address, code []byte, caller vm.
} }
vsnapshot := env.State().Copy() vsnapshot := env.State().Copy()
var createAccount bool
if self.address == nil { if self.address == nil {
// Generate a new address // Generate a new address
nonce := env.State().GetNonce(caller.Address()) nonce := env.State().GetNonce(caller.Address())
addr := crypto.CreateAddress(caller.Address(), nonce)
env.State().SetNonce(caller.Address(), nonce+1) env.State().SetNonce(caller.Address(), nonce+1)
addr := crypto.CreateAddress(caller.Address(), nonce)
self.address = &addr self.address = &addr
createAccount = true
} }
snapshot := env.State().Copy() snapshot := env.State().Copy()
from, to := env.State().GetStateObject(caller.Address()), env.State().GetOrNewStateObject(*self.address) var (
from = env.State().GetStateObject(caller.Address())
to *state.StateObject
)
if createAccount {
to = env.State().CreateAccount(*self.address)
} else {
to = env.State().GetOrNewStateObject(*self.address)
}
err = env.Transfer(from, to, self.value) err = env.Transfer(from, to, self.value)
if err != nil { if err != nil {
env.State().Set(vsnapshot) env.State().Set(vsnapshot)

View File

@ -47,7 +47,7 @@ func GenesisBlock(db common.Database) *types.Block {
statedb := state.New(genesis.Root(), db) statedb := state.New(genesis.Root(), db)
for addr, account := range accounts { for addr, account := range accounts {
codedAddr := common.Hex2Bytes(addr) codedAddr := common.Hex2Bytes(addr)
accountState := statedb.GetAccount(common.BytesToAddress(codedAddr)) accountState := statedb.CreateAccount(common.BytesToAddress(codedAddr))
accountState.SetBalance(common.Big(account.Balance)) accountState.SetBalance(common.Big(account.Balance))
accountState.SetCode(common.FromHex(account.Code)) accountState.SetCode(common.FromHex(account.Code))
statedb.UpdateStateObject(accountState) statedb.UpdateStateObject(accountState)

View File

@ -57,6 +57,10 @@ func (self *StateDB) Refund(address common.Address, gas *big.Int) {
self.refund[addr].Add(self.refund[addr], gas) self.refund[addr].Add(self.refund[addr], gas)
} }
/*
* GETTERS
*/
// 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)
@ -67,13 +71,6 @@ func (self *StateDB) GetBalance(addr common.Address) *big.Int {
return common.Big0 return common.Big0
} }
func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) {
stateObject := self.GetStateObject(addr)
if stateObject != nil {
stateObject.AddBalance(amount)
}
}
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 {
@ -101,22 +98,41 @@ func (self *StateDB) GetState(a common.Address, b common.Hash) []byte {
return nil return nil
} }
func (self *StateDB) SetNonce(addr common.Address, nonce uint64) { func (self *StateDB) IsDeleted(addr common.Address) bool {
stateObject := self.GetStateObject(addr) stateObject := self.GetStateObject(addr)
if stateObject != nil {
return stateObject.remove
}
return false
}
/*
* SETTERS
*/
func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) {
stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil {
stateObject.AddBalance(amount)
}
}
func (self *StateDB) SetNonce(addr common.Address, nonce uint64) {
stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
stateObject.SetNonce(nonce) stateObject.SetNonce(nonce)
} }
} }
func (self *StateDB) SetCode(addr common.Address, code []byte) { func (self *StateDB) SetCode(addr common.Address, code []byte) {
stateObject := self.GetStateObject(addr) stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
stateObject.SetCode(code) stateObject.SetCode(code)
} }
} }
func (self *StateDB) SetState(addr common.Address, key common.Hash, value interface{}) { func (self *StateDB) SetState(addr common.Address, key common.Hash, value interface{}) {
stateObject := self.GetStateObject(addr) stateObject := self.GetOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
stateObject.SetState(key, common.NewValue(value)) stateObject.SetState(key, common.NewValue(value))
} }
@ -134,14 +150,6 @@ func (self *StateDB) Delete(addr common.Address) bool {
return false return false
} }
func (self *StateDB) IsDeleted(addr common.Address) bool {
stateObject := self.GetStateObject(addr)
if stateObject != nil {
return stateObject.remove
}
return false
}
// //
// Setting, updating & deleting state object methods // Setting, updating & deleting state object methods
// //
@ -194,16 +202,14 @@ func (self *StateDB) SetStateObject(object *StateObject) {
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 { if stateObject == nil {
stateObject = self.NewStateObject(addr) stateObject = self.CreateAccount(addr)
} }
return stateObject return stateObject
} }
// 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 {
//addr = common.Address(addr)
statelogger.Debugf("(+) %x\n", addr) statelogger.Debugf("(+) %x\n", addr)
stateObject := NewStateObject(addr, self.db) stateObject := NewStateObject(addr, self.db)
@ -212,9 +218,19 @@ func (self *StateDB) NewStateObject(addr common.Address) *StateObject {
return stateObject return stateObject
} }
// Deprecated // Creates creates a new state object and takes ownership. This is different from "NewStateObject"
func (self *StateDB) GetAccount(addr common.Address) *StateObject { func (self *StateDB) CreateAccount(addr common.Address) *StateObject {
return self.GetOrNewStateObject(addr) // Get previous (if any)
so := self.GetStateObject(addr)
// Create a new one
newSo := self.newStateObject(addr)
// If it existed set the balance to the new account
if so != nil {
newSo.balance = so.balance
}
return newSo
} }
// //

View File

@ -183,15 +183,16 @@ func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, er
} }
// Pay data gas // Pay data gas
var dgas int64 dgas := new(big.Int)
for _, byt := range self.data { for _, byt := range self.data {
if byt != 0 { if byt != 0 {
dgas += vm.GasTxDataNonzeroByte.Int64() dgas.Add(dgas, vm.GasTxDataNonzeroByte)
} else { } else {
dgas += vm.GasTxDataZeroByte.Int64() dgas.Add(dgas, vm.GasTxDataZeroByte)
} }
} }
if err = self.UseGas(big.NewInt(dgas)); err != nil {
if err = self.UseGas(dgas); err != nil {
return nil, nil, InvalidTxError(err) return nil, nil, InvalidTxError(err)
} }

View File

@ -857,7 +857,8 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
quadCoef = new(big.Int).Div(pow, GasQuadCoeffDenom) quadCoef = new(big.Int).Div(pow, GasQuadCoeffDenom)
newTotalFee := new(big.Int).Add(linCoef, quadCoef) newTotalFee := new(big.Int).Add(linCoef, quadCoef)
gas.Add(gas, new(big.Int).Sub(newTotalFee, oldTotalFee)) fee := new(big.Int).Sub(newTotalFee, oldTotalFee)
gas.Add(gas, fee)
} }
} }

View File

@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math/big" "math/big"
@ -69,7 +68,7 @@ type btBlock struct {
BlockHeader *btHeader BlockHeader *btHeader
Rlp string Rlp string
Transactions []btTransaction Transactions []btTransaction
UncleHeaders []string UncleHeaders []*btHeader
} }
type BlockTest struct { type BlockTest struct {
@ -106,13 +105,13 @@ func (t *BlockTest) InsertPreState(db common.Database) (*state.StateDB, error) {
balance, _ := new(big.Int).SetString(acct.Balance, 0) balance, _ := new(big.Int).SetString(acct.Balance, 0)
nonce, _ := strconv.ParseUint(acct.Nonce, 16, 64) nonce, _ := strconv.ParseUint(acct.Nonce, 16, 64)
obj := statedb.NewStateObject(common.HexToAddress(addrString)) obj := statedb.CreateAccount(common.HexToAddress(addrString))
obj.SetCode(code) obj.SetCode(code)
obj.SetBalance(balance) obj.SetBalance(balance)
obj.SetNonce(nonce) obj.SetNonce(nonce)
// for k, v := range acct.Storage { for k, v := range acct.Storage {
// obj.SetState(k, v) statedb.SetState(common.HexToAddress(addrString), common.HexToHash(k), common.FromHex(v))
// } }
} }
// sync objects to trie // sync objects to trie
statedb.Update(nil) statedb.Update(nil)
@ -120,7 +119,7 @@ func (t *BlockTest) InsertPreState(db common.Database) (*state.StateDB, error) {
statedb.Sync() statedb.Sync()
if !bytes.Equal(t.Genesis.Root().Bytes(), statedb.Root().Bytes()) { if !bytes.Equal(t.Genesis.Root().Bytes(), statedb.Root().Bytes()) {
return nil, errors.New("computed state root does not match genesis block") return nil, fmt.Errorf("computed state root does not match genesis block %x %x", t.Genesis.Root().Bytes()[:4], statedb.Root().Bytes()[:4])
} }
return statedb, nil return statedb, nil
} }