aboutsummaryrefslogtreecommitdiffstats
path: root/chain/block_manager.go
diff options
context:
space:
mode:
Diffstat (limited to 'chain/block_manager.go')
-rw-r--r--chain/block_manager.go137
1 files changed, 50 insertions, 87 deletions
diff --git a/chain/block_manager.go b/chain/block_manager.go
index 998b1705d..efe9e0862 100644
--- a/chain/block_manager.go
+++ b/chain/block_manager.go
@@ -3,9 +3,9 @@ package chain
import (
"bytes"
"container/list"
+ "errors"
"fmt"
"math/big"
- "os"
"sync"
"time"
@@ -88,28 +88,11 @@ func NewBlockManager(ethereum EthManager) *BlockManager {
}
func (self *BlockManager) Start() {
- statelogger.Debugln("Starting state manager")
- self.events = self.eth.EventMux().Subscribe(Blocks(nil))
- go self.updateThread()
+ statelogger.Debugln("Starting block manager")
}
func (self *BlockManager) Stop() {
statelogger.Debugln("Stopping state manager")
- self.events.Unsubscribe()
-}
-
-func (self *BlockManager) updateThread() {
- for ev := range self.events.Chan() {
- for _, block := range ev.(Blocks) {
- err := self.Process(block)
- if err != nil {
- statelogger.Infoln(err)
- statelogger.Debugf("Block #%v failed (%x...)\n", block.Number, block.Hash()[0:4])
- statelogger.Debugln(block)
- break
- }
- }
- }
}
func (sm *BlockManager) CurrentState() *state.State {
@@ -168,7 +151,6 @@ done:
erroneous = append(erroneous, tx)
err = nil
continue
- //return nil, nil, nil, err
}
}
@@ -177,21 +159,8 @@ done:
txGas.Sub(txGas, st.gas)
cumulative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas))
- //receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative}
- receipt := &Receipt{ethutil.CopyBytes(state.Root().([]byte)), cumulative, LogsBloom(state.Logs()).Bytes(), state.Logs()}
-
- if i < len(block.Receipts()) {
- original := block.Receipts()[i]
- if !original.Cmp(receipt) {
- if ethutil.Config.Diff {
- os.Exit(1)
- }
-
- err := fmt.Errorf("#%d receipt failed (r) %v ~ %x <=> (c) %v ~ %x (%x...)", i+1, original.CumulativeGasUsed, original.PostState[0:4], receipt.CumulativeGasUsed, receipt.PostState[0:4], tx.Hash()[0:4])
-
- return nil, nil, nil, nil, err
- }
- }
+ receipt := &Receipt{ethutil.CopyBytes(state.Root()), cumulative, nil /*bloom*/, state.Logs()}
+ receipt.Bloom = CreateBloom(Receipts{receipt})
// Notify all subscribers
go self.eth.EventMux().Post(TxPostEvent{tx})
@@ -204,30 +173,32 @@ done:
}
}
- parent.GasUsed = totalUsedGas
+ block.GasUsed = totalUsedGas
return receipts, handled, unhandled, erroneous, err
}
-func (sm *BlockManager) Process(block *Block) (err error) {
+func (sm *BlockManager) Process(block *Block) (td *big.Int, msgs state.Messages, err error) {
// Processing a blocks may never happen simultaneously
sm.mutex.Lock()
defer sm.mutex.Unlock()
if sm.bc.HasBlock(block.Hash()) {
- return nil
+ return nil, nil, nil
}
if !sm.bc.HasBlock(block.PrevHash) {
- return ParentError(block.PrevHash)
+ return nil, nil, ParentError(block.PrevHash)
}
+ parent := sm.bc.GetBlock(block.PrevHash)
+ return sm.ProcessWithParent(block, parent)
+}
+
+func (sm *BlockManager) ProcessWithParent(block, parent *Block) (td *big.Int, messages state.Messages, err error) {
sm.lastAttemptedBlock = block
- var (
- parent = sm.bc.GetBlock(block.PrevHash)
- state = parent.State()
- )
+ state := parent.State().Copy()
// Defer the Undo on the Trie. If the block processing happened
// we don't want to undo but since undo only happens on dirty
@@ -239,63 +210,66 @@ func (sm *BlockManager) Process(block *Block) (err error) {
fmt.Printf("## %x %x ##\n", block.Hash(), block.Number)
}
- txSha := DeriveSha(block.transactions)
- if bytes.Compare(txSha, block.TxSha) != 0 {
- return fmt.Errorf("Error validating transaction sha. Received %x, got %x", block.TxSha, txSha)
- }
-
receipts, err := sm.ApplyDiff(state, parent, block)
if err != nil {
- return err
+ return
+ }
+
+ txSha := DeriveSha(block.transactions)
+ if bytes.Compare(txSha, block.TxSha) != 0 {
+ err = fmt.Errorf("validating transaction root. received=%x got=%x", block.TxSha, txSha)
+ return
}
receiptSha := DeriveSha(receipts)
if bytes.Compare(receiptSha, block.ReceiptSha) != 0 {
- return fmt.Errorf("Error validating receipt sha. Received %x, got %x", block.ReceiptSha, receiptSha)
+ err = fmt.Errorf("validating receipt root. received=%x got=%x", block.ReceiptSha, receiptSha)
+ return
}
- // TODO validate bloom
-
// Block validation
- if err = sm.ValidateBlock(block); err != nil {
- statelogger.Errorln("Error validating block:", err)
- return err
+ if err = sm.ValidateBlock(block, parent); err != nil {
+ statelogger.Errorln("validating block:", err)
+ return
}
if err = sm.AccumelateRewards(state, block, parent); err != nil {
- statelogger.Errorln("Error accumulating reward", err)
- return err
+ statelogger.Errorln("accumulating reward", err)
+ return
+ }
+
+ block.receipts = receipts // although this isn't necessary it be in the future
+ rbloom := CreateBloom(receipts)
+ if bytes.Compare(rbloom, block.LogsBloom) != 0 {
+ err = fmt.Errorf("unable to replicate block's bloom=%x", rbloom)
+ return
}
state.Update()
if !block.State().Cmp(state) {
- err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().Trie.Root, state.Trie.Root)
+ err = fmt.Errorf("invalid merkle root. received=%x got=%x", block.Root(), state.Root())
return
}
// Calculate the new total difficulty and sync back to the db
- if sm.CalculateTD(block) {
+ if td, ok := sm.CalculateTD(block); ok {
// Sync the current block's state to the database and cancelling out the deferred Undo
state.Sync()
- // Add the block to the chain
- sm.bc.Add(block)
+ messages := state.Manifest().Messages
+ state.Manifest().Reset()
- // TODO at this point we should also insert LOGS in to a database
+ chainlogger.Infof("Processed block #%d (%x...)\n", block.Number, block.Hash()[0:4])
sm.transState = state.Copy()
- statelogger.Infof("Imported block #%d (%x...)\n", block.Number, block.Hash()[0:4])
-
- state.Manifest().Reset()
-
sm.eth.TxPool().RemoveSet(block.Transactions())
+
+ return td, messages, nil
} else {
- statelogger.Errorln("total diff failed")
+ return nil, nil, errors.New("total diff failed")
}
-
- return nil
}
func (sm *BlockManager) ApplyDiff(state *state.State, parent, block *Block) (receipts Receipts, err error) {
@@ -311,7 +285,7 @@ func (sm *BlockManager) ApplyDiff(state *state.State, parent, block *Block) (rec
return receipts, nil
}
-func (sm *BlockManager) CalculateTD(block *Block) bool {
+func (sm *BlockManager) CalculateTD(block *Block) (*big.Int, bool) {
uncleDiff := new(big.Int)
for _, uncle := range block.Uncles {
uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty)
@@ -325,30 +299,19 @@ func (sm *BlockManager) CalculateTD(block *Block) bool {
// The new TD will only be accepted if the new difficulty is
// is greater than the previous.
if td.Cmp(sm.bc.TD) > 0 {
- // Set the new total difficulty back to the block chain
- sm.bc.SetTotalDifficulty(td)
+ return td, true
- return true
+ // Set the new total difficulty back to the block chain
+ //sm.bc.SetTotalDifficulty(td)
}
- return false
+ return nil, false
}
// Validates the current block. Returns an error if the block was invalid,
// an uncle or anything that isn't on the current block chain.
// Validation validates easy over difficult (dagger takes longer time = difficult)
-func (sm *BlockManager) ValidateBlock(block *Block) error {
- // Check each uncle's previous hash. In order for it to be valid
- // is if it has the same block hash as the current
- parent := sm.bc.GetBlock(block.PrevHash)
- /*
- for _, uncle := range block.Uncles {
- if bytes.Compare(uncle.PrevHash,parent.PrevHash) != 0 {
- return ValidationError("Mismatch uncle's previous hash. Expected %x, got %x",parent.PrevHash, uncle.PrevHash)
- }
- }
- */
-
+func (sm *BlockManager) ValidateBlock(block, parent *Block) error {
expd := CalcDifficulty(block, parent)
if expd.Cmp(block.Difficulty) < 0 {
return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd)
@@ -387,7 +350,7 @@ func (sm *BlockManager) AccumelateRewards(state *state.State, block, parent *Blo
uncleParent := sm.bc.GetBlock(uncle.PrevHash)
if uncleParent == nil {
- return UncleError("Uncle's parent unknown")
+ return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.PrevHash[0:4]))
}
if uncleParent.Number.Cmp(new(big.Int).Sub(parent.Number, big.NewInt(6))) < 0 {