From 0a554a1f27ece4235d180373643482ceb57d90ca Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 1 Apr 2015 10:53:32 +0200 Subject: [PATCH] Blocktest fixed, Execution fixed * Added new CreateAccount method which properly overwrites previous accounts (excluding balance) * Fixed block tests (100% success) --- cmd/geth/blocktest.go | 2 +- core/block_processor.go | 6 +++- core/execution.go | 17 ++++++++-- core/genesis.go | 2 +- core/state/statedb.go | 68 +++++++++++++++++++++++++--------------- core/state_transition.go | 9 +++--- core/vm/vm.go | 3 +- tests/blocktest.go | 13 ++++---- 8 files changed, 77 insertions(+), 43 deletions(-) diff --git a/cmd/geth/blocktest.go b/cmd/geth/blocktest.go index d9cdfa83f..f0b6bb1a2 100644 --- a/cmd/geth/blocktest.go +++ b/cmd/geth/blocktest.go @@ -60,7 +60,7 @@ func runblocktest(ctx *cli.Context) { // insert the test blocks, which will execute all transactions chain := ethereum.ChainManager() 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 { fmt.Println("Block Test chain loaded") } diff --git a/core/block_processor.go b/core/block_processor.go index e970ad06e..8fbf760af 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -326,8 +326,12 @@ func (sm *BlockProcessor) AccumulateRewards(statedb *state.StateDB, block, paren 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.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) diff --git a/core/execution.go b/core/execution.go index 24e085e6d..93fb03ecc 100644 --- a/core/execution.go +++ b/core/execution.go @@ -50,16 +50,29 @@ func (self *Execution) exec(contextAddr *common.Address, code []byte, caller vm. } vsnapshot := env.State().Copy() + var createAccount bool if self.address == nil { // Generate a new address nonce := env.State().GetNonce(caller.Address()) - addr := crypto.CreateAddress(caller.Address(), nonce) env.State().SetNonce(caller.Address(), nonce+1) + + addr := crypto.CreateAddress(caller.Address(), nonce) + self.address = &addr + createAccount = true } 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) if err != nil { env.State().Set(vsnapshot) diff --git a/core/genesis.go b/core/genesis.go index 716298231..7958157a4 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -47,7 +47,7 @@ func GenesisBlock(db common.Database) *types.Block { statedb := state.New(genesis.Root(), db) for addr, account := range accounts { codedAddr := common.Hex2Bytes(addr) - accountState := statedb.GetAccount(common.BytesToAddress(codedAddr)) + accountState := statedb.CreateAccount(common.BytesToAddress(codedAddr)) accountState.SetBalance(common.Big(account.Balance)) accountState.SetCode(common.FromHex(account.Code)) statedb.UpdateStateObject(accountState) diff --git a/core/state/statedb.go b/core/state/statedb.go index 6fcd39dbc..2dc8239ef 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -57,6 +57,10 @@ func (self *StateDB) Refund(address common.Address, gas *big.Int) { self.refund[addr].Add(self.refund[addr], gas) } +/* + * GETTERS + */ + // Retrieve the balance from the given address or 0 if object not found func (self *StateDB) GetBalance(addr common.Address) *big.Int { stateObject := self.GetStateObject(addr) @@ -67,13 +71,6 @@ func (self *StateDB) GetBalance(addr common.Address) *big.Int { 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 { stateObject := self.GetStateObject(addr) if stateObject != nil { @@ -101,22 +98,41 @@ func (self *StateDB) GetState(a common.Address, b common.Hash) []byte { return nil } -func (self *StateDB) SetNonce(addr common.Address, nonce uint64) { +func (self *StateDB) IsDeleted(addr common.Address) bool { 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 { stateObject.SetNonce(nonce) } } func (self *StateDB) SetCode(addr common.Address, code []byte) { - stateObject := self.GetStateObject(addr) + stateObject := self.GetOrNewStateObject(addr) if stateObject != nil { stateObject.SetCode(code) } } func (self *StateDB) SetState(addr common.Address, key common.Hash, value interface{}) { - stateObject := self.GetStateObject(addr) + stateObject := self.GetOrNewStateObject(addr) if stateObject != nil { stateObject.SetState(key, common.NewValue(value)) } @@ -134,14 +150,6 @@ func (self *StateDB) Delete(addr common.Address) bool { 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 // @@ -194,16 +202,14 @@ func (self *StateDB) SetStateObject(object *StateObject) { func (self *StateDB) GetOrNewStateObject(addr common.Address) *StateObject { stateObject := self.GetStateObject(addr) if stateObject == nil { - stateObject = self.NewStateObject(addr) + stateObject = self.CreateAccount(addr) } return stateObject } -// Create a state object whether it exist in the trie or not -func (self *StateDB) NewStateObject(addr common.Address) *StateObject { - //addr = common.Address(addr) - +// NewStateObject create a state object whether it exist in the trie or not +func (self *StateDB) newStateObject(addr common.Address) *StateObject { statelogger.Debugf("(+) %x\n", addr) stateObject := NewStateObject(addr, self.db) @@ -212,9 +218,19 @@ func (self *StateDB) NewStateObject(addr common.Address) *StateObject { return stateObject } -// Deprecated -func (self *StateDB) GetAccount(addr common.Address) *StateObject { - return self.GetOrNewStateObject(addr) +// Creates creates a new state object and takes ownership. This is different from "NewStateObject" +func (self *StateDB) CreateAccount(addr common.Address) *StateObject { + // 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 } // diff --git a/core/state_transition.go b/core/state_transition.go index 10a49f829..7616686db 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -183,15 +183,16 @@ func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, er } // Pay data gas - var dgas int64 + dgas := new(big.Int) for _, byt := range self.data { if byt != 0 { - dgas += vm.GasTxDataNonzeroByte.Int64() + dgas.Add(dgas, vm.GasTxDataNonzeroByte) } 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) } diff --git a/core/vm/vm.go b/core/vm/vm.go index 6c3dd240a..59c64e8a3 100644 --- a/core/vm/vm.go +++ b/core/vm/vm.go @@ -857,7 +857,8 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo quadCoef = new(big.Int).Div(pow, GasQuadCoeffDenom) 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) } } diff --git a/tests/blocktest.go b/tests/blocktest.go index d813ebeec..fc62eda58 100644 --- a/tests/blocktest.go +++ b/tests/blocktest.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/hex" "encoding/json" - "errors" "fmt" "io/ioutil" "math/big" @@ -69,7 +68,7 @@ type btBlock struct { BlockHeader *btHeader Rlp string Transactions []btTransaction - UncleHeaders []string + UncleHeaders []*btHeader } 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) nonce, _ := strconv.ParseUint(acct.Nonce, 16, 64) - obj := statedb.NewStateObject(common.HexToAddress(addrString)) + obj := statedb.CreateAccount(common.HexToAddress(addrString)) obj.SetCode(code) obj.SetBalance(balance) obj.SetNonce(nonce) - // for k, v := range acct.Storage { - // obj.SetState(k, v) - // } + for k, v := range acct.Storage { + statedb.SetState(common.HexToAddress(addrString), common.HexToHash(k), common.FromHex(v)) + } } // sync objects to trie statedb.Update(nil) @@ -120,7 +119,7 @@ func (t *BlockTest) InsertPreState(db common.Database) (*state.StateDB, error) { statedb.Sync() 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 }