@@ -488,8 +488,10 @@ export default class Blockchain implements BlockchainInterface {
488
488
489
489
await this . dbManager . batch ( dbOps )
490
490
// Output active signers for debugging purposes
491
- for ( const [ i , signer ] of this . cliqueActiveSigners ( ) . entries ( ) ) {
491
+ let i = 0
492
+ for ( const signer of this . cliqueActiveSigners ( ) ) {
492
493
debug ( `Clique signer [${ i } ]: ${ signer } ` )
494
+ i ++
493
495
}
494
496
}
495
497
@@ -506,63 +508,34 @@ export default class Blockchain implements BlockchainInterface {
506
508
const nonce = header . nonce
507
509
const latestVote : CliqueVote = [ header . number , [ signer , beneficiary , nonce ] ]
508
510
509
- const alreadyVoted = this . _cliqueLatestVotes . find ( ( vote ) => {
510
- return (
511
- vote [ 1 ] [ 0 ] . equals ( signer ) && vote [ 1 ] [ 1 ] . equals ( beneficiary ) && vote [ 1 ] [ 2 ] . equals ( nonce )
512
- )
513
- } )
514
- ? true
515
- : false
516
-
517
- // Always add the latest vote to the history no matter if already voted
518
- // the same vote or not
519
- this . _cliqueLatestVotes . push ( latestVote )
520
- debug (
521
- `[Block ${ header . number . toNumber ( ) } ] New clique vote: ${ signer } -> ${ beneficiary } ${
522
- nonce . equals ( CLIQUE_NONCE_AUTH ) ? 'AUTH' : 'DROP'
523
- } `
524
- )
525
-
526
- // remove any opposite votes for [signer, beneficiary]
527
- const oppositeNonce = nonce . equals ( CLIQUE_NONCE_AUTH ) ? CLIQUE_NONCE_DROP : CLIQUE_NONCE_AUTH
528
- this . _cliqueLatestVotes = this . _cliqueLatestVotes . filter (
529
- ( vote ) =>
530
- ! (
531
- vote [ 1 ] [ 0 ] . equals ( signer ) &&
532
- vote [ 1 ] [ 1 ] . equals ( beneficiary ) &&
533
- vote [ 1 ] [ 2 ] . equals ( oppositeNonce )
534
- )
535
- )
511
+ // Do two rounds here, one to execute on a potential previously reached consensus
512
+ // on the newly touched beneficiary, one with the added new vote
513
+ for ( let round = 1 ; round <= 2 ; round ++ ) {
536
514
537
- // If same vote not already in history see if there is a new majority consensus
538
- // to update the signer list
539
- if ( ! alreadyVoted ) {
515
+ // See if there is a new majority consensus to update the signer list
540
516
const lastEpochBlockNumber = header . number . sub (
541
517
header . number . mod ( new BN ( this . _common . consensusConfig ( ) . epoch ) )
542
518
)
543
- const beneficiaryVotesAuth = this . _cliqueLatestVotes . filter (
544
- ( vote ) =>
545
- vote [ 0 ] . gte ( lastEpochBlockNumber ) &&
546
- vote [ 1 ] [ 1 ] . equals ( beneficiary ) &&
547
- vote [ 1 ] [ 2 ] . equals ( CLIQUE_NONCE_AUTH )
548
- )
549
- const beneficiaryVotesDrop = this . _cliqueLatestVotes . filter (
550
- ( vote ) =>
551
- vote [ 0 ] . gte ( lastEpochBlockNumber ) &&
552
- vote [ 1 ] [ 1 ] . equals ( beneficiary ) &&
553
- vote [ 1 ] [ 2 ] . equals ( CLIQUE_NONCE_DROP )
554
- )
555
519
const limit = this . cliqueSignerLimit ( )
556
- const consensus =
557
- beneficiaryVotesAuth . length >= limit || beneficiaryVotesDrop . length >= limit
558
- const auth = beneficiaryVotesAuth . length >= limit
559
- // Majority consensus
560
- if ( consensus ) {
561
- debug (
562
- `[Block ${ header . number . toNumber ( ) } ] Clique majority consensus -> update signer states`
563
- )
564
- let activeSigners = this . cliqueActiveSigners ( )
565
- if ( auth ) {
520
+ let activeSigners = this . cliqueActiveSigners ( )
521
+ let consensus = false
522
+
523
+ // AUTH vote analysis
524
+ if ( round === 1 || round === 2 && nonce . equals ( CLIQUE_NONCE_AUTH ) ) {
525
+ let beneficiaryVotesAUTH = this . _cliqueLatestVotes . filter ( ( vote ) => {
526
+ return (
527
+ vote [ 0 ] . gte ( lastEpochBlockNumber ) &&
528
+ ! vote [ 1 ] [ 0 ] . equals ( signer ) &&
529
+ vote [ 1 ] [ 1 ] . equals ( beneficiary ) &&
530
+ vote [ 1 ] [ 2 ] . equals ( CLIQUE_NONCE_AUTH )
531
+ )
532
+ } ) . length
533
+ if ( round === 2 && nonce . equals ( CLIQUE_NONCE_AUTH ) ) {
534
+ beneficiaryVotesAUTH += 1
535
+ }
536
+ // Majority consensus
537
+ if ( beneficiaryVotesAUTH >= limit ) {
538
+ consensus = true
566
539
// Authorize new signer
567
540
activeSigners . push ( beneficiary )
568
541
activeSigners . sort ( ( a , b ) => {
@@ -573,16 +546,61 @@ export default class Blockchain implements BlockchainInterface {
573
546
this . _cliqueLatestVotes = this . _cliqueLatestVotes . filter (
574
547
( vote ) => ! vote [ 1 ] [ 1 ] . equals ( beneficiary )
575
548
)
576
- } else {
549
+ debug (
550
+ `[Block ${ header . number . toNumber ( ) } ] Clique majority consensus (AUTH ${ beneficiary } )`
551
+ )
552
+ }
553
+ }
554
+ // DROP vote
555
+ if ( round === 1 || round === 2 && nonce . equals ( CLIQUE_NONCE_DROP ) ) {
556
+ let beneficiaryVotesDROP = this . _cliqueLatestVotes . filter ( ( vote ) => {
557
+ return (
558
+ vote [ 0 ] . gte ( lastEpochBlockNumber ) &&
559
+ ! vote [ 1 ] [ 0 ] . equals ( signer ) &&
560
+ vote [ 1 ] [ 1 ] . equals ( beneficiary ) &&
561
+ vote [ 1 ] [ 2 ] . equals ( CLIQUE_NONCE_DROP )
562
+ )
563
+ } ) . length
564
+ if ( round === 2 && nonce . equals ( CLIQUE_NONCE_DROP ) ) {
565
+ beneficiaryVotesDROP += 1
566
+ }
567
+ // Majority consensus
568
+ if ( beneficiaryVotesDROP >= limit ) {
569
+ consensus = true
577
570
// Drop signer
578
571
activeSigners = activeSigners . filter ( ( signer ) => ! signer . equals ( beneficiary ) )
579
572
// Discard votes from removed signer
580
573
this . _cliqueLatestVotes = this . _cliqueLatestVotes . filter (
581
574
( vote ) => ! vote [ 1 ] [ 0 ] . equals ( beneficiary )
582
575
)
576
+ debug (
577
+ `[Block ${ header . number . toNumber ( ) } ] Clique majority consensus (DROP ${ beneficiary } )`
578
+ )
579
+ }
580
+ }
581
+ if ( round === 1 ) {
582
+ // Always add the latest vote to the history no matter if already voted
583
+ // the same vote or not
584
+ this . _cliqueLatestVotes . push ( latestVote )
585
+ debug (
586
+ `[Block ${ header . number . toNumber ( ) } ] New clique vote: ${ signer } -> ${ beneficiary } ${
587
+ nonce . equals ( CLIQUE_NONCE_AUTH ) ? 'AUTH' : 'DROP'
588
+ } `
589
+ )
590
+ }
591
+ if ( consensus ) {
592
+ if ( round === 1 ) {
593
+ debug (
594
+ `[Block ${ header . number . toNumber ( ) } ] Clique majority consensus on existing votes -> update signer states`
595
+ )
596
+ } else {
597
+ debug (
598
+ `[Block ${ header . number . toNumber ( ) } ] Clique majority consensus on new vote -> update signer states`
599
+ )
583
600
}
584
601
const newSignerState : CliqueSignerState = [ header . number , activeSigners ]
585
602
await this . cliqueUpdateSignerStates ( newSignerState )
603
+ return
586
604
}
587
605
}
588
606
}
@@ -843,11 +861,7 @@ export default class Blockchain implements BlockchainInterface {
843
861
844
862
if ( this . _validateBlocks && ! isGenesis ) {
845
863
// this calls into `getBlock`, which is why we cannot lock yet
846
- if ( item instanceof BlockHeader ) {
847
- await block . header . validate ( this )
848
- } else {
849
- await block . validate ( this )
850
- }
864
+ await block . validate ( this )
851
865
}
852
866
853
867
if ( this . _validateConsensus ) {
0 commit comments