Skip to content

Commit a8ebf75

Browse files
committed
Merge branch 'miner-broadcast' into core-optimisations-2
Conflicts: core/chain_manager.go miner/worker.go
2 parents 5d9df73 + b39042d commit a8ebf75

File tree

3 files changed

+129
-66
lines changed

3 files changed

+129
-66
lines changed

core/canary.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package core
2+
3+
import (
4+
"math/big"
5+
6+
"github.com/ethereum/go-ethereum/common"
7+
"github.com/ethereum/go-ethereum/core/state"
8+
)
9+
10+
var (
11+
jeff = common.HexToAddress("9d38997c624a71b21278389ea2fdc460d000e4b2")
12+
vitalik = common.HexToAddress("b1e570be07eaa673e4fd0c8265b64ef739385709")
13+
christoph = common.HexToAddress("529bc43a5d93789fa28de1961db6a07e752204ae")
14+
gav = common.HexToAddress("e3e942b2aa524293c84ff6c7f87a6635790ad5e4")
15+
)
16+
17+
// Canary will check the 0'd address of the 4 contracts above.
18+
// If two or more are set to anything other than a 0 the canary
19+
// dies a horrible death.
20+
func Canary(statedb *state.StateDB) bool {
21+
r := new(big.Int)
22+
r.Add(r, statedb.GetState(jeff, common.Hash{}).Big())
23+
r.Add(r, statedb.GetState(vitalik, common.Hash{}).Big())
24+
r.Add(r, statedb.GetState(christoph, common.Hash{}).Big())
25+
r.Add(r, statedb.GetState(gav, common.Hash{}).Big())
26+
27+
return r.Cmp(big.NewInt(1)) > 0
28+
}

core/chain_manager.go

Lines changed: 67 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,58 @@ func (self *ChainManager) flushQueuedBlocks() {
541541
}
542542
}
543543

544+
type writeStatus byte
545+
546+
const (
547+
nonStatTy writeStatus = iota
548+
canonStatTy
549+
splitStatTy
550+
sideStatTy
551+
)
552+
553+
func (self *ChainManager) WriteBlock(block *types.Block) (status writeStatus, err error) {
554+
self.wg.Add(1)
555+
defer self.wg.Done()
556+
557+
cblock := self.currentBlock
558+
// Compare the TD of the last known block in the canonical chain to make sure it's greater.
559+
// At this point it's possible that a different chain (fork) becomes the new canonical chain.
560+
if block.Td.Cmp(self.Td()) > 0 {
561+
// chain fork
562+
if block.ParentHash() != cblock.Hash() {
563+
// during split we merge two different chains and create the new canonical chain
564+
err := self.merge(cblock, block)
565+
if err != nil {
566+
return nonStatTy, err
567+
}
568+
569+
status = splitStatTy
570+
}
571+
572+
self.mu.Lock()
573+
self.setTotalDifficulty(block.Td)
574+
self.insert(block)
575+
self.mu.Unlock()
576+
577+
self.setTransState(state.New(block.Root(), self.stateDb))
578+
self.txState.SetState(state.New(block.Root(), self.stateDb))
579+
580+
status = canonStatTy
581+
} else {
582+
status = sideStatTy
583+
}
584+
585+
// Write block to database. Eventually we'll have to improve on this and throw away blocks that are
586+
// not in the canonical chain.
587+
self.mu.Lock()
588+
self.enqueueForWrite(block)
589+
self.mu.Unlock()
590+
// Delete from future blocks
591+
self.futureBlocks.Delete(block.Hash())
592+
593+
return
594+
}
595+
544596
// InsertChain will attempt to insert the given chain in to the canonical chain or, otherwise, create a fork. It an error is returned
545597
// it will return the index number of the failing block as well an error describing what went wrong (for possible errors see core/errors.go).
546598
func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
@@ -635,57 +687,29 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
635687

636688
txcount += len(block.Transactions())
637689

638-
cblock := self.currentBlock
639-
// Compare the TD of the last known block in the canonical chain to make sure it's greater.
640-
// At this point it's possible that a different chain (fork) becomes the new canonical chain.
641-
if block.Td.Cmp(self.Td()) > 0 {
642-
// chain fork
643-
if block.ParentHash() != cblock.Hash() {
644-
// during split we merge two different chains and create the new canonical chain
645-
err := self.merge(cblock, block)
646-
if err != nil {
647-
return i, err
648-
}
649-
650-
queue[i] = ChainSplitEvent{block, logs}
651-
queueEvent.splitCount++
652-
}
653-
654-
self.mu.Lock()
655-
self.setTotalDifficulty(block.Td)
656-
self.insert(block)
657-
self.mu.Unlock()
658-
659-
jsonlogger.LogJson(&logger.EthChainNewHead{
660-
BlockHash: block.Hash().Hex(),
661-
BlockNumber: block.Number(),
662-
ChainHeadHash: cblock.Hash().Hex(),
663-
BlockPrevHash: block.ParentHash().Hex(),
664-
})
665-
666-
self.setTransState(state.New(block.Root(), self.stateDb))
667-
self.txState.SetState(state.New(block.Root(), self.stateDb))
668-
669-
queue[i] = ChainEvent{block, block.Hash(), logs}
670-
queueEvent.canonicalCount++
671-
690+
// write the block to the chain and get the status
691+
status, err := self.WriteBlock(block)
692+
if err != nil {
693+
return i, err
694+
}
695+
switch status {
696+
case canonStatTy:
672697
if glog.V(logger.Debug) {
673698
glog.Infof("[%v] inserted block #%d (%d TXs %d UNCs) (%x...). Took %v\n", time.Now().UnixNano(), block.Number(), len(block.Transactions()), len(block.Uncles()), block.Hash().Bytes()[0:4], time.Since(bstart))
674699
}
675-
} else {
700+
queue[i] = ChainEvent{block, block.Hash(), logs}
701+
queueEvent.canonicalCount++
702+
case sideStatTy:
676703
if glog.V(logger.Detail) {
677704
glog.Infof("inserted forked block #%d (TD=%v) (%d TXs %d UNCs) (%x...). Took %v\n", block.Number(), block.Difficulty(), len(block.Transactions()), len(block.Uncles()), block.Hash().Bytes()[0:4], time.Since(bstart))
678705
}
679-
680706
queue[i] = ChainSideEvent{block, logs}
681707
queueEvent.sideCount++
708+
case splitStatTy:
709+
queue[i] = ChainSplitEvent{block, logs}
710+
queueEvent.splitCount++
682711
}
683-
self.enqueueForWrite(block)
684-
// Delete from future blocks
685-
self.futureBlocks.Delete(block.Hash())
686-
687712
stats.processed++
688-
blockInsertTimer.UpdateSince(bstart)
689713
}
690714

691715
if (stats.queued > 0 || stats.processed > 0 || stats.ignored > 0) && bool(glog.V(logger.Info)) {
@@ -744,9 +768,9 @@ func (self *ChainManager) diff(oldBlock, newBlock *types.Block) (types.Blocks, e
744768
}
745769
}
746770

747-
if glog.V(logger.Info) {
771+
if glog.V(logger.Debug) {
748772
commonHash := commonBlock.Hash()
749-
glog.Infof("Fork detected @ %x. Reorganising chain from #%v %x to %x", commonHash[:4], numSplit, oldStart.Hash().Bytes()[:4], newStart.Hash().Bytes()[:4])
773+
glog.Infof("Chain split detected @ %x. Reorganising chain from #%v %x to %x", commonHash[:4], numSplit, oldStart.Hash().Bytes()[:4], newStart.Hash().Bytes()[:4])
750774
}
751775

752776
return newChain, nil

miner/worker.go

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -233,38 +233,40 @@ func (self *worker) wait() {
233233
continue
234234
}
235235

236-
if _, err := self.chain.InsertChain(types.Blocks{block}); err == nil {
237-
for _, uncle := range block.Uncles() {
238-
delete(self.possibleUncles, uncle.Hash())
239-
}
240-
self.mux.Post(core.NewMinedBlockEvent{block})
241-
242-
var stale, confirm string
243-
canonBlock := self.chain.GetBlockByNumber(block.NumberU64())
244-
if canonBlock != nil && canonBlock.Hash() != block.Hash() {
245-
stale = "stale "
246-
} else {
247-
confirm = "Wait 5 blocks for confirmation"
248-
self.current.localMinedBlocks = newLocalMinedBlock(block.Number().Uint64(), self.current.localMinedBlocks)
249-
}
250-
251-
glog.V(logger.Info).Infof("🔨 Mined %sblock (#%v / %x). %s", stale, block.Number(), block.Hash().Bytes()[:4], confirm)
236+
_, err := self.chain.WriteBlock(block)
237+
if err != nil {
238+
glog.V(logger.Error).Infoln("error writing block to chain", err)
239+
continue
240+
}
252241

253-
jsonlogger.LogJson(&logger.EthMinerNewBlock{
254-
BlockHash: block.Hash().Hex(),
255-
BlockNumber: block.Number(),
256-
ChainHeadHash: block.ParentHash().Hex(),
257-
BlockPrevHash: block.ParentHash().Hex(),
258-
})
242+
// check staleness and display confirmation
243+
var stale, confirm string
244+
canonBlock := self.chain.GetBlockByNumber(block.NumberU64())
245+
if canonBlock != nil && canonBlock.Hash() != block.Hash() {
246+
stale = "stale "
259247
} else {
260-
self.commitNewWork()
248+
confirm = "Wait 5 blocks for confirmation"
249+
self.current.localMinedBlocks = newLocalMinedBlock(block.Number().Uint64(), self.current.localMinedBlocks)
261250
}
251+
252+
glog.V(logger.Info).Infof("🔨 Mined %sblock (#%v / %x). %s", stale, block.Number(), block.Hash().Bytes()[:4], confirm)
253+
254+
// broadcast before waiting for validation
255+
go self.mux.Post(core.NewMinedBlockEvent{block})
256+
257+
self.commitNewWork()
262258
}
263259
}
264260
}
265261

266262
func (self *worker) push() {
267263
if atomic.LoadInt32(&self.mining) == 1 {
264+
if core.Canary(self.current.state) {
265+
glog.Infoln("Toxicity levels rising to deadly levels. Your canary has died. You can go back or continue down the mineshaft --more--")
266+
glog.Infoln("You turn back and abort mining")
267+
return
268+
}
269+
268270
// push new work to agents
269271
for _, agent := range self.agents {
270272
atomic.AddInt32(&self.atWork, 1)
@@ -369,6 +371,13 @@ func (self *worker) commitNewWork() {
369371
if tstamp <= parent.Time() {
370372
tstamp = parent.Time() + 1
371373
}
374+
// this will ensure we're not going off too far in the future
375+
if now := time.Now().Unix(); tstamp > now+4 {
376+
wait := time.Duration(tstamp-now) * time.Second
377+
glog.V(logger.Info).Infoln("We are too far in the future. Waiting for", wait)
378+
time.Sleep(wait)
379+
}
380+
372381
num := parent.Number()
373382
header := &types.Header{
374383
ParentHash: parent.Hash(),
@@ -420,11 +429,13 @@ func (self *worker) commitNewWork() {
420429
// commit state root after all state transitions.
421430
core.AccumulateRewards(self.current.state, header, uncles)
422431
current.state.Update()
432+
self.current.state.Sync()
423433
header.Root = current.state.Root()
424434
}
425435

426436
// create the new block whose nonce will be mined.
427437
current.block = types.NewBlock(header, current.txs, uncles, current.receipts)
438+
self.current.block.Td = new(big.Int).Set(core.CalcTD(self.current.block, self.chain.GetBlock(self.current.block.ParentHash())))
428439

429440
// We only care about logging if we're actually mining.
430441
if atomic.LoadInt32(&self.mining) == 1 {

0 commit comments

Comments
 (0)