diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/block_processor.go | 15 | ||||
-rw-r--r-- | core/chain_manager.go | 82 | ||||
-rw-r--r-- | core/error.go | 2 | ||||
-rw-r--r-- | core/execution.go | 11 | ||||
-rw-r--r-- | core/genesis.go | 3 | ||||
-rw-r--r-- | core/state_transition.go | 50 |
6 files changed, 87 insertions, 76 deletions
diff --git a/core/block_processor.go b/core/block_processor.go index 395622a8e..f421c3539 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -78,21 +78,18 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated // If we are mining this block and validating we want to set the logs back to 0 statedb.EmptyLogs() - txGas := new(big.Int).Set(tx.Gas()) - cb := statedb.GetStateObject(coinbase.Address()) - st := NewStateTransition(NewEnv(statedb, self.bc, tx, block), tx, cb) - _, err := st.TransitionState() + _, gas, err := ApplyMessage(NewEnv(statedb, self.bc, tx, block), tx, cb) if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err) || IsInvalidTxErr(err)) { + // If the account is managed, remove the invalid nonce. + self.bc.TxState().RemoveNonce(tx.From(), tx.Nonce()) return nil, nil, err } - txGas.Sub(txGas, st.gas) - // Update the state with pending changes - statedb.Update(txGas) + statedb.Update(nil) - cumulative := new(big.Int).Set(usedGas.Add(usedGas, txGas)) + cumulative := new(big.Int).Set(usedGas.Add(usedGas, gas)) receipt := types.NewReceipt(statedb.Root(), cumulative) receipt.SetLogs(statedb.Logs()) receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) @@ -105,7 +102,7 @@ func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, stated go self.eventMux.Post(logs) } - return receipt, txGas, err + return receipt, gas, err } func (self *BlockProcessor) ChainManager() *ChainManager { return self.bc diff --git a/core/chain_manager.go b/core/chain_manager.go index 97c61395e..af9053820 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -17,6 +17,9 @@ import ( var ( chainlogger = logger.NewLogger("CHAIN") jsonlogger = logger.NewJsonLogger() + + blockHashPre = []byte("block-hash-") + blockNumPre = []byte("block-num-") ) type StateQuery interface { @@ -68,9 +71,7 @@ func CalcGasLimit(parent, block *types.Block) *big.Int { result := new(big.Int).Add(previous, curInt) result.Div(result, big.NewInt(1024)) - min := big.NewInt(125000) - - return ethutil.BigMax(min, result) + return ethutil.BigMax(GenesisGasLimit, result) } type ChainManager struct { @@ -88,7 +89,7 @@ type ChainManager struct { lastBlockHash []byte transState *state.StateDB - txState *state.StateDB + txState *state.ManagedState quit chan struct{} } @@ -97,7 +98,8 @@ func NewChainManager(blockDb, stateDb ethutil.Database, mux *event.TypeMux) *Cha bc := &ChainManager{blockDb: blockDb, stateDb: stateDb, genesisBlock: GenesisBlock(stateDb), eventMux: mux, quit: make(chan struct{})} bc.setLastBlock() bc.transState = bc.State().Copy() - bc.txState = bc.State().Copy() + // Take ownership of this particular state + bc.txState = state.ManageState(bc.State().Copy()) go bc.update() return bc @@ -146,17 +148,17 @@ func (self *ChainManager) TransState() *state.StateDB { return self.transState } -func (self *ChainManager) TxState() *state.StateDB { +func (self *ChainManager) TxState() *state.ManagedState { self.tsmu.RLock() defer self.tsmu.RUnlock() return self.txState } -func (self *ChainManager) setTxState(state *state.StateDB) { +func (self *ChainManager) setTxState(statedb *state.StateDB) { self.tsmu.Lock() defer self.tsmu.Unlock() - self.txState = state + self.txState = state.ManageState(statedb) } func (self *ChainManager) setTransState(statedb *state.StateDB) { @@ -166,9 +168,8 @@ func (self *ChainManager) setTransState(statedb *state.StateDB) { func (bc *ChainManager) setLastBlock() { data, _ := bc.blockDb.Get([]byte("LastBlock")) if len(data) != 0 { - var block types.Block - rlp.Decode(bytes.NewReader(data), &block) - bc.currentBlock = &block + block := bc.GetBlock(data) + bc.currentBlock = block bc.lastBlockHash = block.Hash() // Set the last know difficulty (might be 0x0 as initial value, Genesis) @@ -221,7 +222,7 @@ func (bc *ChainManager) Reset() { defer bc.mu.Unlock() for block := bc.currentBlock; block != nil; block = bc.GetBlock(block.Header().ParentHash) { - bc.blockDb.Delete(block.Hash()) + bc.removeBlock(block) } // Prepare the genesis block @@ -232,12 +233,16 @@ func (bc *ChainManager) Reset() { bc.setTotalDifficulty(ethutil.Big("0")) } +func (bc *ChainManager) removeBlock(block *types.Block) { + bc.blockDb.Delete(append(blockHashPre, block.Hash()...)) +} + func (bc *ChainManager) ResetWithGenesisBlock(gb *types.Block) { bc.mu.Lock() defer bc.mu.Unlock() for block := bc.currentBlock; block != nil; block = bc.GetBlock(block.Header().ParentHash) { - bc.blockDb.Delete(block.Hash()) + bc.removeBlock(block) } // Prepare the genesis block @@ -262,15 +267,20 @@ func (self *ChainManager) Export() []byte { } func (bc *ChainManager) insert(block *types.Block) { - encodedBlock := ethutil.Encode(block) - bc.blockDb.Put([]byte("LastBlock"), encodedBlock) + //encodedBlock := ethutil.Encode(block) + bc.blockDb.Put([]byte("LastBlock"), block.Hash()) bc.currentBlock = block bc.lastBlockHash = block.Hash() + + key := append(blockNumPre, block.Number().Bytes()...) + bc.blockDb.Put(key, bc.lastBlockHash) } func (bc *ChainManager) write(block *types.Block) { encodedBlock := ethutil.Encode(block.RlpDataForStorage()) - bc.blockDb.Put(block.Hash(), encodedBlock) + + key := append(blockHashPre, block.Hash()...) + bc.blockDb.Put(key, encodedBlock) } // Accessors @@ -280,7 +290,7 @@ func (bc *ChainManager) Genesis() *types.Block { // Block fetching methods func (bc *ChainManager) HasBlock(hash []byte) bool { - data, _ := bc.blockDb.Get(hash) + data, _ := bc.blockDb.Get(append(blockHashPre, hash...)) return len(data) != 0 } @@ -308,7 +318,7 @@ func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain } func (self *ChainManager) GetBlock(hash []byte) *types.Block { - data, _ := self.blockDb.Get(hash) + data, _ := self.blockDb.Get(append(blockHashPre, hash...)) if len(data) == 0 { return nil } @@ -321,6 +331,18 @@ func (self *ChainManager) GetBlock(hash []byte) *types.Block { return &block } +func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block { + self.mu.RLock() + defer self.mu.RUnlock() + + key, _ := self.blockDb.Get(append(blockNumPre, big.NewInt(int64(num)).Bytes()...)) + if len(key) == 0 { + return nil + } + + return self.GetBlock(key) +} + func (self *ChainManager) GetUnclesInChain(block *types.Block, length int) (uncles []*types.Header) { for i := 0; block != nil && i < length; i++ { uncles = append(uncles, block.Uncles()...) @@ -343,24 +365,6 @@ func (self *ChainManager) GetAncestors(block *types.Block, length int) (blocks [ return } -func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block { - self.mu.RLock() - defer self.mu.RUnlock() - - var block *types.Block - - if num <= self.currentBlock.Number().Uint64() { - block = self.currentBlock - for ; block != nil; block = self.GetBlock(block.Header().ParentHash) { - if block.Header().Number.Uint64() == num { - break - } - } - } - - return block -} - func (bc *ChainManager) setTotalDifficulty(td *big.Int) { bc.blockDb.Put([]byte("LTD"), td.Bytes()) bc.td = td @@ -414,9 +418,9 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { } h := block.Header() - chainlogger.Infof("block #%v process failed (%x)\n", h.Number, h.Hash()[:4]) - chainlogger.Infoln(block) + chainlogger.Infof("INVALID block #%v (%x)\n", h.Number, h.Hash()[:4]) chainlogger.Infoln(err) + chainlogger.Debufln(block) return err } block.Td = td @@ -450,6 +454,8 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { */ self.setTransState(state.New(block.Root(), self.stateDb)) + self.setTxState(state.New(block.Root(), self.stateDb)) + queue[i] = ChainEvent{block} queueEvent.canonicalCount++ } else { diff --git a/core/error.go b/core/error.go index 04e40646c..69e320eb0 100644 --- a/core/error.go +++ b/core/error.go @@ -78,7 +78,7 @@ func (err *NonceErr) Error() string { } func NonceError(is, exp uint64) *NonceErr { - return &NonceErr{Message: fmt.Sprintf("Nonce err. Is %d, expected %d", is, exp), Is: is, Exp: exp} + return &NonceErr{Message: fmt.Sprintf("Transaction w/ invalid nonce (%d / %d)", is, exp), Is: is, Exp: exp} } func IsNonceErr(err error) bool { diff --git a/core/execution.go b/core/execution.go index 4a69cce09..be45eeeb4 100644 --- a/core/execution.go +++ b/core/execution.go @@ -25,10 +25,7 @@ func (self *Execution) Addr() []byte { func (self *Execution) Call(codeAddr []byte, caller vm.ContextRef) ([]byte, error) { // Retrieve the executing code - var code []byte - if self.env.State().GetStateObject(codeAddr) != nil { - code = self.env.State().GetCode(codeAddr) - } + code := self.env.State().GetCode(codeAddr) return self.exec(code, codeAddr, caller) } @@ -62,7 +59,11 @@ func (self *Execution) exec(code, contextAddr []byte, caller vm.ContextRef) (ret snapshot := env.State().Copy() start := time.Now() - ret, err = evm.Run(to, caller, code, self.value, self.Gas, self.price, self.input) + + context := vm.NewContext(caller, to, self.value, self.Gas, self.price) + context.SetCallCode(contextAddr, code) + + ret, err = evm.Run(context, self.input) //self.value, self.Gas, self.price, self.input) chainlogger.Debugf("vm took %v\n", time.Since(start)) if err != nil { env.State().Set(snapshot) diff --git a/core/genesis.go b/core/genesis.go index a3f5dfb38..a3d701f9f 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -23,11 +23,12 @@ var EmptyShaList = crypto.Sha3(ethutil.Encode([]interface{}{})) var EmptyListRoot = crypto.Sha3(ethutil.Encode("")) var GenesisDiff = big.NewInt(131072) +var GenesisGasLimit = big.NewInt(3141592) func GenesisBlock(db ethutil.Database) *types.Block { genesis := types.NewBlock(ZeroHash256, ZeroHash160, nil, GenesisDiff, 42, "") genesis.Header().Number = ethutil.Big0 - genesis.Header().GasLimit = big.NewInt(1000000) + genesis.Header().GasLimit = GenesisGasLimit genesis.Header().GasUsed = ethutil.Big0 genesis.Header().Time = 0 genesis.Header().SeedHash = make([]byte, 32) diff --git a/core/state_transition.go b/core/state_transition.go index 7659e3d50..f49aed874 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -69,6 +69,10 @@ func MessageGasValue(msg Message) *big.Int { return new(big.Int).Mul(msg.Gas(), msg.GasPrice()) } +func ApplyMessage(env vm.Environment, msg Message, coinbase *state.StateObject) ([]byte, *big.Int, error) { + return NewStateTransition(env, msg, coinbase).transitionState() +} + func NewStateTransition(env vm.Environment, msg Message, coinbase *state.StateObject) *StateTransition { return &StateTransition{ coinbase: coinbase.Address(), @@ -144,13 +148,16 @@ func (self *StateTransition) preCheck() (err error) { // Pre-pay gas / Buy gas of the coinbase account if err = self.BuyGas(); err != nil { + if state.IsGasLimitErr(err) { + return err + } return InvalidTxError(err) } return nil } -func (self *StateTransition) TransitionState() (ret []byte, err error) { +func (self *StateTransition) transitionState() (ret []byte, usedGas *big.Int, err error) { // statelogger.Debugf("(~) %x\n", self.msg.Hash()) // XXX Transactions after this point are considered valid. @@ -163,11 +170,9 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) { sender = self.From() ) - defer self.RefundGas() - // Transaction gas if err = self.UseGas(vm.GasTx); err != nil { - return nil, InvalidTxError(err) + return nil, nil, InvalidTxError(err) } // Increment the nonce for the next transaction @@ -184,15 +189,13 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) { } } if err = self.UseGas(big.NewInt(dgas)); err != nil { - println("2") - return nil, InvalidTxError(err) + return nil, nil, InvalidTxError(err) } - //stateCopy := self.env.State().Copy() vmenv := self.env var ref vm.ContextRef if MessageCreatesContract(msg) { - contract := MakeContract(msg, self.state) + contract := makeContract(msg, self.state) ret, err, ref = vmenv.Create(sender, contract.Address(), self.msg.Data(), self.gas, self.gasPrice, self.value) if err == nil { dataGas := big.NewInt(int64(len(ret))) @@ -208,29 +211,22 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) { } if err != nil && IsValueTransferErr(err) { - return nil, InvalidTxError(err) + return nil, nil, InvalidTxError(err) } - return -} - -// Converts an transaction in to a state object -func MakeContract(msg Message, state *state.StateDB) *state.StateObject { - addr := AddressFromMessage(msg) - - contract := state.GetOrNewStateObject(addr) - contract.SetInitCode(msg.Data()) + self.refundGas() + self.state.AddBalance(self.coinbase, new(big.Int).Mul(self.gasUsed(), self.gasPrice)) - return contract + return ret, self.gasUsed(), err } -func (self *StateTransition) RefundGas() { +func (self *StateTransition) refundGas() { coinbase, sender := self.Coinbase(), self.From() // Return remaining gas remaining := new(big.Int).Mul(self.gas, self.msg.GasPrice()) sender.AddBalance(remaining) - uhalf := new(big.Int).Div(self.GasUsed(), ethutil.Big2) + uhalf := new(big.Int).Div(self.gasUsed(), ethutil.Big2) for addr, ref := range self.state.Refunds() { refund := ethutil.BigMin(uhalf, ref) self.gas.Add(self.gas, refund) @@ -240,6 +236,16 @@ func (self *StateTransition) RefundGas() { coinbase.RefundGas(self.gas, self.msg.GasPrice()) } -func (self *StateTransition) GasUsed() *big.Int { +func (self *StateTransition) gasUsed() *big.Int { return new(big.Int).Sub(self.initialGas, self.gas) } + +// Converts an message in to a state object +func makeContract(msg Message, state *state.StateDB) *state.StateObject { + addr := AddressFromMessage(msg) + + contract := state.GetOrNewStateObject(addr) + contract.SetInitCode(msg.Data()) + + return contract +} |