8
8
"os"
9
9
"runtime"
10
10
"sync"
11
+ "sync/atomic"
11
12
"time"
12
13
13
14
"github.com/ethereum/go-ethereum/common"
@@ -100,9 +101,10 @@ type ChainManager struct {
100
101
cache * BlockCache
101
102
futureBlocks * BlockCache
102
103
103
- quit chan struct {}
104
- procInterupt chan struct {} // interupt signaler for block processing
105
- wg sync.WaitGroup
104
+ quit chan struct {}
105
+ // procInterrupt must be atomically called
106
+ procInterrupt int32 // interrupt signaler for block processing
107
+ wg sync.WaitGroup
106
108
107
109
pow pow.PoW
108
110
}
@@ -114,7 +116,6 @@ func NewChainManager(genesis *types.Block, blockDb, stateDb common.Database, pow
114
116
genesisBlock : GenesisBlock (42 , stateDb ),
115
117
eventMux : mux ,
116
118
quit : make (chan struct {}),
117
- procInterupt : make (chan struct {}),
118
119
cache : NewBlockCache (blockCacheLimit ),
119
120
pow : pow ,
120
121
}
@@ -518,7 +519,7 @@ func (self *ChainManager) CalcTotalDiff(block *types.Block) (*big.Int, error) {
518
519
519
520
func (bc * ChainManager ) Stop () {
520
521
close (bc .quit )
521
- close ( bc .procInterupt )
522
+ atomic . StoreInt32 ( & bc .procInterrupt , 1 )
522
523
523
524
bc .wg .Wait ()
524
525
@@ -571,126 +572,124 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
571
572
defer close (nonceQuit )
572
573
573
574
txcount := 0
574
- done:
575
575
for i , block := range chain {
576
- select {
577
- case <- self .procInterupt :
576
+ if atomic .LoadInt32 (& self .procInterrupt ) == 1 {
578
577
glog .V (logger .Debug ).Infoln ("Premature abort during chain processing" )
579
- break done
580
- default :
581
- bstart := time .Now ()
582
- // Wait for block i's nonce to be verified before processing
583
- // its state transition.
584
- for ! nonceChecked [i ] {
585
- r := <- nonceDone
586
- nonceChecked [r .i ] = true
587
- if ! r .valid {
588
- block := chain [r .i ]
589
- return r .i , & BlockNonceErr {Hash : block .Hash (), Number : block .Number (), Nonce : block .Nonce ()}
590
- }
591
- }
578
+ break
579
+ }
592
580
593
- if BadHashes [block .Hash ()] {
594
- err := fmt .Errorf ("Found known bad hash in chain %x" , block .Hash ())
595
- blockErr (block , err )
596
- return i , err
581
+ bstart := time .Now ()
582
+ // Wait for block i's nonce to be verified before processing
583
+ // its state transition.
584
+ for ! nonceChecked [i ] {
585
+ r := <- nonceDone
586
+ nonceChecked [r .i ] = true
587
+ if ! r .valid {
588
+ block := chain [r .i ]
589
+ return r .i , & BlockNonceErr {Hash : block .Hash (), Number : block .Number (), Nonce : block .Nonce ()}
597
590
}
591
+ }
598
592
599
- // Setting block.Td regardless of error (known for example) prevents errors down the line
600
- // in the protocol handler
601
- block .Td = new (big.Int ).Set (CalcTD (block , self .GetBlock (block .ParentHash ())))
602
-
603
- // Call in to the block processor and check for errors. It's likely that if one block fails
604
- // all others will fail too (unless a known block is returned).
605
- logs , err := self .processor .Process (block )
606
- if err != nil {
607
- if IsKnownBlockErr (err ) {
608
- stats .ignored ++
609
- continue
610
- }
611
-
612
- if err == BlockFutureErr {
613
- // Allow up to MaxFuture second in the future blocks. If this limit
614
- // is exceeded the chain is discarded and processed at a later time
615
- // if given.
616
- if max := time .Now ().Unix () + maxTimeFutureBlocks ; block .Time () > max {
617
- return i , fmt .Errorf ("%v: BlockFutureErr, %v > %v" , BlockFutureErr , block .Time (), max )
618
- }
593
+ if BadHashes [block .Hash ()] {
594
+ err := fmt .Errorf ("Found known bad hash in chain %x" , block .Hash ())
595
+ blockErr (block , err )
596
+ return i , err
597
+ }
619
598
620
- block .SetQueued (true )
621
- self .futureBlocks .Push (block )
622
- stats .queued ++
623
- continue
624
- }
599
+ // Setting block.Td regardless of error (known for example) prevents errors down the line
600
+ // in the protocol handler
601
+ block .Td = new (big.Int ).Set (CalcTD (block , self .GetBlock (block .ParentHash ())))
602
+
603
+ // Call in to the block processor and check for errors. It's likely that if one block fails
604
+ // all others will fail too (unless a known block is returned).
605
+ logs , err := self .processor .Process (block )
606
+ if err != nil {
607
+ if IsKnownBlockErr (err ) {
608
+ stats .ignored ++
609
+ continue
610
+ }
625
611
626
- if IsParentErr (err ) && self .futureBlocks .Has (block .ParentHash ()) {
627
- block .SetQueued (true )
628
- self .futureBlocks .Push (block )
629
- stats .queued ++
630
- continue
612
+ if err == BlockFutureErr {
613
+ // Allow up to MaxFuture second in the future blocks. If this limit
614
+ // is exceeded the chain is discarded and processed at a later time
615
+ // if given.
616
+ if max := time .Now ().Unix () + maxTimeFutureBlocks ; block .Time () > max {
617
+ return i , fmt .Errorf ("%v: BlockFutureErr, %v > %v" , BlockFutureErr , block .Time (), max )
631
618
}
632
619
633
- blockErr (block , err )
620
+ block .SetQueued (true )
621
+ self .futureBlocks .Push (block )
622
+ stats .queued ++
623
+ continue
624
+ }
634
625
635
- return i , err
626
+ if IsParentErr (err ) && self .futureBlocks .Has (block .ParentHash ()) {
627
+ block .SetQueued (true )
628
+ self .futureBlocks .Push (block )
629
+ stats .queued ++
630
+ continue
636
631
}
637
632
638
- txcount += len (block .Transactions ())
639
-
640
- cblock := self .currentBlock
641
- // Compare the TD of the last known block in the canonical chain to make sure it's greater.
642
- // At this point it's possible that a different chain (fork) becomes the new canonical chain.
643
- if block .Td .Cmp (self .Td ()) > 0 {
644
- // chain fork
645
- if block .ParentHash () != cblock .Hash () {
646
- // during split we merge two different chains and create the new canonical chain
647
- err := self .merge (cblock , block )
648
- if err != nil {
649
- return i , err
650
- }
633
+ blockErr (block , err )
634
+
635
+ return i , err
636
+ }
651
637
652
- queue [i ] = ChainSplitEvent {block , logs }
653
- queueEvent .splitCount ++
638
+ txcount += len (block .Transactions ())
639
+
640
+ cblock := self .currentBlock
641
+ // Compare the TD of the last known block in the canonical chain to make sure it's greater.
642
+ // At this point it's possible that a different chain (fork) becomes the new canonical chain.
643
+ if block .Td .Cmp (self .Td ()) > 0 {
644
+ // chain fork
645
+ if block .ParentHash () != cblock .Hash () {
646
+ // during split we merge two different chains and create the new canonical chain
647
+ err := self .merge (cblock , block )
648
+ if err != nil {
649
+ return i , err
654
650
}
655
651
656
- self .mu .Lock ()
657
- self .setTotalDifficulty (block .Td )
658
- self .insert (block )
659
- self .mu .Unlock ()
652
+ queue [i ] = ChainSplitEvent {block , logs }
653
+ queueEvent .splitCount ++
654
+ }
660
655
661
- jsonlogger .LogJson (& logger.EthChainNewHead {
662
- BlockHash : block .Hash ().Hex (),
663
- BlockNumber : block .Number (),
664
- ChainHeadHash : cblock .Hash ().Hex (),
665
- BlockPrevHash : block .ParentHash ().Hex (),
666
- })
656
+ self .mu .Lock ()
657
+ self .setTotalDifficulty (block .Td )
658
+ self .insert (block )
659
+ self .mu .Unlock ()
667
660
668
- self .setTransState (state .New (block .Root (), self .stateDb ))
669
- self .txState .SetState (state .New (block .Root (), self .stateDb ))
661
+ jsonlogger .LogJson (& logger.EthChainNewHead {
662
+ BlockHash : block .Hash ().Hex (),
663
+ BlockNumber : block .Number (),
664
+ ChainHeadHash : cblock .Hash ().Hex (),
665
+ BlockPrevHash : block .ParentHash ().Hex (),
666
+ })
670
667
671
- queue [ i ] = ChainEvent { block , block . Hash (), logs }
672
- queueEvent . canonicalCount ++
668
+ self . setTransState ( state . New ( block . Root (), self . stateDb ))
669
+ self . txState . SetState ( state . New ( block . Root (), self . stateDb ))
673
670
674
- if glog .V (logger .Debug ) {
675
- 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 ))
676
- }
677
- } else {
678
- if glog .V (logger .Detail ) {
679
- 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 ))
680
- }
671
+ queue [i ] = ChainEvent {block , block .Hash (), logs }
672
+ queueEvent .canonicalCount ++
681
673
682
- queue [i ] = ChainSideEvent {block , logs }
683
- queueEvent .sideCount ++
674
+ if glog .V (logger .Debug ) {
675
+ 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 ))
676
+ }
677
+ } else {
678
+ if glog .V (logger .Detail ) {
679
+ 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 ))
684
680
}
685
- // Write block to database. Eventually we'll have to improve on this and throw away blocks that are
686
- // not in the canonical chain.
687
- self .write (block )
688
- // Delete from future blocks
689
- self .futureBlocks .Delete (block .Hash ())
690
-
691
- stats .processed ++
692
681
682
+ queue [i ] = ChainSideEvent {block , logs }
683
+ queueEvent .sideCount ++
693
684
}
685
+ // Write block to database. Eventually we'll have to improve on this and throw away blocks that are
686
+ // not in the canonical chain.
687
+ self .write (block )
688
+ // Delete from future blocks
689
+ self .futureBlocks .Delete (block .Hash ())
690
+
691
+ stats .processed ++
692
+
694
693
}
695
694
696
695
if (stats .queued > 0 || stats .processed > 0 || stats .ignored > 0 ) && bool (glog .V (logger .Info )) {
0 commit comments