diff --git a/core/block_processor.go b/core/block_processor.go
index 059c442cc2417f04b3f9d5aaaf9cb8f988bd6554..5199e4b4d9855ba61345e374d34438d100e84ba5 100644
--- a/core/block_processor.go
+++ b/core/block_processor.go
@@ -347,17 +347,17 @@ func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *ty
 	for i, uncle := range block.Uncles() {
 		if uncles.Has(uncle.Hash()) {
 			// Error not unique
-			return UncleError("Uncle not unique")
+			return UncleError("uncle[%d] not unique", i)
 		}
 
 		uncles.Add(uncle.Hash())
 
 		if ancestors.Has(uncle.Hash()) {
-			return UncleError("Uncle is ancestor")
+			return UncleError("uncle[%d] is ancestor", i)
 		}
 
 		if !ancestors.Has(uncle.ParentHash) {
-			return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
+			return UncleError("uncle[%d]'s parent unknown (%x)", i, uncle.ParentHash[0:4])
 		}
 
 		if err := sm.ValidateHeader(uncle, ancestorHeaders[uncle.ParentHash]); err != nil {
diff --git a/core/chain_makers.go b/core/chain_makers.go
index 5cd7ab4abb0c6c6a0851935349760199ff0d9e8a..acf7b39cc535d9c092f2f3ae10d36498339e1996 100644
--- a/core/chain_makers.go
+++ b/core/chain_makers.go
@@ -98,7 +98,7 @@ func makeChain(bman *BlockProcessor, parent *types.Block, max int, db common.Dat
 			fmt.Println("process with parent failed", err)
 			panic(err)
 		}
-		block.Td = CalculateTD(block, parent)
+		block.Td = CalcTD(block, parent)
 		blocks[i] = block
 		parent = block
 	}
diff --git a/core/chain_manager.go b/core/chain_manager.go
index 9f6d7f823532a5b46fa74b29f2efe036014d9888..a0839ad418038e6a32ecede3a781a5b97bc47d0f 100644
--- a/core/chain_manager.go
+++ b/core/chain_manager.go
@@ -48,7 +48,7 @@ func CalcDifficulty(block, parent *types.Header) *big.Int {
 	return diff
 }
 
-func CalculateTD(block, parent *types.Block) *big.Int {
+func CalcTD(block, parent *types.Block) *big.Int {
 	if parent == nil {
 		return block.Difficulty()
 	}
@@ -59,14 +59,20 @@ func CalculateTD(block, parent *types.Block) *big.Int {
 }
 
 func CalcGasLimit(parent *types.Block) *big.Int {
-	// ((1024-1) * parent.gasLimit + (gasUsed * 6 / 5)) / 1024
-	previous := new(big.Int).Mul(big.NewInt(1024-1), parent.GasLimit())
-	current := new(big.Rat).Mul(new(big.Rat).SetInt(parent.GasUsed()), big.NewRat(6, 5))
-	curInt := new(big.Int).Div(current.Num(), current.Denom())
+	decay := new(big.Int).Div(parent.GasLimit(), params.GasLimitBoundDivisor)
+	contrib := new(big.Int).Mul(parent.GasUsed(), big.NewInt(3))
+	contrib = contrib.Div(contrib, big.NewInt(2))
+	contrib = contrib.Div(contrib, params.GasLimitBoundDivisor)
 
-	result := new(big.Int).Add(previous, curInt)
-	result.Div(result, big.NewInt(1024))
-	return common.BigMax(params.GenesisGasLimit, result)
+	gl := new(big.Int).Sub(parent.GasLimit(), decay)
+	gl = gl.Add(gl, contrib)
+	gl = common.BigMax(gl, params.MinGasLimit)
+
+	if gl.Cmp(params.GenesisGasLimit) < 0 {
+		gl2 := new(big.Int).Add(parent.GasLimit(), decay)
+		return common.BigMin(params.GenesisGasLimit, gl2)
+	}
+	return gl
 }
 
 type ChainManager struct {
@@ -525,7 +531,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
 		}
 		// Setting block.Td regardless of error (known for example) prevents errors down the line
 		// in the protocol handler
-		block.Td = new(big.Int).Set(CalculateTD(block, self.GetBlock(block.ParentHash())))
+		block.Td = new(big.Int).Set(CalcTD(block, self.GetBlock(block.ParentHash())))
 
 		// 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).
@@ -593,7 +599,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
 				self.setTransState(state.New(block.Root(), self.stateDb))
 				self.txState.SetState(state.New(block.Root(), self.stateDb))
 
-				queue[i] = ChainEvent{block, logs}
+				queue[i] = ChainEvent{block, block.Hash(), logs}
 				queueEvent.canonicalCount++
 
 				if glog.V(logger.Debug) {
@@ -683,7 +689,7 @@ out:
 					case ChainEvent:
 						// We need some control over the mining operation. Acquiring locks and waiting for the miner to create new block takes too long
 						// and in most cases isn't even necessary.
-						if i+1 == ev.canonicalCount {
+						if self.lastBlockHash == event.Hash {
 							self.currentGasLimit = CalcGasLimit(event.Block)
 							self.eventMux.Post(ChainHeadEvent{event.Block})
 						}
diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go
index f456e4fffb525f2cfe3957739a1add60d3ab1b6d..b5155e223db5aa398473a55b1f283a81d2d7902d 100644
--- a/core/chain_manager_test.go
+++ b/core/chain_manager_test.go
@@ -81,7 +81,7 @@ func testChain(chainB types.Blocks, bman *BlockProcessor) (*big.Int, error) {
 			return nil, err
 		}
 		parent := bman.bc.GetBlock(block.ParentHash())
-		block.Td = CalculateTD(block, parent)
+		block.Td = CalcTD(block, parent)
 		td = block.Td
 
 		bman.bc.mu.Lock()
diff --git a/core/error.go b/core/error.go
index 40db99ecd8701ab4788defebbfc5a0f7dadc322d..2bdad364f547fa345612cbede308f97c00bbced5 100644
--- a/core/error.go
+++ b/core/error.go
@@ -42,8 +42,8 @@ func (err *UncleErr) Error() string {
 	return err.Message
 }
 
-func UncleError(str string) error {
-	return &UncleErr{Message: str}
+func UncleError(format string, v ...interface{}) error {
+	return &UncleErr{Message: fmt.Sprintf(format, v...)}
 }
 
 func IsUncleErr(err error) bool {
diff --git a/core/events.go b/core/events.go
index 1ea35c2f49b7df6e3c7a5244e37834191d4a8f13..7b56f8bb65ba3c490ec8cf3dd3a605a403be2ad8 100644
--- a/core/events.go
+++ b/core/events.go
@@ -3,6 +3,7 @@ package core
 import (
 	"math/big"
 
+	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
 )
@@ -27,6 +28,7 @@ type ChainSplitEvent struct {
 
 type ChainEvent struct {
 	Block *types.Block
+	Hash  common.Hash
 	Logs  state.Logs
 }
 
diff --git a/core/manager.go b/core/manager.go
index 433ada7ee66c856df1b6c804db05069ad6b8c73a..695f0e99c93bf28bdcc481bd22ac71ab3dbd9bac 100644
--- a/core/manager.go
+++ b/core/manager.go
@@ -3,10 +3,12 @@ package core
 import (
 	"github.com/ethereum/go-ethereum/accounts"
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/eth/downloader"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/p2p"
 )
 
+// TODO move this to types?
 type Backend interface {
 	AccountManager() *accounts.Manager
 	BlockProcessor() *BlockProcessor
@@ -18,4 +20,5 @@ type Backend interface {
 	BlockDb() common.Database
 	StateDb() common.Database
 	EventMux() *event.TypeMux
+	Downloader() *downloader.Downloader
 }
diff --git a/eth/backend.go b/eth/backend.go
index 362a7eab7dabf41d56bf8a462d942ec3341d76b9..0640189554af69425cd285c86a3df9d9ad61f457 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -265,12 +265,12 @@ func New(config *Config) (*Ethereum, error) {
 	}
 
 	eth.chainManager = core.NewChainManager(blockDb, stateDb, eth.EventMux())
-	eth.downloader = downloader.New(eth.chainManager.HasBlock, eth.chainManager.GetBlock)
+	eth.downloader = downloader.New(eth.EventMux(), eth.chainManager.HasBlock, eth.chainManager.GetBlock)
 	eth.pow = ethash.New()
 	eth.txPool = core.NewTxPool(eth.EventMux(), eth.chainManager.State, eth.chainManager.GasLimit)
 	eth.blockProcessor = core.NewBlockProcessor(stateDb, extraDb, eth.pow, eth.txPool, eth.chainManager, eth.EventMux())
 	eth.chainManager.SetProcessor(eth.blockProcessor)
-	eth.miner = miner.New(eth, eth.pow)
+	eth.miner = miner.New(eth, eth.EventMux(), eth.pow)
 	eth.miner.SetGasPrice(config.GasPrice)
 
 	eth.protocolManager = NewProtocolManager(config.ProtocolVersion, config.NetworkId, eth.eventMux, eth.txPool, eth.chainManager, eth.downloader)
diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go
index cc75c3014e9351fb8b83e7017a2460a1047e1a2b..616971f73ec6bb3da0e88820414199b763bb315e 100644
--- a/eth/downloader/downloader.go
+++ b/eth/downloader/downloader.go
@@ -9,6 +9,7 @@ import (
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/logger/glog"
 )
@@ -55,6 +56,8 @@ type hashPack struct {
 }
 
 type Downloader struct {
+	mux *event.TypeMux
+
 	mu    sync.RWMutex
 	queue *queue
 	peers *peerSet
@@ -76,8 +79,9 @@ type Downloader struct {
 	cancelLock sync.RWMutex  // Lock to protect the cancel channel in delivers
 }
 
-func New(hasBlock hashCheckFn, getBlock getBlockFn) *Downloader {
+func New(mux *event.TypeMux, hasBlock hashCheckFn, getBlock getBlockFn) *Downloader {
 	downloader := &Downloader{
+		mux:       mux,
 		queue:     newQueue(),
 		peers:     newPeerSet(),
 		hasBlock:  hasBlock,
@@ -93,6 +97,11 @@ func (d *Downloader) Stats() (current int, max int) {
 	return d.queue.Size()
 }
 
+// Synchronising returns the state of the downloader
+func (d *Downloader) Synchronising() bool {
+	return atomic.LoadInt32(&d.synchronising) > 0
+}
+
 // RegisterPeer injects a new download peer into the set of block source to be
 // used for fetching hashes and blocks from.
 func (d *Downloader) RegisterPeer(id string, head common.Hash, getHashes hashFetcherFn, getBlocks blockFetcherFn) error {
@@ -129,6 +138,9 @@ func (d *Downloader) Synchronise(id string, hash common.Hash) error {
 	if atomic.CompareAndSwapInt32(&d.notified, 0, 1) {
 		glog.V(logger.Info).Infoln("Block synchronisation started")
 	}
+
+	d.mux.Post(StartEvent{})
+
 	// Create cancel channel for aborting mid-flight
 	d.cancelLock.Lock()
 	d.cancelCh = make(chan struct{})
@@ -166,6 +178,9 @@ func (d *Downloader) syncWithPeer(p *peer, hash common.Hash) (err error) {
 		// reset on error
 		if err != nil {
 			d.queue.Reset()
+			d.mux.Post(FailedEvent{err})
+		} else {
+			d.mux.Post(DoneEvent{})
 		}
 	}()
 
diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go
index cfa6257a3de528a4b02be2502919b91bec4c1704..50fe00d42ac4dac7f8e5899d157391653912a2ec 100644
--- a/eth/downloader/downloader_test.go
+++ b/eth/downloader/downloader_test.go
@@ -8,6 +8,7 @@ import (
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/event"
 )
 
 var (
@@ -67,7 +68,8 @@ func newTester(t *testing.T, hashes []common.Hash, blocks map[common.Hash]*types
 
 		done: make(chan bool),
 	}
-	downloader := New(tester.hasBlock, tester.getBlock)
+	var mux event.TypeMux
+	downloader := New(&mux, tester.hasBlock, tester.getBlock)
 	tester.downloader = downloader
 
 	return tester
diff --git a/eth/downloader/events.go b/eth/downloader/events.go
new file mode 100644
index 0000000000000000000000000000000000000000..333feb976c8d5ec6eb3645edb16ecf31f4f0ea01
--- /dev/null
+++ b/eth/downloader/events.go
@@ -0,0 +1,5 @@
+package downloader
+
+type DoneEvent struct{}
+type StartEvent struct{}
+type FailedEvent struct{ Err error }
diff --git a/miner/miner.go b/miner/miner.go
index 8143fcef721009d280d260abd547f6c17b9a5bd9..359be40325b393f944512ef5d0724bce79e54c8c 100644
--- a/miner/miner.go
+++ b/miner/miner.go
@@ -2,33 +2,63 @@ package miner
 
 import (
 	"math/big"
+	"sync/atomic"
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/eth/downloader"
+	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/logger/glog"
 	"github.com/ethereum/go-ethereum/pow"
 )
 
 type Miner struct {
+	mux *event.TypeMux
+
 	worker *worker
 
 	MinAcceptedGasPrice *big.Int
 
-	threads int
-	mining  bool
-	eth     core.Backend
-	pow     pow.PoW
+	threads  int
+	coinbase common.Address
+	mining   int32
+	eth      core.Backend
+	pow      pow.PoW
+
+	canStart    int32 // can start indicates whether we can start the mining operation
+	shouldStart int32 // should start indicates whether we should start after sync
 }
 
-func New(eth core.Backend, pow pow.PoW) *Miner {
-	return &Miner{eth: eth, pow: pow, worker: newWorker(common.Address{}, eth)}
+func New(eth core.Backend, mux *event.TypeMux, pow pow.PoW) *Miner {
+	miner := &Miner{eth: eth, mux: mux, pow: pow, worker: newWorker(common.Address{}, eth), canStart: 1}
+	go miner.update()
+
+	return miner
 }
 
-func (self *Miner) Mining() bool {
-	return self.mining
+func (self *Miner) update() {
+	events := self.mux.Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{})
+	for ev := range events.Chan() {
+		switch ev.(type) {
+		case downloader.StartEvent:
+			atomic.StoreInt32(&self.canStart, 0)
+			if self.Mining() {
+				self.Stop()
+				glog.V(logger.Info).Infoln("Mining operation aborted due to sync operation")
+			}
+		case downloader.DoneEvent, downloader.FailedEvent:
+			shouldStart := atomic.LoadInt32(&self.shouldStart) == 1
+
+			atomic.StoreInt32(&self.canStart, 1)
+			atomic.StoreInt32(&self.shouldStart, 0)
+			if shouldStart {
+				self.Start(self.coinbase, self.threads)
+			}
+		}
+	}
 }
 
 func (m *Miner) SetGasPrice(price *big.Int) {
@@ -41,34 +71,46 @@ func (m *Miner) SetGasPrice(price *big.Int) {
 }
 
 func (self *Miner) Start(coinbase common.Address, threads int) {
+	atomic.StoreInt32(&self.shouldStart, 1)
+	self.threads = threads
+	self.worker.coinbase = coinbase
+
+	if atomic.LoadInt32(&self.canStart) == 0 {
+		glog.V(logger.Info).Infoln("Can not start mining operation due to network sync (starts when finished)")
+		return
+	}
 
-	self.mining = true
+	atomic.StoreInt32(&self.mining, 1)
 
 	for i := 0; i < threads; i++ {
 		self.worker.register(NewCpuAgent(i, self.pow))
 	}
-	self.threads = threads
 
 	glog.V(logger.Info).Infof("Starting mining operation (CPU=%d TOT=%d)\n", threads, len(self.worker.agents))
 
-	self.worker.coinbase = coinbase
 	self.worker.start()
+
 	self.worker.commitNewWork()
 }
 
 func (self *Miner) Stop() {
 	self.worker.stop()
-	self.mining = false
+	atomic.StoreInt32(&self.mining, 0)
+	atomic.StoreInt32(&self.shouldStart, 0)
 }
 
 func (self *Miner) Register(agent Agent) {
-	if self.mining {
+	if atomic.LoadInt32(&self.mining) == 0 {
 		agent.Start()
 	}
 
 	self.worker.register(agent)
 }
 
+func (self *Miner) Mining() bool {
+	return atomic.LoadInt32(&self.mining) > 0
+}
+
 func (self *Miner) HashRate() int64 {
 	return self.pow.GetHashrate()
 }