diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go
index bc3a264d1e2601f7ab77f35bf21c955c5e8caaa5..a357a8b1a93e982bbf6bbecdc1fd214c094c4a19 100644
--- a/core/chain_manager_test.go
+++ b/core/chain_manager_test.go
@@ -3,6 +3,7 @@ package core
 import (
 	"bytes"
 	"fmt"
+	"math/big"
 	"os"
 	"path"
 	"runtime"
@@ -13,14 +14,167 @@ import (
 	"github.com/ethereum/go-ethereum/ethdb"
 	"github.com/ethereum/go-ethereum/ethutil"
 	"github.com/ethereum/go-ethereum/event"
+	"github.com/ethereum/go-ethereum/pow"
 	"github.com/ethereum/go-ethereum/rlp"
+	"github.com/ethereum/go-ethereum/state"
 )
 
+// So we can generate blocks easily
+type fakePow struct{}
+
+func (f fakePow) Search(block pow.Block, stop <-chan struct{}) []byte { return nil }
+func (f fakePow) Verify(block pow.Block) bool                         { return true }
+func (f fakePow) GetHashrate() int64                                  { return 0 }
+func (f fakePow) Turbo(bool)                                          {}
+
 func init() {
 	runtime.GOMAXPROCS(runtime.NumCPU())
 	ethutil.ReadConfig("/tmp/ethtest", "/tmp/ethtest", "ETH")
 }
 
+func newBlockFromParent(addr []byte, parent *types.Block) *types.Block {
+	block := types.NewBlock(parent.Hash(), addr, parent.Root(), ethutil.BigPow(2, 32), nil, "")
+
+	block.SetUncles(nil)
+	block.SetTransactions(nil)
+	block.SetReceipts(nil)
+
+	header := block.Header()
+	header.Difficulty = CalcDifficulty(block, parent)
+	header.Number = new(big.Int).Add(parent.Header().Number, ethutil.Big1)
+	header.GasLimit = CalcGasLimit(parent, block)
+
+	block.Td = parent.Td
+
+	return block
+}
+
+// Actually make a block by simulating what miner would do
+func makeBlock(bman *BlockProcessor, parent *types.Block, i int, db ethutil.Database) *types.Block {
+	addr := ethutil.LeftPadBytes([]byte{byte(i)}, 20)
+	block := newBlockFromParent(addr, parent)
+	state := state.New(block.Root(), db)
+	cbase := state.GetOrNewStateObject(addr)
+	cbase.SetGasPool(CalcGasLimit(parent, block))
+	cbase.AddAmount(BlockReward)
+	state.Update(ethutil.Big0)
+	block.SetRoot(state.Root())
+	return block
+}
+
+// Make a chain with real blocks
+// Runs ProcessWithParent to get proper state roots
+func makeChain(bman *BlockProcessor, parent *types.Block, max int, db ethutil.Database) types.Blocks {
+	bman.bc.currentBlock = parent
+	blocks := make(types.Blocks, max)
+	for i := 0; i < max; i++ {
+		block := makeBlock(bman, parent, i, db)
+		td, err := bman.processWithParent(block, parent)
+		if err != nil {
+			fmt.Println("process with parent failed", err)
+			panic(err)
+		}
+		block.Td = td
+		blocks[i] = block
+		parent = block
+		fmt.Printf("New Block: %x\n", block.Hash())
+	}
+	fmt.Println("Done making chain")
+	return blocks
+}
+
+// Create a new chain manager starting from given block
+// Effectively a fork factory
+func newChainManager(block *types.Block, eventMux *event.TypeMux, db ethutil.Database) *ChainManager {
+	bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: eventMux}
+	if block == nil {
+		bc.Reset()
+	} else {
+		bc.currentBlock = block
+		bc.td = block.Td
+	}
+	return bc
+}
+
+// block processor with fake pow
+func newBlockProcessor(db ethutil.Database, txpool *TxPool, cman *ChainManager, eventMux *event.TypeMux) *BlockProcessor {
+	bman := NewBlockProcessor(db, txpool, newChainManager(nil, eventMux, db), eventMux)
+	bman.Pow = fakePow{}
+	return bman
+}
+
+// Make a new canonical chain by running InsertChain
+// on result of makeChain
+func newCanonical(n int, db ethutil.Database) (*BlockProcessor, error) {
+	eventMux := &event.TypeMux{}
+	txpool := NewTxPool(eventMux)
+
+	bman := newBlockProcessor(db, txpool, newChainManager(nil, eventMux, db), eventMux)
+	bman.bc.SetProcessor(bman)
+	parent := bman.bc.CurrentBlock()
+	if n == 0 {
+		return bman, nil
+	}
+	lchain := makeChain(bman, parent, n, db)
+	bman.bc.InsertChain(lchain)
+	return bman, nil
+}
+
+// Test fork of length N starting from block i
+func testFork(t *testing.T, bman *BlockProcessor, i, N int, f func(td1, td2 *big.Int)) {
+	fmt.Println("Testing Fork!")
+	var b *types.Block = nil
+	if i > 0 {
+		b = bman.bc.GetBlockByNumber(uint64(i))
+	}
+	_ = b
+	// switch databases to process the new chain
+	db, err := ethdb.NewMemDatabase()
+	if err != nil {
+		t.Fatal("Failed to create db:", err)
+	}
+	// copy old chain up to i into new db with deterministic canonical
+	bman2, err := newCanonical(i, db)
+	if err != nil {
+		t.Fatal("could not make new canonical in testFork", err)
+	}
+	bman2.bc.SetProcessor(bman2)
+
+	parent := bman2.bc.CurrentBlock()
+	chainB := makeChain(bman2, parent, N, db)
+	bman2.bc.InsertChain(chainB)
+
+	tdpre := bman.bc.Td()
+	td, err := testChain(chainB, bman)
+	if err != nil {
+		t.Fatal("expected chainB not to give errors:", err)
+	}
+	// Compare difficulties
+	f(tdpre, td)
+}
+
+func testChain(chainB types.Blocks, bman *BlockProcessor) (*big.Int, error) {
+	td := new(big.Int)
+	for _, block := range chainB {
+		td2, err := bman.bc.processor.Process(block)
+		if err != nil {
+			if IsKnownBlockErr(err) {
+				continue
+			}
+			return nil, err
+		}
+		block.Td = td2
+		td = td2
+
+		bman.bc.mu.Lock()
+		{
+			bman.bc.write(block)
+		}
+		bman.bc.mu.Unlock()
+	}
+	return td, nil
+}
+
 func loadChain(fn string, t *testing.T) (types.Blocks, error) {
 	fh, err := os.OpenFile(path.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "_data", fn), os.O_RDONLY, os.ModePerm)
 	if err != nil {
@@ -45,6 +199,128 @@ func insertChain(done chan bool, chainMan *ChainManager, chain types.Blocks, t *
 	done <- true
 }
 
+func TestExtendCanonical(t *testing.T) {
+	db, err := ethdb.NewMemDatabase()
+	if err != nil {
+		t.Fatal("Failed to create db:", err)
+	}
+	// make first chain starting from genesis
+	bman, err := newCanonical(5, db)
+	if err != nil {
+		t.Fatal("Could not make new canonical chain:", err)
+	}
+	f := func(td1, td2 *big.Int) {
+		if td2.Cmp(td1) <= 0 {
+			t.Error("expected chainB to have higher difficulty. Got", td2, "expected more than", td1)
+		}
+	}
+	// Start fork from current height (5)
+	testFork(t, bman, 5, 1, f)
+	testFork(t, bman, 5, 2, f)
+	testFork(t, bman, 5, 5, f)
+	testFork(t, bman, 5, 10, f)
+}
+
+func TestShorterFork(t *testing.T) {
+	db, err := ethdb.NewMemDatabase()
+	if err != nil {
+		t.Fatal("Failed to create db:", err)
+	}
+	// make first chain starting from genesis
+	bman, err := newCanonical(10, db)
+	if err != nil {
+		t.Fatal("Could not make new canonical chain:", err)
+	}
+	f := func(td1, td2 *big.Int) {
+		if td2.Cmp(td1) >= 0 {
+			t.Error("expected chainB to have lower difficulty. Got", td2, "expected less than", td1)
+		}
+	}
+	// Sum of numbers must be less than 10
+	// for this to be a shorter fork
+	testFork(t, bman, 0, 3, f)
+	testFork(t, bman, 0, 7, f)
+	testFork(t, bman, 1, 1, f)
+	testFork(t, bman, 1, 7, f)
+	testFork(t, bman, 5, 3, f)
+	testFork(t, bman, 5, 4, f)
+}
+
+func TestLongerFork(t *testing.T) {
+	db, err := ethdb.NewMemDatabase()
+	if err != nil {
+		t.Fatal("Failed to create db:", err)
+	}
+	// make first chain starting from genesis
+	bman, err := newCanonical(10, db)
+	if err != nil {
+		t.Fatal("Could not make new canonical chain:", err)
+	}
+	f := func(td1, td2 *big.Int) {
+		if td2.Cmp(td1) <= 0 {
+			t.Error("expected chainB to have higher difficulty. Got", td2, "expected more than", td1)
+		}
+	}
+	// Sum of numbers must be greater than 10
+	// for this to be a longer fork
+	testFork(t, bman, 0, 11, f)
+	testFork(t, bman, 0, 15, f)
+	testFork(t, bman, 1, 10, f)
+	testFork(t, bman, 1, 12, f)
+	testFork(t, bman, 5, 6, f)
+	testFork(t, bman, 5, 8, f)
+}
+
+func TestEqualFork(t *testing.T) {
+	db, err := ethdb.NewMemDatabase()
+	if err != nil {
+		t.Fatal("Failed to create db:", err)
+	}
+	bman, err := newCanonical(10, db)
+	if err != nil {
+		t.Fatal("Could not make new canonical chain:", err)
+	}
+	f := func(td1, td2 *big.Int) {
+		if td2.Cmp(td1) != 0 {
+			t.Error("expected chainB to have equal difficulty. Got", td2, "expected ", td1)
+		}
+	}
+	// Sum of numbers must be equal to 10
+	// for this to be an equal fork
+	testFork(t, bman, 1, 9, f)
+	testFork(t, bman, 2, 8, f)
+	testFork(t, bman, 5, 5, f)
+	testFork(t, bman, 6, 4, f)
+	testFork(t, bman, 9, 1, f)
+}
+
+func TestBrokenChain(t *testing.T) {
+	db, err := ethdb.NewMemDatabase()
+	if err != nil {
+		t.Fatal("Failed to create db:", err)
+	}
+	bman, err := newCanonical(10, db)
+	if err != nil {
+		t.Fatal("Could not make new canonical chain:", err)
+	}
+	db2, err := ethdb.NewMemDatabase()
+	if err != nil {
+		t.Fatal("Failed to create db:", err)
+	}
+	bman2, err := newCanonical(10, db2)
+	if err != nil {
+		t.Fatal("Could not make new canonical chain:", err)
+	}
+	bman2.bc.SetProcessor(bman2)
+	parent := bman2.bc.CurrentBlock()
+	chainB := makeChain(bman2, parent, 5, db2)
+	chainB = chainB[1:]
+	_, err = testChain(chainB, bman)
+	if err == nil {
+		t.Error("expected broken chain to return error")
+	}
+}
+
 func TestChainInsertions(t *testing.T) {
 	t.Skip() // travil fails.