Browse Source

core, eth, rpc: split out block validator and state processor

This removes the burden on a single object to take care of all
validation and state processing. Now instead the validation is done by
the `core.BlockValidator` (`types.Validator`) that takes care of both
header and uncle validation through the `ValidateBlock` method and state
validation through the `ValidateState` method. The state processing is
done by a new object `core.StateProcessor` (`types.Processor`) and
accepts a new state as input and uses that to process the given block's
transactions (and uncles for rewords) to calculate the state root for
the next block (P_n + 1).
Jeffrey Wilcke 10 years ago
parent
commit
a1d9ef48c5

+ 0 - 2
cmd/utils/flags.go

@@ -557,8 +557,6 @@ func MakeChain(ctx *cli.Context) (chain *core.BlockChain, chainDb ethdb.Database
 		Fatalf("Could not start chainmanager: %v", err)
 	}
 
-	proc := core.NewBlockProcessor(chainDb, pow, chain, eventMux)
-	chain.SetProcessor(proc)
 	return chain, chainDb
 }
 

+ 0 - 1
core/bench_test.go

@@ -169,7 +169,6 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
 	// State and blocks are stored in the same DB.
 	evmux := new(event.TypeMux)
 	chainman, _ := NewBlockChain(db, FakePow{}, evmux)
-	chainman.SetProcessor(NewBlockProcessor(db, FakePow{}, chainman, evmux))
 	defer chainman.Stop()
 	b.ReportAllocs()
 	b.ResetTimer()

+ 0 - 460
core/block_processor.go

@@ -1,460 +0,0 @@
-// Copyright 2014 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package core
-
-import (
-	"fmt"
-	"math/big"
-	"sync"
-	"time"
-
-	"github.com/ethereum/go-ethereum/common"
-	"github.com/ethereum/go-ethereum/core/state"
-	"github.com/ethereum/go-ethereum/core/types"
-	"github.com/ethereum/go-ethereum/core/vm"
-	"github.com/ethereum/go-ethereum/crypto"
-	"github.com/ethereum/go-ethereum/ethdb"
-	"github.com/ethereum/go-ethereum/event"
-	"github.com/ethereum/go-ethereum/logger"
-	"github.com/ethereum/go-ethereum/logger/glog"
-	"github.com/ethereum/go-ethereum/params"
-	"github.com/ethereum/go-ethereum/pow"
-	"gopkg.in/fatih/set.v0"
-)
-
-const (
-	// must be bumped when consensus algorithm is changed, this forces the upgradedb
-	// command to be run (forces the blocks to be imported again using the new algorithm)
-	BlockChainVersion = 3
-)
-
-type BlockProcessor struct {
-	chainDb ethdb.Database
-	// Mutex for locking the block processor. Blocks can only be handled one at a time
-	mutex sync.Mutex
-	// Canonical block chain
-	bc *BlockChain
-	// non-persistent key/value memory storage
-	mem map[string]*big.Int
-	// Proof of work used for validating
-	Pow pow.PoW
-
-	events event.Subscription
-
-	eventMux *event.TypeMux
-}
-
-// GasPool tracks the amount of gas available during
-// execution of the transactions in a block.
-// The zero value is a pool with zero gas available.
-type GasPool big.Int
-
-// AddGas makes gas available for execution.
-func (gp *GasPool) AddGas(amount *big.Int) *GasPool {
-	i := (*big.Int)(gp)
-	i.Add(i, amount)
-	return gp
-}
-
-// SubGas deducts the given amount from the pool if enough gas is
-// available and returns an error otherwise.
-func (gp *GasPool) SubGas(amount *big.Int) error {
-	i := (*big.Int)(gp)
-	if i.Cmp(amount) < 0 {
-		return &GasLimitErr{Have: new(big.Int).Set(i), Want: amount}
-	}
-	i.Sub(i, amount)
-	return nil
-}
-
-func (gp *GasPool) String() string {
-	return (*big.Int)(gp).String()
-}
-
-func NewBlockProcessor(db ethdb.Database, pow pow.PoW, blockchain *BlockChain, eventMux *event.TypeMux) *BlockProcessor {
-	sm := &BlockProcessor{
-		chainDb:  db,
-		mem:      make(map[string]*big.Int),
-		Pow:      pow,
-		bc:       blockchain,
-		eventMux: eventMux,
-	}
-	return sm
-}
-
-func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block, transientProcess bool) (receipts types.Receipts, err error) {
-	gp := new(GasPool).AddGas(block.GasLimit())
-	if glog.V(logger.Core) {
-		glog.Infof("%x: gas (+ %v)", block.Coinbase(), gp)
-	}
-
-	// Process the transactions on to parent state
-	receipts, err = sm.ApplyTransactions(gp, statedb, block, block.Transactions(), transientProcess)
-	if err != nil {
-		return nil, err
-	}
-
-	return receipts, nil
-}
-
-func (self *BlockProcessor) ApplyTransaction(gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, transientProcess bool) (*types.Receipt, *big.Int, error) {
-	_, gas, err := ApplyMessage(NewEnv(statedb, self.bc, tx, header), tx, gp)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	// Update the state with pending changes
-	usedGas.Add(usedGas, gas)
-	receipt := types.NewReceipt(statedb.IntermediateRoot().Bytes(), usedGas)
-	receipt.TxHash = tx.Hash()
-	receipt.GasUsed = new(big.Int).Set(gas)
-	if MessageCreatesContract(tx) {
-		from, _ := tx.From()
-		receipt.ContractAddress = crypto.CreateAddress(from, tx.Nonce())
-	}
-
-	logs := statedb.GetLogs(tx.Hash())
-	receipt.Logs = logs
-	receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
-
-	glog.V(logger.Debug).Infoln(receipt)
-
-	// Notify all subscribers
-	if !transientProcess {
-		go self.eventMux.Post(TxPostEvent{tx})
-		go self.eventMux.Post(logs)
-	}
-
-	return receipt, gas, err
-}
-func (self *BlockProcessor) BlockChain() *BlockChain {
-	return self.bc
-}
-
-func (self *BlockProcessor) ApplyTransactions(gp *GasPool, statedb *state.StateDB, block *types.Block, txs types.Transactions, transientProcess bool) (types.Receipts, error) {
-	var (
-		receipts      types.Receipts
-		totalUsedGas  = big.NewInt(0)
-		err           error
-		cumulativeSum = new(big.Int)
-		header        = block.Header()
-	)
-
-	for i, tx := range txs {
-		statedb.StartRecord(tx.Hash(), block.Hash(), i)
-
-		receipt, txGas, err := self.ApplyTransaction(gp, statedb, header, tx, totalUsedGas, transientProcess)
-		if err != nil {
-			return nil, err
-		}
-
-		if err != nil {
-			glog.V(logger.Core).Infoln("TX err:", err)
-		}
-		receipts = append(receipts, receipt)
-
-		cumulativeSum.Add(cumulativeSum, new(big.Int).Mul(txGas, tx.GasPrice()))
-	}
-
-	if block.GasUsed().Cmp(totalUsedGas) != 0 {
-		return nil, ValidationError(fmt.Sprintf("gas used error (%v / %v)", block.GasUsed(), totalUsedGas))
-	}
-
-	if transientProcess {
-		go self.eventMux.Post(PendingBlockEvent{block, statedb.Logs()})
-	}
-
-	return receipts, err
-}
-
-func (sm *BlockProcessor) RetryProcess(block *types.Block) (logs vm.Logs, err error) {
-	// Processing a blocks may never happen simultaneously
-	sm.mutex.Lock()
-	defer sm.mutex.Unlock()
-
-	if !sm.bc.HasBlock(block.ParentHash()) {
-		return nil, ParentError(block.ParentHash())
-	}
-	parent := sm.bc.GetBlock(block.ParentHash())
-
-	// FIXME Change to full header validation. See #1225
-	errch := make(chan bool)
-	go func() { errch <- sm.Pow.Verify(block) }()
-
-	logs, _, err = sm.processWithParent(block, parent)
-	if !<-errch {
-		return nil, ValidationError("Block's nonce is invalid (= %x)", block.Nonce)
-	}
-
-	return logs, err
-}
-
-// Process block will attempt to process the given block's transactions and applies them
-// on top of the block's parent state (given it exists) and will return wether it was
-// successful or not.
-func (sm *BlockProcessor) Process(block *types.Block) (logs vm.Logs, receipts types.Receipts, err error) {
-	// Processing a blocks may never happen simultaneously
-	sm.mutex.Lock()
-	defer sm.mutex.Unlock()
-
-	if sm.bc.HasBlock(block.Hash()) {
-		if _, err := state.New(block.Root(), sm.chainDb); err == nil {
-			return nil, nil, &KnownBlockError{block.Number(), block.Hash()}
-		}
-	}
-	if parent := sm.bc.GetBlock(block.ParentHash()); parent != nil {
-		if _, err := state.New(parent.Root(), sm.chainDb); err == nil {
-			return sm.processWithParent(block, parent)
-		}
-	}
-	return nil, nil, ParentError(block.ParentHash())
-}
-
-func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs vm.Logs, receipts types.Receipts, err error) {
-	// Create a new state based on the parent's root (e.g., create copy)
-	state, err := state.New(parent.Root(), sm.chainDb)
-	if err != nil {
-		return nil, nil, err
-	}
-	header := block.Header()
-	uncles := block.Uncles()
-	txs := block.Transactions()
-
-	// Block validation
-	if err = ValidateHeader(sm.Pow, header, parent.Header(), false, false); err != nil {
-		return
-	}
-
-	// There can be at most two uncles
-	if len(uncles) > 2 {
-		return nil, nil, ValidationError("Block can only contain maximum 2 uncles (contained %v)", len(uncles))
-	}
-
-	receipts, err = sm.TransitionState(state, parent, block, false)
-	if err != nil {
-		return
-	}
-
-	// Validate the received block's bloom with the one derived from the generated receipts.
-	// For valid blocks this should always validate to true.
-	rbloom := types.CreateBloom(receipts)
-	if rbloom != header.Bloom {
-		err = fmt.Errorf("unable to replicate block's bloom=%x", rbloom)
-		return
-	}
-
-	// The transactions Trie's root (R = (Tr [[i, RLP(T1)], [i, RLP(T2)], ... [n, RLP(Tn)]]))
-	// can be used by light clients to make sure they've received the correct Txs
-	txSha := types.DeriveSha(txs)
-	if txSha != header.TxHash {
-		err = fmt.Errorf("invalid transaction root hash. received=%x calculated=%x", header.TxHash, txSha)
-		return
-	}
-
-	// Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]]))
-	receiptSha := types.DeriveSha(receipts)
-	if receiptSha != header.ReceiptHash {
-		err = fmt.Errorf("invalid receipt root hash. received=%x calculated=%x", header.ReceiptHash, receiptSha)
-		return
-	}
-
-	// Verify UncleHash before running other uncle validations
-	unclesSha := types.CalcUncleHash(uncles)
-	if unclesSha != header.UncleHash {
-		err = fmt.Errorf("invalid uncles root hash. received=%x calculated=%x", header.UncleHash, unclesSha)
-		return
-	}
-
-	// Verify uncles
-	if err = sm.VerifyUncles(state, block, parent); err != nil {
-		return
-	}
-	// Accumulate static rewards; block reward, uncle's and uncle inclusion.
-	AccumulateRewards(state, header, uncles)
-
-	// Commit state objects/accounts to a database batch and calculate
-	// the state root. The database is not modified if the root
-	// doesn't match.
-	root, batch := state.CommitBatch()
-	if header.Root != root {
-		return nil, nil, fmt.Errorf("invalid merkle root: header=%x computed=%x", header.Root, root)
-	}
-
-	// Execute the database writes.
-	batch.Write()
-
-	return state.Logs(), receipts, nil
-}
-
-var (
-	big8  = big.NewInt(8)
-	big32 = big.NewInt(32)
-)
-
-// AccumulateRewards credits the coinbase of the given block with the
-// mining reward. The total reward consists of the static block reward
-// and rewards for included uncles. The coinbase of each uncle block is
-// also rewarded.
-func AccumulateRewards(statedb *state.StateDB, header *types.Header, uncles []*types.Header) {
-	reward := new(big.Int).Set(BlockReward)
-	r := new(big.Int)
-	for _, uncle := range uncles {
-		r.Add(uncle.Number, big8)
-		r.Sub(r, header.Number)
-		r.Mul(r, BlockReward)
-		r.Div(r, big8)
-		statedb.AddBalance(uncle.Coinbase, r)
-
-		r.Div(BlockReward, big32)
-		reward.Add(reward, r)
-	}
-	statedb.AddBalance(header.Coinbase, reward)
-}
-
-func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *types.Block) error {
-	uncles := set.New()
-	ancestors := make(map[common.Hash]*types.Block)
-	for _, ancestor := range sm.bc.GetBlocksFromHash(block.ParentHash(), 7) {
-		ancestors[ancestor.Hash()] = ancestor
-		// Include ancestors uncles in the uncle set. Uncles must be unique.
-		for _, uncle := range ancestor.Uncles() {
-			uncles.Add(uncle.Hash())
-		}
-	}
-	ancestors[block.Hash()] = block
-	uncles.Add(block.Hash())
-
-	for i, uncle := range block.Uncles() {
-		hash := uncle.Hash()
-		if uncles.Has(hash) {
-			// Error not unique
-			return UncleError("uncle[%d](%x) not unique", i, hash[:4])
-		}
-		uncles.Add(hash)
-
-		if ancestors[hash] != nil {
-			branch := fmt.Sprintf("  O - %x\n  |\n", block.Hash())
-			for h := range ancestors {
-				branch += fmt.Sprintf("  O - %x\n  |\n", h)
-			}
-			glog.Infoln(branch)
-			return UncleError("uncle[%d](%x) is ancestor", i, hash[:4])
-		}
-
-		if ancestors[uncle.ParentHash] == nil || uncle.ParentHash == parent.Hash() {
-			return UncleError("uncle[%d](%x)'s parent is not ancestor (%x)", i, hash[:4], uncle.ParentHash[0:4])
-		}
-
-		if err := ValidateHeader(sm.Pow, uncle, ancestors[uncle.ParentHash].Header(), true, true); err != nil {
-			return ValidationError(fmt.Sprintf("uncle[%d](%x) header invalid: %v", i, hash[:4], err))
-		}
-	}
-
-	return nil
-}
-
-// GetBlockReceipts returns the receipts beloniging to the block hash
-func (sm *BlockProcessor) GetBlockReceipts(bhash common.Hash) types.Receipts {
-	if block := sm.BlockChain().GetBlock(bhash); block != nil {
-		return GetBlockReceipts(sm.chainDb, block.Hash())
-	}
-
-	return nil
-}
-
-// GetLogs returns the logs of the given block. This method is using a two step approach
-// where it tries to get it from the (updated) method which gets them from the receipts or
-// the depricated way by re-processing the block.
-func (sm *BlockProcessor) GetLogs(block *types.Block) (logs vm.Logs, err error) {
-	receipts := GetBlockReceipts(sm.chainDb, block.Hash())
-	// coalesce logs
-	for _, receipt := range receipts {
-		logs = append(logs, receipt.Logs...)
-	}
-	return logs, nil
-}
-
-// ValidateHeader verifies the validity of a header, relying on the database and
-// POW behind the block processor.
-func (sm *BlockProcessor) ValidateHeader(header *types.Header, checkPow, uncle bool) error {
-	// Short circuit if the header's already known or its parent missing
-	if sm.bc.HasHeader(header.Hash()) {
-		return nil
-	}
-	if parent := sm.bc.GetHeader(header.ParentHash); parent == nil {
-		return ParentError(header.ParentHash)
-	} else {
-		return ValidateHeader(sm.Pow, header, parent, checkPow, uncle)
-	}
-}
-
-// ValidateHeaderWithParent verifies the validity of a header, relying on the database and
-// POW behind the block processor.
-func (sm *BlockProcessor) ValidateHeaderWithParent(header, parent *types.Header, checkPow, uncle bool) error {
-	if sm.bc.HasHeader(header.Hash()) {
-		return nil
-	}
-	return ValidateHeader(sm.Pow, header, parent, checkPow, uncle)
-}
-
-// See YP section 4.3.4. "Block Header Validity"
-// Validates a header. Returns an error if the header is invalid.
-func ValidateHeader(pow pow.PoW, header *types.Header, parent *types.Header, checkPow, uncle bool) error {
-	if big.NewInt(int64(len(header.Extra))).Cmp(params.MaximumExtraDataSize) == 1 {
-		return fmt.Errorf("Header extra data too long (%d)", len(header.Extra))
-	}
-	if uncle {
-		if header.Time.Cmp(common.MaxBig) == 1 {
-			return BlockTSTooBigErr
-		}
-	} else {
-		if header.Time.Cmp(big.NewInt(time.Now().Unix())) == 1 {
-			return BlockFutureErr
-		}
-	}
-	if header.Time.Cmp(parent.Time) != 1 {
-		return BlockEqualTSErr
-	}
-
-	expd := CalcDifficulty(header.Time.Uint64(), parent.Time.Uint64(), parent.Number, parent.Difficulty)
-	if expd.Cmp(header.Difficulty) != 0 {
-		return fmt.Errorf("Difficulty check failed for header %v, %v", header.Difficulty, expd)
-	}
-
-	a := new(big.Int).Set(parent.GasLimit)
-	a = a.Sub(a, header.GasLimit)
-	a.Abs(a)
-	b := new(big.Int).Set(parent.GasLimit)
-	b = b.Div(b, params.GasLimitBoundDivisor)
-	if !(a.Cmp(b) < 0) || (header.GasLimit.Cmp(params.MinGasLimit) == -1) {
-		return fmt.Errorf("GasLimit check failed for header %v (%v > %v)", header.GasLimit, a, b)
-	}
-
-	num := new(big.Int).Set(parent.Number)
-	num.Sub(header.Number, num)
-	if num.Cmp(big.NewInt(1)) != 0 {
-		return BlockNumberErr
-	}
-
-	if checkPow {
-		// Verify the nonce of the header. Return an error if it's not valid
-		if !pow.Verify(types.NewBlockWithHeader(header)) {
-			return &BlockNonceErr{Hash: header.Hash(), Number: header.Number, Nonce: header.Nonce.Uint64()}
-		}
-	}
-	return nil
-}

+ 243 - 0
core/block_validator.go

@@ -0,0 +1,243 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package core
+
+import (
+	"fmt"
+	"math/big"
+	"time"
+
+	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/core/state"
+	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/logger/glog"
+	"github.com/ethereum/go-ethereum/params"
+	"github.com/ethereum/go-ethereum/pow"
+	"gopkg.in/fatih/set.v0"
+)
+
+// BlockValidator is responsible for validating block headers, uncles and
+// processed state.
+//
+// BlockValidator implements Validator.
+type BlockValidator struct {
+	bc  *BlockChain // Canonical block chain
+	Pow pow.PoW     // Proof of work used for validating
+}
+
+// NewBlockValidator returns a new block validator which is safe for re-use
+func NewBlockValidator(blockchain *BlockChain, pow pow.PoW) *BlockValidator {
+	validator := &BlockValidator{
+		Pow: pow,
+		bc:  blockchain,
+	}
+	return validator
+}
+
+// ValidateBlock validates the given block's header and uncles and verifies the
+// the block header's transaction and uncle roots.
+//
+// ValidateBlock does not validate the header's pow. The pow work validated
+// seperately so we can process them in paralel.
+//
+// ValidateBlock also validates and makes sure that any previous state (or present)
+// state that might or might not be present is checked to make sure that fast
+// sync has done it's job proper. This prevents the block validator form accepting
+// false positives where a header is present but the state is not.
+func (v *BlockValidator) ValidateBlock(block *types.Block) error {
+	if v.bc.HasBlock(block.Hash()) {
+		if _, err := state.New(block.Root(), v.bc.chainDb); err == nil {
+			return &KnownBlockError{block.Number(), block.Hash()}
+		}
+	}
+	parent := v.bc.GetBlock(block.ParentHash())
+	if parent == nil {
+		return ParentError(block.ParentHash())
+	}
+	if _, err := state.New(parent.Root(), v.bc.chainDb); err != nil {
+		return ParentError(block.ParentHash())
+	}
+
+	header := block.Header()
+	// validate the block header
+	if err := ValidateHeader(v.Pow, header, parent.Header(), false, false); err != nil {
+		return err
+	}
+	// verify the uncles are correctly rewarded
+	if err := v.VerifyUncles(block, parent); err != nil {
+		return err
+	}
+
+	// Verify UncleHash before running other uncle validations
+	unclesSha := types.CalcUncleHash(block.Uncles())
+	if unclesSha != header.UncleHash {
+		return fmt.Errorf("invalid uncles root hash. received=%x calculated=%x", header.UncleHash, unclesSha)
+	}
+
+	// The transactions Trie's root (R = (Tr [[i, RLP(T1)], [i, RLP(T2)], ... [n, RLP(Tn)]]))
+	// can be used by light clients to make sure they've received the correct Txs
+	txSha := types.DeriveSha(block.Transactions())
+	if txSha != header.TxHash {
+		return fmt.Errorf("invalid transaction root hash. received=%x calculated=%x", header.TxHash, txSha)
+	}
+
+	return nil
+}
+
+// ValidateState validates the various changes that happen after a state
+// transition, such as amount of used gas, the receipt roots and the state root
+// itself. ValidateState returns a database batch if the validation was a succes
+// otherwise nil and an error is returned.
+func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas *big.Int) (err error) {
+	header := block.Header()
+	if block.GasUsed().Cmp(usedGas) != 0 {
+		return ValidationError(fmt.Sprintf("gas used error (%v / %v)", block.GasUsed(), usedGas))
+	}
+	// Validate the received block's bloom with the one derived from the generated receipts.
+	// For valid blocks this should always validate to true.
+	rbloom := types.CreateBloom(receipts)
+	if rbloom != header.Bloom {
+		return fmt.Errorf("unable to replicate block's bloom=%x", rbloom)
+	}
+	// Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]]))
+	receiptSha := types.DeriveSha(receipts)
+	if receiptSha != header.ReceiptHash {
+		return fmt.Errorf("invalid receipt root hash. received=%x calculated=%x", header.ReceiptHash, receiptSha)
+	}
+	// Validate the state root against the received state root and throw
+	// an error if they don't match.
+	if root := statedb.IntermediateRoot(); header.Root != root {
+		return fmt.Errorf("invalid merkle root: header=%x computed=%x", header.Root, root)
+	}
+	return nil
+}
+
+// VerifyUncles verifies the given block's uncles and applies the Ethereum
+// consensus rules to the various block headers included; it will return an
+// error if any of the included uncle headers were invalid. It returns an error
+// if the validation failed.
+func (v *BlockValidator) VerifyUncles(block, parent *types.Block) error {
+	// validate that there at most 2 uncles included in this block
+	if len(block.Uncles()) > 2 {
+		return ValidationError("Block can only contain maximum 2 uncles (contained %v)", len(block.Uncles()))
+	}
+
+	uncles := set.New()
+	ancestors := make(map[common.Hash]*types.Block)
+	for _, ancestor := range v.bc.GetBlocksFromHash(block.ParentHash(), 7) {
+		ancestors[ancestor.Hash()] = ancestor
+		// Include ancestors uncles in the uncle set. Uncles must be unique.
+		for _, uncle := range ancestor.Uncles() {
+			uncles.Add(uncle.Hash())
+		}
+	}
+	ancestors[block.Hash()] = block
+	uncles.Add(block.Hash())
+
+	for i, uncle := range block.Uncles() {
+		hash := uncle.Hash()
+		if uncles.Has(hash) {
+			// Error not unique
+			return UncleError("uncle[%d](%x) not unique", i, hash[:4])
+		}
+		uncles.Add(hash)
+
+		if ancestors[hash] != nil {
+			branch := fmt.Sprintf("  O - %x\n  |\n", block.Hash())
+			for h := range ancestors {
+				branch += fmt.Sprintf("  O - %x\n  |\n", h)
+			}
+			glog.Infoln(branch)
+			return UncleError("uncle[%d](%x) is ancestor", i, hash[:4])
+		}
+
+		if ancestors[uncle.ParentHash] == nil || uncle.ParentHash == parent.Hash() {
+			return UncleError("uncle[%d](%x)'s parent is not ancestor (%x)", i, hash[:4], uncle.ParentHash[0:4])
+		}
+
+		if err := ValidateHeader(v.Pow, uncle, ancestors[uncle.ParentHash].Header(), true, true); err != nil {
+			return ValidationError(fmt.Sprintf("uncle[%d](%x) header invalid: %v", i, hash[:4], err))
+		}
+	}
+
+	return nil
+}
+
+// ValidateHeader validates the given header and, depending on the pow arg,
+// checks the proof of work of the given header. Returns an error if the
+// validation failed.
+func (v *BlockValidator) ValidateHeader(header, parent *types.Header, checkPow bool) error {
+	// Short circuit if the parent is missing.
+	if parent == nil {
+		return ParentError(header.ParentHash)
+	}
+	// Short circuit if the header's already known or its parent missing
+	if v.bc.HasHeader(header.Hash()) {
+		return nil
+	}
+	return ValidateHeader(v.Pow, header, parent, checkPow, false)
+}
+
+// Validates a header. Returns an error if the header is invalid.
+//
+// See YP section 4.3.4. "Block Header Validity"
+func ValidateHeader(pow pow.PoW, header *types.Header, parent *types.Header, checkPow, uncle bool) error {
+	if big.NewInt(int64(len(header.Extra))).Cmp(params.MaximumExtraDataSize) == 1 {
+		return fmt.Errorf("Header extra data too long (%d)", len(header.Extra))
+	}
+
+	if uncle {
+		if header.Time.Cmp(common.MaxBig) == 1 {
+			return BlockTSTooBigErr
+		}
+	} else {
+		if header.Time.Cmp(big.NewInt(time.Now().Unix())) == 1 {
+			return BlockFutureErr
+		}
+	}
+	if header.Time.Cmp(parent.Time) != 1 {
+		return BlockEqualTSErr
+	}
+
+	expd := CalcDifficulty(header.Time.Uint64(), parent.Time.Uint64(), parent.Number, parent.Difficulty)
+	if expd.Cmp(header.Difficulty) != 0 {
+		return fmt.Errorf("Difficulty check failed for header %v, %v", header.Difficulty, expd)
+	}
+
+	a := new(big.Int).Set(parent.GasLimit)
+	a = a.Sub(a, header.GasLimit)
+	a.Abs(a)
+	b := new(big.Int).Set(parent.GasLimit)
+	b = b.Div(b, params.GasLimitBoundDivisor)
+	if !(a.Cmp(b) < 0) || (header.GasLimit.Cmp(params.MinGasLimit) == -1) {
+		return fmt.Errorf("GasLimit check failed for header %v (%v > %v)", header.GasLimit, a, b)
+	}
+
+	num := new(big.Int).Set(parent.Number)
+	num.Sub(header.Number, num)
+	if num.Cmp(big.NewInt(1)) != 0 {
+		return BlockNumberErr
+	}
+
+	if checkPow {
+		// Verify the nonce of the header. Return an error if it's not valid
+		if !pow.Verify(types.NewBlockWithHeader(header)) {
+			return &BlockNonceErr{header.Number, header.Hash(), header.Nonce.Uint64()}
+		}
+	}
+	return nil
+}

+ 2 - 2
core/block_processor_test.go → core/block_validator_test.go

@@ -30,7 +30,7 @@ import (
 	"github.com/ethereum/go-ethereum/pow/ezp"
 )
 
-func proc() (*BlockProcessor, *BlockChain) {
+func proc() (Validator, *BlockChain) {
 	db, _ := ethdb.NewMemDatabase()
 	var mux event.TypeMux
 
@@ -39,7 +39,7 @@ func proc() (*BlockProcessor, *BlockChain) {
 	if err != nil {
 		fmt.Println(err)
 	}
-	return NewBlockProcessor(db, ezp.New(), blockchain, &mux), blockchain
+	return blockchain.validator, blockchain
 }
 
 func TestNumber(t *testing.T) {

+ 114 - 20
core/blockchain.go

@@ -33,6 +33,7 @@ import (
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/event"
@@ -61,17 +62,34 @@ const (
 	blockCacheLimit     = 256
 	maxFutureBlocks     = 256
 	maxTimeFutureBlocks = 30
+	// must be bumped when consensus algorithm is changed, this forces the upgradedb
+	// command to be run (forces the blocks to be imported again using the new algorithm)
+	BlockChainVersion = 3
 )
 
+// BlockChain represents the canonical chain given a database with a genesis
+// block. The Blockchain manages chain imports, reverts, chain reorganisations.
+//
+// Importing blocks in to the block chain happens according to the set of rules
+// defined by the two stage Validator. Processing of blocks is done using the
+// Processor which processes the included transaction. The validation of the state
+// is done in the second part of the Validator. Failing results in aborting of
+// the import.
+//
+// The BlockChain also helps in returning blocks from **any** chain included
+// in the database as well as blocks that represents the canonical chain. It's
+// important to note that GetBlock can return any block and does not need to be
+// included in the canonical one where as GetBlockByNumber always represents the
+// canonical chain.
 type BlockChain struct {
 	chainDb      ethdb.Database
-	processor    types.BlockProcessor
 	eventMux     *event.TypeMux
 	genesisBlock *types.Block
 	// Last known total difficulty
 	mu      sync.RWMutex
 	chainmu sync.RWMutex
 	tsmu    sync.RWMutex
+	procmu  sync.RWMutex
 
 	checkpoint       int           // checkpoint counts towards the new checkpoint
 	currentHeader    *types.Header // Current head of the header chain (may be above the block chain!)
@@ -91,10 +109,15 @@ type BlockChain struct {
 	procInterrupt int32 // interrupt signaler for block processing
 	wg            sync.WaitGroup
 
-	pow  pow.PoW
-	rand *mrand.Rand
+	pow       pow.PoW
+	rand      *mrand.Rand
+	processor Processor
+	validator Validator
 }
 
+// NewBlockChain returns a fully initialised block chain using information
+// available in the database. It initialiser the default Ethereum Validator and
+// Processor.
 func NewBlockChain(chainDb ethdb.Database, pow pow.PoW, mux *event.TypeMux) (*BlockChain, error) {
 	headerCache, _ := lru.New(headerCacheLimit)
 	bodyCache, _ := lru.New(bodyCacheLimit)
@@ -121,6 +144,8 @@ func NewBlockChain(chainDb ethdb.Database, pow pow.PoW, mux *event.TypeMux) (*Bl
 		return nil, err
 	}
 	bc.rand = mrand.New(mrand.NewSource(seed.Int64()))
+	bc.SetValidator(NewBlockValidator(bc, pow))
+	bc.SetProcessor(NewStateProcessor(bc))
 
 	bc.genesisBlock = bc.GetBlockByNumber(0)
 	if bc.genesisBlock == nil {
@@ -292,6 +317,7 @@ func (self *BlockChain) FastSyncCommitHead(hash common.Hash) error {
 	return nil
 }
 
+// GasLimit returns the gas limit of the current HEAD block.
 func (self *BlockChain) GasLimit() *big.Int {
 	self.mu.RLock()
 	defer self.mu.RUnlock()
@@ -299,6 +325,7 @@ func (self *BlockChain) GasLimit() *big.Int {
 	return self.currentBlock.GasLimit()
 }
 
+// LastBlockHash return the hash of the HEAD block.
 func (self *BlockChain) LastBlockHash() common.Hash {
 	self.mu.RLock()
 	defer self.mu.RUnlock()
@@ -333,6 +360,8 @@ func (self *BlockChain) CurrentFastBlock() *types.Block {
 	return self.currentFastBlock
 }
 
+// Status returns status information about the current chain such as the HEAD Td,
+// the HEAD hash and the hash of the genesis block.
 func (self *BlockChain) Status() (td *big.Int, currentBlock common.Hash, genesisBlock common.Hash) {
 	self.mu.RLock()
 	defer self.mu.RUnlock()
@@ -340,10 +369,38 @@ func (self *BlockChain) Status() (td *big.Int, currentBlock common.Hash, genesis
 	return self.GetTd(self.currentBlock.Hash()), self.currentBlock.Hash(), self.genesisBlock.Hash()
 }
 
-func (self *BlockChain) SetProcessor(proc types.BlockProcessor) {
-	self.processor = proc
+// SetProcessor sets the processor required for making state modifications.
+func (self *BlockChain) SetProcessor(processor Processor) {
+	self.procmu.Lock()
+	defer self.procmu.Unlock()
+	self.processor = processor
+}
+
+// SetValidator sets the validator which is used to validate incoming blocks.
+func (self *BlockChain) SetValidator(validator Validator) {
+	self.procmu.Lock()
+	defer self.procmu.Unlock()
+	self.validator = validator
 }
 
+// Validator returns the current validator.
+func (self *BlockChain) Validator() Validator {
+	self.procmu.RLock()
+	defer self.procmu.RUnlock()
+	return self.validator
+}
+
+// Processor returns the current processor.
+func (self *BlockChain) Processor() Processor {
+	self.procmu.RLock()
+	defer self.procmu.RUnlock()
+	return self.processor
+}
+
+// AuxValidator returns the auxiliary validator (Proof of work atm)
+func (self *BlockChain) AuxValidator() pow.PoW { return self.pow }
+
+// State returns a new mutable state based on the current HEAD block.
 func (self *BlockChain) State() (*state.StateDB, error) {
 	return state.New(self.CurrentBlock().Root(), self.chainDb)
 }
@@ -606,6 +663,8 @@ func (self *BlockChain) GetUnclesInChain(block *types.Block, length int) []*type
 	return uncles
 }
 
+// Stop stops the blockchain service. If any imports are currently in progress
+// it will abort them using the procInterrupt.
 func (bc *BlockChain) Stop() {
 	if !atomic.CompareAndSwapInt32(&bc.running, 0, 1) {
 		return
@@ -758,9 +817,9 @@ func (self *BlockChain) InsertHeaderChain(chain []*types.Header, checkFreq int)
 
 			var err error
 			if index == 0 {
-				err = self.processor.ValidateHeader(header, checkPow, false)
+				err = self.Validator().ValidateHeader(header, self.GetHeader(header.ParentHash), checkPow)
 			} else {
-				err = self.processor.ValidateHeaderWithParent(header, chain[index-1], checkPow, false)
+				err = self.Validator().ValidateHeader(header, chain[index-1], checkPow)
 			}
 			if err != nil {
 				errs[index] = err
@@ -1025,9 +1084,10 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
 	// faster than direct delivery and requires much less mutex
 	// acquiring.
 	var (
-		stats  struct{ queued, processed, ignored int }
-		events = make([]interface{}, 0, len(chain))
-		tstart = time.Now()
+		stats         struct{ queued, processed, ignored int }
+		events        = make([]interface{}, 0, len(chain))
+		coalescedLogs vm.Logs
+		tstart        = time.Now()
 
 		nonceChecked = make([]bool, len(chain))
 	)
@@ -1057,12 +1117,12 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
 
 		if BadHashes[block.Hash()] {
 			err := BadHashError(block.Hash())
-			blockErr(block, err)
+			reportBlock(block, err)
 			return i, err
 		}
-		// Call in to the block processor and check for errors. It's likely that if one block fails
-		// all others will fail too (unless a known block is returned).
-		logs, receipts, err := self.processor.Process(block)
+		// Stage 1 validation of the block using the chain's validator
+		// interface.
+		err := self.Validator().ValidateBlock(block)
 		if err != nil {
 			if IsKnownBlockErr(err) {
 				stats.ignored++
@@ -1089,14 +1149,41 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
 				continue
 			}
 
-			blockErr(block, err)
+			reportBlock(block, err)
 
-			go ReportBlock(block, err)
+			return i, err
+		}
 
+		// Create a new statedb using the parent block and report an
+		// error if it fails.
+		statedb, err := state.New(self.GetBlock(block.ParentHash()).Root(), self.chainDb)
+		if err != nil {
+			reportBlock(block, err)
 			return i, err
 		}
+		// Process block using the parent state as reference point.
+		receipts, logs, usedGas, err := self.processor.Process(block, statedb)
+		if err != nil {
+			reportBlock(block, err)
+			return i, err
+		}
+		// Validate the state using the default validator
+		err = self.Validator().ValidateState(block, self.GetBlock(block.ParentHash()), statedb, receipts, usedGas)
+		if err != nil {
+			reportBlock(block, err)
+			return i, err
+		}
+		// Write state changes to database
+		_, err = statedb.Commit()
+		if err != nil {
+			return i, err
+		}
+
+		// coalesce logs for later processing
+		coalescedLogs = append(coalescedLogs, logs...)
+
 		if err := PutBlockReceipts(self.chainDb, block.Hash(), receipts); err != nil {
-			glog.V(logger.Warn).Infoln("error writing block receipts:", err)
+			return i, err
 		}
 
 		txcount += len(block.Transactions())
@@ -1105,6 +1192,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
 		if err != nil {
 			return i, err
 		}
+
 		switch status {
 		case CanonStatTy:
 			if glog.V(logger.Debug) {
@@ -1141,7 +1229,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
 		start, end := chain[0], chain[len(chain)-1]
 		glog.Infof("imported %d block(s) (%d queued %d ignored) including %d txs in %v. #%v [%x / %x]\n", stats.processed, stats.queued, stats.ignored, txcount, tend, end.Number(), start.Hash().Bytes()[:4], end.Hash().Bytes()[:4])
 	}
-	go self.postChainEvents(events)
+	go self.postChainEvents(events, coalescedLogs)
 
 	return 0, nil
 }
@@ -1239,7 +1327,9 @@ func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
 
 // postChainEvents iterates over the events generated by a chain insertion and
 // posts them into the event mux.
-func (self *BlockChain) postChainEvents(events []interface{}) {
+func (self *BlockChain) postChainEvents(events []interface{}, logs vm.Logs) {
+	// post event logs for further processing
+	self.eventMux.Post(logs)
 	for _, event := range events {
 		if event, ok := event.(ChainEvent); ok {
 			// We need some control over the mining operation. Acquiring locks and waiting for the miner to create new block takes too long
@@ -1265,9 +1355,13 @@ func (self *BlockChain) update() {
 	}
 }
 
-func blockErr(block *types.Block, err error) {
+// reportBlock reports the given block and error using the canonical block
+// reporting tool. Reporting the block to the service is handled in a separate
+// goroutine.
+func reportBlock(block *types.Block, err error) {
 	if glog.V(logger.Error) {
 		glog.Errorf("Bad block #%v (%s)\n", block.Number(), block.Hash().Hex())
 		glog.Errorf("    %v", err)
 	}
+	go ReportBlock(block, err)
 }

+ 75 - 64
core/blockchain_test.go

@@ -28,6 +28,7 @@ import (
 
 	"github.com/ethereum/ethash"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/crypto"
@@ -53,31 +54,29 @@ func theBlockChain(db ethdb.Database, t *testing.T) *BlockChain {
 	WriteTestNetGenesisBlock(db, 0)
 	blockchain, err := NewBlockChain(db, thePow(), &eventMux)
 	if err != nil {
-		t.Error("failed creating chainmanager:", err)
+		t.Error("failed creating blockchain:", err)
 		t.FailNow()
 		return nil
 	}
-	blockMan := NewBlockProcessor(db, nil, blockchain, &eventMux)
-	blockchain.SetProcessor(blockMan)
 
 	return blockchain
 }
 
 // Test fork of length N starting from block i
-func testFork(t *testing.T, processor *BlockProcessor, i, n int, full bool, comparator func(td1, td2 *big.Int)) {
+func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, comparator func(td1, td2 *big.Int)) {
 	// Copy old chain up to #i into a new db
-	db, processor2, err := newCanonical(i, full)
+	db, blockchain2, err := newCanonical(i, full)
 	if err != nil {
 		t.Fatal("could not make new canonical in testFork", err)
 	}
 	// Assert the chains have the same header/block at #i
 	var hash1, hash2 common.Hash
 	if full {
-		hash1 = processor.bc.GetBlockByNumber(uint64(i)).Hash()
-		hash2 = processor2.bc.GetBlockByNumber(uint64(i)).Hash()
+		hash1 = blockchain.GetBlockByNumber(uint64(i)).Hash()
+		hash2 = blockchain2.GetBlockByNumber(uint64(i)).Hash()
 	} else {
-		hash1 = processor.bc.GetHeaderByNumber(uint64(i)).Hash()
-		hash2 = processor2.bc.GetHeaderByNumber(uint64(i)).Hash()
+		hash1 = blockchain.GetHeaderByNumber(uint64(i)).Hash()
+		hash2 = blockchain2.GetHeaderByNumber(uint64(i)).Hash()
 	}
 	if hash1 != hash2 {
 		t.Errorf("chain content mismatch at %d: have hash %v, want hash %v", i, hash2, hash1)
@@ -88,13 +87,13 @@ func testFork(t *testing.T, processor *BlockProcessor, i, n int, full bool, comp
 		headerChainB []*types.Header
 	)
 	if full {
-		blockChainB = makeBlockChain(processor2.bc.CurrentBlock(), n, db, forkSeed)
-		if _, err := processor2.bc.InsertChain(blockChainB); err != nil {
+		blockChainB = makeBlockChain(blockchain2.CurrentBlock(), n, db, forkSeed)
+		if _, err := blockchain2.InsertChain(blockChainB); err != nil {
 			t.Fatalf("failed to insert forking chain: %v", err)
 		}
 	} else {
-		headerChainB = makeHeaderChain(processor2.bc.CurrentHeader(), n, db, forkSeed)
-		if _, err := processor2.bc.InsertHeaderChain(headerChainB, 1); err != nil {
+		headerChainB = makeHeaderChain(blockchain2.CurrentHeader(), n, db, forkSeed)
+		if _, err := blockchain2.InsertHeaderChain(headerChainB, 1); err != nil {
 			t.Fatalf("failed to insert forking chain: %v", err)
 		}
 	}
@@ -102,17 +101,17 @@ func testFork(t *testing.T, processor *BlockProcessor, i, n int, full bool, comp
 	var tdPre, tdPost *big.Int
 
 	if full {
-		tdPre = processor.bc.GetTd(processor.bc.CurrentBlock().Hash())
-		if err := testBlockChainImport(blockChainB, processor); err != nil {
+		tdPre = blockchain.GetTd(blockchain.CurrentBlock().Hash())
+		if err := testBlockChainImport(blockChainB, blockchain); err != nil {
 			t.Fatalf("failed to import forked block chain: %v", err)
 		}
-		tdPost = processor.bc.GetTd(blockChainB[len(blockChainB)-1].Hash())
+		tdPost = blockchain.GetTd(blockChainB[len(blockChainB)-1].Hash())
 	} else {
-		tdPre = processor.bc.GetTd(processor.bc.CurrentHeader().Hash())
-		if err := testHeaderChainImport(headerChainB, processor); err != nil {
+		tdPre = blockchain.GetTd(blockchain.CurrentHeader().Hash())
+		if err := testHeaderChainImport(headerChainB, blockchain); err != nil {
 			t.Fatalf("failed to import forked header chain: %v", err)
 		}
-		tdPost = processor.bc.GetTd(headerChainB[len(headerChainB)-1].Hash())
+		tdPost = blockchain.GetTd(headerChainB[len(headerChainB)-1].Hash())
 	}
 	// Compare the total difficulties of the chains
 	comparator(tdPre, tdPost)
@@ -127,37 +126,52 @@ func printChain(bc *BlockChain) {
 
 // testBlockChainImport tries to process a chain of blocks, writing them into
 // the database if successful.
-func testBlockChainImport(chain []*types.Block, processor *BlockProcessor) error {
+func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
 	for _, block := range chain {
 		// Try and process the block
-		if _, _, err := processor.Process(block); err != nil {
+		err := blockchain.Validator().ValidateBlock(block)
+		if err != nil {
 			if IsKnownBlockErr(err) {
 				continue
 			}
 			return err
 		}
-		// Manually insert the block into the database, but don't reorganize (allows subsequent testing)
-		processor.bc.mu.Lock()
-		WriteTd(processor.chainDb, block.Hash(), new(big.Int).Add(block.Difficulty(), processor.bc.GetTd(block.ParentHash())))
-		WriteBlock(processor.chainDb, block)
-		processor.bc.mu.Unlock()
+		statedb, err := state.New(blockchain.GetBlock(block.ParentHash()).Root(), blockchain.chainDb)
+		if err != nil {
+			return err
+		}
+		receipts, _, usedGas, err := blockchain.Processor().Process(block, statedb)
+		if err != nil {
+			reportBlock(block, err)
+			return err
+		}
+		err = blockchain.Validator().ValidateState(block, blockchain.GetBlock(block.ParentHash()), statedb, receipts, usedGas)
+		if err != nil {
+			reportBlock(block, err)
+			return err
+		}
+		blockchain.mu.Lock()
+		WriteTd(blockchain.chainDb, block.Hash(), new(big.Int).Add(block.Difficulty(), blockchain.GetTd(block.ParentHash())))
+		WriteBlock(blockchain.chainDb, block)
+		statedb.Commit()
+		blockchain.mu.Unlock()
 	}
 	return nil
 }
 
 // testHeaderChainImport tries to process a chain of header, writing them into
 // the database if successful.
-func testHeaderChainImport(chain []*types.Header, processor *BlockProcessor) error {
+func testHeaderChainImport(chain []*types.Header, blockchain *BlockChain) error {
 	for _, header := range chain {
 		// Try and validate the header
-		if err := processor.ValidateHeader(header, false, false); err != nil {
+		if err := blockchain.Validator().ValidateHeader(header, blockchain.GetHeader(header.ParentHash), false); err != nil {
 			return err
 		}
 		// Manually insert the header into the database, but don't reorganize (allows subsequent testing)
-		processor.bc.mu.Lock()
-		WriteTd(processor.chainDb, header.Hash(), new(big.Int).Add(header.Difficulty, processor.bc.GetTd(header.ParentHash)))
-		WriteHeader(processor.chainDb, header)
-		processor.bc.mu.Unlock()
+		blockchain.mu.Lock()
+		WriteTd(blockchain.chainDb, header.Hash(), new(big.Int).Add(header.Difficulty, blockchain.GetTd(header.ParentHash)))
+		WriteHeader(blockchain.chainDb, header)
+		blockchain.mu.Unlock()
 	}
 	return nil
 }
@@ -313,19 +327,19 @@ func TestBrokenBlockChain(t *testing.T)  { testBrokenChain(t, true) }
 
 func testBrokenChain(t *testing.T, full bool) {
 	// Make chain starting from genesis
-	db, processor, err := newCanonical(10, full)
+	db, blockchain, err := newCanonical(10, full)
 	if err != nil {
 		t.Fatalf("failed to make new canonical chain: %v", err)
 	}
 	// Create a forked chain, and try to insert with a missing link
 	if full {
-		chain := makeBlockChain(processor.bc.CurrentBlock(), 5, db, forkSeed)[1:]
-		if err := testBlockChainImport(chain, processor); err == nil {
+		chain := makeBlockChain(blockchain.CurrentBlock(), 5, db, forkSeed)[1:]
+		if err := testBlockChainImport(chain, blockchain); err == nil {
 			t.Errorf("broken block chain not reported")
 		}
 	} else {
-		chain := makeHeaderChain(processor.bc.CurrentHeader(), 5, db, forkSeed)[1:]
-		if err := testHeaderChainImport(chain, processor); err == nil {
+		chain := makeHeaderChain(blockchain.CurrentHeader(), 5, db, forkSeed)[1:]
+		if err := testHeaderChainImport(chain, blockchain); err == nil {
 			t.Errorf("broken header chain not reported")
 		}
 	}
@@ -415,9 +429,14 @@ func TestChainMultipleInsertions(t *testing.T) {
 
 type bproc struct{}
 
-func (bproc) Process(*types.Block) (vm.Logs, types.Receipts, error)                   { return nil, nil, nil }
-func (bproc) ValidateHeader(*types.Header, bool, bool) error                          { return nil }
-func (bproc) ValidateHeaderWithParent(*types.Header, *types.Header, bool, bool) error { return nil }
+func (bproc) ValidateBlock(*types.Block) error                        { return nil }
+func (bproc) ValidateHeader(*types.Header, *types.Header, bool) error { return nil }
+func (bproc) ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error {
+	return nil
+}
+func (bproc) Process(block *types.Block, statedb *state.StateDB) (types.Receipts, vm.Logs, *big.Int, error) {
+	return nil, nil, nil, nil
+}
 
 func makeHeaderChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Header {
 	blocks := makeBlockChainWithDiff(genesis, d, seed)
@@ -459,7 +478,8 @@ func chm(genesis *types.Block, db ethdb.Database) *BlockChain {
 	bc.tdCache, _ = lru.New(100)
 	bc.blockCache, _ = lru.New(100)
 	bc.futureBlocks, _ = lru.New(100)
-	bc.processor = bproc{}
+	bc.SetValidator(bproc{})
+	bc.SetProcessor(bproc{})
 	bc.ResetWithGenesisBlock(genesis)
 
 	return bc
@@ -612,12 +632,10 @@ func TestBlocksInsertNonceError(t *testing.T)  { testInsertNonceError(t, true) }
 func testInsertNonceError(t *testing.T, full bool) {
 	for i := 1; i < 25 && !t.Failed(); i++ {
 		// Create a pristine chain and database
-		db, processor, err := newCanonical(0, full)
+		db, blockchain, err := newCanonical(0, full)
 		if err != nil {
 			t.Fatalf("failed to create pristine chain: %v", err)
 		}
-		bc := processor.bc
-
 		// Create and insert a chain with a failing nonce
 		var (
 			failAt   int
@@ -626,34 +644,33 @@ func testInsertNonceError(t *testing.T, full bool) {
 			failHash common.Hash
 		)
 		if full {
-			blocks := makeBlockChain(processor.bc.CurrentBlock(), i, db, 0)
+			blocks := makeBlockChain(blockchain.CurrentBlock(), i, db, 0)
 
 			failAt = rand.Int() % len(blocks)
 			failNum = blocks[failAt].NumberU64()
 			failHash = blocks[failAt].Hash()
 
-			processor.bc.pow = failPow{failNum}
-			processor.Pow = failPow{failNum}
+			blockchain.pow = failPow{failNum}
 
-			failRes, err = processor.bc.InsertChain(blocks)
+			failRes, err = blockchain.InsertChain(blocks)
 		} else {
-			headers := makeHeaderChain(processor.bc.CurrentHeader(), i, db, 0)
+			headers := makeHeaderChain(blockchain.CurrentHeader(), i, db, 0)
 
 			failAt = rand.Int() % len(headers)
 			failNum = headers[failAt].Number.Uint64()
 			failHash = headers[failAt].Hash()
 
-			processor.bc.pow = failPow{failNum}
-			processor.Pow = failPow{failNum}
+			blockchain.pow = failPow{failNum}
+			blockchain.validator = NewBlockValidator(blockchain, failPow{failNum})
 
-			failRes, err = processor.bc.InsertHeaderChain(headers, 1)
+			failRes, err = blockchain.InsertHeaderChain(headers, 1)
 		}
 		// Check that the returned error indicates the nonce failure.
 		if failRes != failAt {
 			t.Errorf("test %d: failure index mismatch: have %d, want %d", i, failRes, failAt)
 		}
 		if !IsBlockNonceErr(err) {
-			t.Fatalf("test %d: error mismatch: have %v, want nonce error", i, err)
+			t.Fatalf("test %d: error mismatch: have %v, want nonce error %T", i, err, err)
 		}
 		nerr := err.(*BlockNonceErr)
 		if nerr.Number.Uint64() != failNum {
@@ -665,11 +682,11 @@ func testInsertNonceError(t *testing.T, full bool) {
 		// Check that all no blocks after the failing block have been inserted.
 		for j := 0; j < i-failAt; j++ {
 			if full {
-				if block := bc.GetBlockByNumber(failNum + uint64(j)); block != nil {
+				if block := blockchain.GetBlockByNumber(failNum + uint64(j)); block != nil {
 					t.Errorf("test %d: invalid block in chain: %v", i, block)
 				}
 			} else {
-				if header := bc.GetHeaderByNumber(failNum + uint64(j)); header != nil {
+				if header := blockchain.GetHeaderByNumber(failNum + uint64(j)); header != nil {
 					t.Errorf("test %d: invalid header in chain: %v", i, header)
 				}
 			}
@@ -711,7 +728,6 @@ func TestFastVsFullChains(t *testing.T) {
 	WriteGenesisBlockForTesting(archiveDb, GenesisAccount{address, funds})
 
 	archive, _ := NewBlockChain(archiveDb, FakePow{}, new(event.TypeMux))
-	archive.SetProcessor(NewBlockProcessor(archiveDb, FakePow{}, archive, new(event.TypeMux)))
 
 	if n, err := archive.InsertChain(blocks); err != nil {
 		t.Fatalf("failed to process block %d: %v", n, err)
@@ -720,7 +736,6 @@ func TestFastVsFullChains(t *testing.T) {
 	fastDb, _ := ethdb.NewMemDatabase()
 	WriteGenesisBlockForTesting(fastDb, GenesisAccount{address, funds})
 	fast, _ := NewBlockChain(fastDb, FakePow{}, new(event.TypeMux))
-	fast.SetProcessor(NewBlockProcessor(fastDb, FakePow{}, fast, new(event.TypeMux)))
 
 	headers := make([]*types.Header, len(blocks))
 	for i, block := range blocks {
@@ -797,7 +812,6 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
 	WriteGenesisBlockForTesting(archiveDb, GenesisAccount{address, funds})
 
 	archive, _ := NewBlockChain(archiveDb, FakePow{}, new(event.TypeMux))
-	archive.SetProcessor(NewBlockProcessor(archiveDb, FakePow{}, archive, new(event.TypeMux)))
 
 	if n, err := archive.InsertChain(blocks); err != nil {
 		t.Fatalf("failed to process block %d: %v", n, err)
@@ -810,7 +824,6 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
 	fastDb, _ := ethdb.NewMemDatabase()
 	WriteGenesisBlockForTesting(fastDb, GenesisAccount{address, funds})
 	fast, _ := NewBlockChain(fastDb, FakePow{}, new(event.TypeMux))
-	fast.SetProcessor(NewBlockProcessor(fastDb, FakePow{}, fast, new(event.TypeMux)))
 
 	headers := make([]*types.Header, len(blocks))
 	for i, block := range blocks {
@@ -830,7 +843,6 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
 	lightDb, _ := ethdb.NewMemDatabase()
 	WriteGenesisBlockForTesting(lightDb, GenesisAccount{address, funds})
 	light, _ := NewBlockChain(lightDb, FakePow{}, new(event.TypeMux))
-	light.SetProcessor(NewBlockProcessor(lightDb, FakePow{}, light, new(event.TypeMux)))
 
 	if n, err := light.InsertHeaderChain(headers, 1); err != nil {
 		t.Fatalf("failed to insert header %d: %v", n, err)
@@ -895,9 +907,8 @@ func TestChainTxReorgs(t *testing.T) {
 	})
 	// Import the chain. This runs all block validation rules.
 	evmux := &event.TypeMux{}
-	chainman, _ := NewBlockChain(db, FakePow{}, evmux)
-	chainman.SetProcessor(NewBlockProcessor(db, FakePow{}, chainman, evmux))
-	if i, err := chainman.InsertChain(chain); err != nil {
+	blockchain, _ := NewBlockChain(db, FakePow{}, evmux)
+	if i, err := blockchain.InsertChain(chain); err != nil {
 		t.Fatalf("failed to insert original chain[%d]: %v", i, err)
 	}
 
@@ -920,7 +931,7 @@ func TestChainTxReorgs(t *testing.T) {
 			gen.AddTx(futureAdd) // This transaction will be added after a full reorg
 		}
 	})
-	if _, err := chainman.InsertChain(chain); err != nil {
+	if _, err := blockchain.InsertChain(chain); err != nil {
 		t.Fatalf("failed to insert forked chain: %v", err)
 	}
 

+ 4 - 7
core/chain_makers.go

@@ -214,7 +214,7 @@ func makeHeader(parent *types.Block, state *state.StateDB) *types.Header {
 // newCanonical creates a chain database, and injects a deterministic canonical
 // chain. Depending on the full flag, if creates either a full block chain or a
 // header only chain.
-func newCanonical(n int, full bool) (ethdb.Database, *BlockProcessor, error) {
+func newCanonical(n int, full bool) (ethdb.Database, *BlockChain, error) {
 	// Create te new chain database
 	db, _ := ethdb.NewMemDatabase()
 	evmux := &event.TypeMux{}
@@ -223,23 +223,20 @@ func newCanonical(n int, full bool) (ethdb.Database, *BlockProcessor, error) {
 	genesis, _ := WriteTestNetGenesisBlock(db, 0)
 
 	blockchain, _ := NewBlockChain(db, FakePow{}, evmux)
-	processor := NewBlockProcessor(db, FakePow{}, blockchain, evmux)
-	processor.bc.SetProcessor(processor)
-
 	// Create and inject the requested chain
 	if n == 0 {
-		return db, processor, nil
+		return db, blockchain, nil
 	}
 	if full {
 		// Full block-chain requested
 		blocks := makeBlockChain(genesis, n, db, canonicalSeed)
 		_, err := blockchain.InsertChain(blocks)
-		return db, processor, err
+		return db, blockchain, err
 	}
 	// Header-only chain requested
 	headers := makeHeaderChain(genesis.Header(), n, db, canonicalSeed)
 	_, err := blockchain.InsertHeaderChain(headers, 1)
-	return db, processor, err
+	return db, blockchain, err
 }
 
 // makeHeaderChain creates a deterministic chain of headers rooted at parent.

+ 4 - 5
core/chain_makers_test.go

@@ -77,15 +77,14 @@ func ExampleGenerateChain() {
 
 	// Import the chain. This runs all block validation rules.
 	evmux := &event.TypeMux{}
-	chainman, _ := NewBlockChain(db, FakePow{}, evmux)
-	chainman.SetProcessor(NewBlockProcessor(db, FakePow{}, chainman, evmux))
-	if i, err := chainman.InsertChain(chain); err != nil {
+	blockchain, _ := NewBlockChain(db, FakePow{}, evmux)
+	if i, err := blockchain.InsertChain(chain); err != nil {
 		fmt.Printf("insert error (block %d): %v\n", i, err)
 		return
 	}
 
-	state, _ := chainman.State()
-	fmt.Printf("last block: #%d\n", chainman.CurrentBlock().Number())
+	state, _ := blockchain.State()
+	fmt.Printf("last block: #%d\n", blockchain.CurrentBlock().Number())
 	fmt.Println("balance of addr1:", state.GetBalance(addr1))
 	fmt.Println("balance of addr2:", state.GetBalance(addr2))
 	fmt.Println("balance of addr3:", state.GetBalance(addr3))

+ 27 - 6
core/types/common.go → core/gaspool.go

@@ -14,12 +14,33 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 
-package types
+package core
 
-import "github.com/ethereum/go-ethereum/core/vm"
+import "math/big"
 
-type BlockProcessor interface {
-	Process(*Block) (vm.Logs, Receipts, error)
-	ValidateHeader(*Header, bool, bool) error
-	ValidateHeaderWithParent(*Header, *Header, bool, bool) error
+// GasPool tracks the amount of gas available during
+// execution of the transactions in a block.
+// The zero value is a pool with zero gas available.
+type GasPool big.Int
+
+// AddGas makes gas available for execution.
+func (gp *GasPool) AddGas(amount *big.Int) *GasPool {
+	i := (*big.Int)(gp)
+	i.Add(i, amount)
+	return gp
+}
+
+// SubGas deducts the given amount from the pool if enough gas is
+// available and returns an error otherwise.
+func (gp *GasPool) SubGas(amount *big.Int) error {
+	i := (*big.Int)(gp)
+	if i.Cmp(amount) < 0 {
+		return &GasLimitErr{Have: new(big.Int).Set(i), Want: amount}
+	}
+	i.Sub(i, amount)
+	return nil
+}
+
+func (gp *GasPool) String() string {
+	return (*big.Int)(gp).String()
 }

+ 0 - 34
core/manager.go

@@ -1,34 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
-
-package core
-
-import (
-	"github.com/ethereum/go-ethereum/accounts"
-	"github.com/ethereum/go-ethereum/ethdb"
-	"github.com/ethereum/go-ethereum/event"
-)
-
-// TODO move this to types?
-type Backend interface {
-	AccountManager() *accounts.Manager
-	BlockProcessor() *BlockProcessor
-	BlockChain() *BlockChain
-	TxPool() *TxPool
-	ChainDb() ethdb.Database
-	DappDb() ethdb.Database
-	EventMux() *event.TypeMux
-}

+ 107 - 0
core/state_processor.go

@@ -0,0 +1,107 @@
+package core
+
+import (
+	"math/big"
+
+	"github.com/ethereum/go-ethereum/core/state"
+	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/core/vm"
+	"github.com/ethereum/go-ethereum/crypto"
+	"github.com/ethereum/go-ethereum/logger"
+	"github.com/ethereum/go-ethereum/logger/glog"
+)
+
+var (
+	big8  = big.NewInt(8)
+	big32 = big.NewInt(32)
+)
+
+type StateProcessor struct {
+	bc *BlockChain
+}
+
+func NewStateProcessor(bc *BlockChain) *StateProcessor {
+	return &StateProcessor{bc}
+}
+
+// Process processes the state changes according to the Ethereum rules by running
+// the transaction messages using the statedb and applying any rewards to both
+// the processor (coinbase) and any included uncles.
+//
+// Process returns the receipts and logs accumulated during the process and
+// returns the amount of gas that was used in the process. If any of the
+// transactions failed to execute due to insufficient gas it will return an error.
+func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB) (types.Receipts, vm.Logs, *big.Int, error) {
+	var (
+		receipts     types.Receipts
+		totalUsedGas = big.NewInt(0)
+		err          error
+		header       = block.Header()
+		allLogs      vm.Logs
+		gp           = new(GasPool).AddGas(block.GasLimit())
+	)
+
+	for i, tx := range block.Transactions() {
+		statedb.StartRecord(tx.Hash(), block.Hash(), i)
+
+		receipt, logs, _, err := ApplyTransaction(p.bc, gp, statedb, header, tx, totalUsedGas)
+		if err != nil {
+			return nil, nil, totalUsedGas, err
+		}
+		receipts = append(receipts, receipt)
+		allLogs = append(allLogs, logs...)
+	}
+	AccumulateRewards(statedb, header, block.Uncles())
+
+	return receipts, allLogs, totalUsedGas, err
+}
+
+// ApplyTransaction attemps to apply a transaction to the given state database
+// and uses the input parameters for its environment.
+//
+// ApplyTransactions returns the generated receipts and vm logs during the
+// execution of the state transition phase.
+func ApplyTransaction(bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int) (*types.Receipt, vm.Logs, *big.Int, error) {
+	_, gas, err := ApplyMessage(NewEnv(statedb, bc, tx, header), tx, gp)
+	if err != nil {
+		return nil, nil, nil, err
+	}
+
+	// Update the state with pending changes
+	usedGas.Add(usedGas, gas)
+	receipt := types.NewReceipt(statedb.IntermediateRoot().Bytes(), usedGas)
+	receipt.TxHash = tx.Hash()
+	receipt.GasUsed = new(big.Int).Set(gas)
+	if MessageCreatesContract(tx) {
+		from, _ := tx.From()
+		receipt.ContractAddress = crypto.CreateAddress(from, tx.Nonce())
+	}
+
+	logs := statedb.GetLogs(tx.Hash())
+	receipt.Logs = logs
+	receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
+
+	glog.V(logger.Debug).Infoln(receipt)
+
+	return receipt, logs, gas, err
+}
+
+// AccumulateRewards credits the coinbase of the given block with the
+// mining reward. The total reward consists of the static block reward
+// and rewards for included uncles. The coinbase of each uncle block is
+// also rewarded.
+func AccumulateRewards(statedb *state.StateDB, header *types.Header, uncles []*types.Header) {
+	reward := new(big.Int).Set(BlockReward)
+	r := new(big.Int)
+	for _, uncle := range uncles {
+		r.Add(uncle.Number, big8)
+		r.Sub(r, header.Number)
+		r.Mul(r, BlockReward)
+		r.Div(r, big8)
+		statedb.AddBalance(uncle.Coinbase, r)
+
+		r.Div(BlockReward, big32)
+		reward.Add(reward, r)
+	}
+	statedb.AddBalance(header.Coinbase, reward)
+}

+ 70 - 0
core/types.go

@@ -0,0 +1,70 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+package core
+
+import (
+	"math/big"
+
+	"github.com/ethereum/go-ethereum/accounts"
+	"github.com/ethereum/go-ethereum/core/state"
+	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/core/vm"
+	"github.com/ethereum/go-ethereum/ethdb"
+	"github.com/ethereum/go-ethereum/event"
+)
+
+// Validator is an interface which defines the standard for block validation.
+//
+// The validator is responsible for validating incoming block or, if desired,
+// validates headers for fast validation.
+//
+// ValidateBlock validates the given block and should return an error if it
+// failed to do so and should be used for "full" validation.
+//
+// ValidateHeader validates the given header and parent and returns an error
+// if it failed to do so.
+//
+// ValidateStack validates the given statedb and optionally the receipts and
+// gas used. The implementor should decide what to do with the given input.
+type Validator interface {
+	ValidateBlock(block *types.Block) error
+	ValidateHeader(header, parent *types.Header, checkPow bool) error
+	ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error
+}
+
+// Processor is an interface for processing blocks using a given initial state.
+//
+// Process takes the block to be processed and the statedb upon which the
+// initial state is based. It should return the receipts generated, amount
+// of gas used in the process and return an error if any of the internal rules
+// failed.
+type Processor interface {
+	Process(block *types.Block, statedb *state.StateDB) (types.Receipts, vm.Logs, *big.Int, error)
+}
+
+// Backend is an interface defining the basic functionality for an operable node
+// with all the functionality to be a functional, valid Ethereum operator.
+//
+// TODO Remove this
+type Backend interface {
+	AccountManager() *accounts.Manager
+	BlockChain() *BlockChain
+	TxPool() *TxPool
+	ChainDb() ethdb.Database
+	DappDb() ethdb.Database
+	EventMux() *event.TypeMux
+}

+ 18 - 23
eth/backend.go

@@ -231,9 +231,7 @@ type Ethereum struct {
 	chainDb ethdb.Database // Block chain database
 	dappDb  ethdb.Database // Dapp database
 
-	//*** SERVICES ***
-	// State manager for processing new blocks and managing the over all states
-	blockProcessor  *core.BlockProcessor
+	// Handlers
 	txPool          *core.TxPool
 	blockchain      *core.BlockChain
 	accountManager  *accounts.Manager
@@ -407,8 +405,6 @@ func New(config *Config) (*Ethereum, error) {
 	newPool := core.NewTxPool(eth.EventMux(), eth.blockchain.State, eth.blockchain.GasLimit)
 	eth.txPool = newPool
 
-	eth.blockProcessor = core.NewBlockProcessor(chainDb, eth.pow, eth.blockchain, eth.EventMux())
-	eth.blockchain.SetProcessor(eth.blockProcessor)
 	if eth.protocolManager, err = NewProtocolManager(config.FastSync, config.NetworkId, eth.eventMux, eth.txPool, eth.pow, eth.blockchain, chainDb); err != nil {
 		return nil, err
 	}
@@ -485,24 +481,23 @@ func (s *Ethereum) IsMining() bool      { return s.miner.Mining() }
 func (s *Ethereum) Miner() *miner.Miner { return s.miner }
 
 // func (s *Ethereum) Logger() logger.LogSystem             { return s.logger }
-func (s *Ethereum) Name() string                         { return s.net.Name }
-func (s *Ethereum) AccountManager() *accounts.Manager    { return s.accountManager }
-func (s *Ethereum) BlockChain() *core.BlockChain         { return s.blockchain }
-func (s *Ethereum) BlockProcessor() *core.BlockProcessor { return s.blockProcessor }
-func (s *Ethereum) TxPool() *core.TxPool                 { return s.txPool }
-func (s *Ethereum) Whisper() *whisper.Whisper            { return s.whisper }
-func (s *Ethereum) EventMux() *event.TypeMux             { return s.eventMux }
-func (s *Ethereum) ChainDb() ethdb.Database              { return s.chainDb }
-func (s *Ethereum) DappDb() ethdb.Database               { return s.dappDb }
-func (s *Ethereum) IsListening() bool                    { return true } // Always listening
-func (s *Ethereum) PeerCount() int                       { return s.net.PeerCount() }
-func (s *Ethereum) Peers() []*p2p.Peer                   { return s.net.Peers() }
-func (s *Ethereum) MaxPeers() int                        { return s.net.MaxPeers }
-func (s *Ethereum) ClientVersion() string                { return s.clientVersion }
-func (s *Ethereum) EthVersion() int                      { return int(s.protocolManager.SubProtocols[0].Version) }
-func (s *Ethereum) NetVersion() int                      { return s.netVersionId }
-func (s *Ethereum) ShhVersion() int                      { return s.shhVersionId }
-func (s *Ethereum) Downloader() *downloader.Downloader   { return s.protocolManager.downloader }
+func (s *Ethereum) Name() string                       { return s.net.Name }
+func (s *Ethereum) AccountManager() *accounts.Manager  { return s.accountManager }
+func (s *Ethereum) BlockChain() *core.BlockChain       { return s.blockchain }
+func (s *Ethereum) TxPool() *core.TxPool               { return s.txPool }
+func (s *Ethereum) Whisper() *whisper.Whisper          { return s.whisper }
+func (s *Ethereum) EventMux() *event.TypeMux           { return s.eventMux }
+func (s *Ethereum) ChainDb() ethdb.Database            { return s.chainDb }
+func (s *Ethereum) DappDb() ethdb.Database             { return s.dappDb }
+func (s *Ethereum) IsListening() bool                  { return true } // Always listening
+func (s *Ethereum) PeerCount() int                     { return s.net.PeerCount() }
+func (s *Ethereum) Peers() []*p2p.Peer                 { return s.net.Peers() }
+func (s *Ethereum) MaxPeers() int                      { return s.net.MaxPeers }
+func (s *Ethereum) ClientVersion() string              { return s.clientVersion }
+func (s *Ethereum) EthVersion() int                    { return int(s.protocolManager.SubProtocols[0].Version) }
+func (s *Ethereum) NetVersion() int                    { return s.netVersionId }
+func (s *Ethereum) ShhVersion() int                    { return s.shhVersionId }
+func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader }
 
 // Start the ethereum
 func (s *Ethereum) Start() error {

+ 1 - 1
eth/gasprice.go

@@ -166,7 +166,7 @@ func (self *GasPriceOracle) processBlock(block *types.Block) {
 func (self *GasPriceOracle) lowestPrice(block *types.Block) *big.Int {
 	gasUsed := big.NewInt(0)
 
-	receipts := self.eth.BlockProcessor().GetBlockReceipts(block.Hash())
+	receipts := core.GetBlockReceipts(self.eth.ChainDb(), block.Hash())
 	if len(receipts) > 0 {
 		if cgu := receipts[len(receipts)-1].CumulativeGasUsed; cgu != nil {
 			gasUsed = receipts[len(receipts)-1].CumulativeGasUsed

+ 0 - 2
eth/helper_test.go

@@ -35,9 +35,7 @@ func newTestProtocolManager(fastSync bool, blocks int, generator func(int, *core
 		db, _         = ethdb.NewMemDatabase()
 		genesis       = core.WriteGenesisBlockForTesting(db, core.GenesisAccount{testBankAddress, testBankFunds})
 		blockchain, _ = core.NewBlockChain(db, pow, evmux)
-		blockproc     = core.NewBlockProcessor(db, pow, blockchain, evmux)
 	)
-	blockchain.SetProcessor(blockproc)
 	chain, _ := core.GenerateChain(genesis, db, blocks, generator)
 	if _, err := blockchain.InsertChain(chain); err != nil {
 		panic(err)

+ 11 - 10
miner/worker.go

@@ -100,7 +100,7 @@ type worker struct {
 
 	eth     core.Backend
 	chain   *core.BlockChain
-	proc    *core.BlockProcessor
+	proc    core.Validator
 	chainDb ethdb.Database
 
 	coinbase common.Address
@@ -131,7 +131,7 @@ func newWorker(coinbase common.Address, eth core.Backend) *worker {
 		recv:           make(chan *Result, resultQueueSize),
 		gasPrice:       new(big.Int),
 		chain:          eth.BlockChain(),
-		proc:           eth.BlockProcessor(),
+		proc:           eth.BlockChain().Validator(),
 		possibleUncles: make(map[common.Hash]*types.Block),
 		coinbase:       coinbase,
 		txQueue:        make(map[common.Hash]*types.Transaction),
@@ -244,7 +244,7 @@ func (self *worker) update() {
 				// Apply transaction to the pending state if we're not mining
 				if atomic.LoadInt32(&self.mining) == 0 {
 					self.currentMu.Lock()
-					self.current.commitTransactions(types.Transactions{ev.Tx}, self.gasPrice, self.proc)
+					self.current.commitTransactions(types.Transactions{ev.Tx}, self.gasPrice, self.chain)
 					self.currentMu.Unlock()
 				}
 			}
@@ -290,7 +290,9 @@ func (self *worker) wait() {
 					glog.V(logger.Error).Infoln("Invalid block found during mining")
 					continue
 				}
-				if err := core.ValidateHeader(self.eth.BlockProcessor().Pow, block.Header(), parent.Header(), true, false); err != nil && err != core.BlockFutureErr {
+
+				auxValidator := self.eth.BlockChain().AuxValidator()
+				if err := core.ValidateHeader(auxValidator, block.Header(), parent.Header(), true, false); err != nil && err != core.BlockFutureErr {
 					glog.V(logger.Error).Infoln("Invalid header on mined block:", err)
 					continue
 				}
@@ -516,7 +518,7 @@ func (self *worker) commitNewWork() {
 	transactions := append(singleTxOwner, multiTxOwner...)
 	*/
 
-	work.commitTransactions(transactions, self.gasPrice, self.proc)
+	work.commitTransactions(transactions, self.gasPrice, self.chain)
 	self.eth.TxPool().RemoveTransactions(work.lowGasTxs)
 
 	// compute uncles for the new block.
@@ -575,9 +577,8 @@ func (self *worker) commitUncle(work *Work, uncle *types.Header) error {
 	return nil
 }
 
-func (env *Work) commitTransactions(transactions types.Transactions, gasPrice *big.Int, proc *core.BlockProcessor) {
+func (env *Work) commitTransactions(transactions types.Transactions, gasPrice *big.Int, bc *core.BlockChain) {
 	gp := new(core.GasPool).AddGas(env.header.GasLimit)
-
 	for _, tx := range transactions {
 		// We can skip err. It has already been validated in the tx pool
 		from, _ := tx.From()
@@ -615,7 +616,7 @@ func (env *Work) commitTransactions(transactions types.Transactions, gasPrice *b
 
 		env.state.StartRecord(tx.Hash(), common.Hash{}, 0)
 
-		err := env.commitTransaction(tx, proc, gp)
+		err := env.commitTransaction(tx, bc, gp)
 		switch {
 		case core.IsGasLimitErr(err):
 			// ignore the transactor so no nonce errors will be thrown for this account
@@ -635,9 +636,9 @@ func (env *Work) commitTransactions(transactions types.Transactions, gasPrice *b
 	}
 }
 
-func (env *Work) commitTransaction(tx *types.Transaction, proc *core.BlockProcessor, gp *core.GasPool) error {
+func (env *Work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, gp *core.GasPool) error {
 	snap := env.state.Copy()
-	receipt, _, err := proc.ApplyTransaction(gp, env.state, env.header, tx, env.header.GasUsed, true)
+	receipt, _, _, err := core.ApplyTransaction(bc, gp, env.state, env.header, tx, env.header.GasUsed)
 	if err != nil {
 		env.state.Set(snap)
 		return err

+ 24 - 4
rpc/api/debug.go

@@ -22,6 +22,7 @@ import (
 	"time"
 
 	"github.com/ethereum/ethash"
+	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/eth"
@@ -166,11 +167,30 @@ func (self *debugApi) ProcessBlock(req *shared.Request) (interface{}, error) {
 	defer func() { vm.Debug = old }()
 	vm.Debug = true
 
-	_, err := self.ethereum.BlockProcessor().RetryProcess(block)
-	if err == nil {
-		return true, nil
+	var (
+		blockchain = self.ethereum.BlockChain()
+		validator  = blockchain.Validator()
+		processor  = blockchain.Processor()
+	)
+
+	err := core.ValidateHeader(blockchain.AuxValidator(), block.Header(), blockchain.GetHeader(block.ParentHash()), true, false)
+	if err != nil {
+		return false, err
 	}
-	return false, err
+	statedb, err := state.New(blockchain.GetBlock(block.ParentHash()).Root(), self.ethereum.ChainDb())
+	if err != nil {
+		return false, err
+	}
+	receipts, _, usedGas, err := processor.Process(block, statedb)
+	if err != nil {
+		return false, err
+	}
+	err = validator.ValidateState(block, blockchain.GetBlock(block.ParentHash()), statedb, receipts, usedGas)
+	if err != nil {
+		return false, err
+	}
+
+	return true, nil
 }
 
 func (self *debugApi) SeedHash(req *shared.Request) (interface{}, error) {

+ 1 - 1
xeth/xeth.go

@@ -379,7 +379,7 @@ func (self *XEth) CurrentBlock() *types.Block {
 }
 
 func (self *XEth) GetBlockReceipts(bhash common.Hash) types.Receipts {
-	return self.backend.BlockProcessor().GetBlockReceipts(bhash)
+	return core.GetBlockReceipts(self.backend.ChainDb(), bhash)
 }
 
 func (self *XEth) GetTxReceipt(txhash common.Hash) *types.Receipt {