@@ -43,6 +43,7 @@ import (
4343 "github.com/ethereum/go-ethereum/miner"
4444 "github.com/ethereum/go-ethereum/node"
4545 "github.com/ethereum/go-ethereum/p2p"
46+ "github.com/ethereum/go-ethereum/params"
4647 "github.com/ethereum/go-ethereum/rpc"
4748 "github.com/gorilla/websocket"
4849)
@@ -70,6 +71,8 @@ type backend interface {
7071 GetTd (ctx context.Context , hash common.Hash ) * big.Int
7172 Stats () (pending int , queued int )
7273 SyncProgress () ethereum.SyncProgress
74+ // ADDED by Jakub Pajek (ethstats votes count)
75+ ChainConfig () * params.ChainConfig
7376}
7477
7578// fullNodeBackend encompasses the functionality necessary for a full node
@@ -585,6 +588,8 @@ type blockStats struct {
585588 TxHash common.Hash `json:"transactionsRoot"`
586589 Root common.Hash `json:"stateRoot"`
587590 Uncles uncleStats `json:"uncles"`
591+ // ADDED by Jakub Pajek (ethstats votes count)
592+ Votes voteStats `json:"votes"`
588593}
589594
590595// txStats is the information to report about individual transactions.
@@ -603,6 +608,55 @@ func (s uncleStats) MarshalJSON() ([]byte, error) {
603608 return []byte ("[]" ), nil
604609}
605610
611+ // ADDED by Jakub Pajek BEG (ethstats votes count)
612+
613+ type vote struct {
614+ Address common.Address `json:"address"`
615+ Proposal string `json:"proposal"`
616+ }
617+
618+ // voteStats is a custom wrapper around an vote array to force serializing
619+ // empty arrays instead of returning null for them.
620+ type voteStats []vote
621+
622+ func (s voteStats ) MarshalJSON () ([]byte , error ) {
623+ if votes := ([]vote )(s ); len (votes ) > 0 {
624+ return json .Marshal (votes )
625+ }
626+ return []byte ("[]" ), nil
627+ }
628+
629+ // isTTDReached checks if the TotalTerminalDifficulty has been surpassed on the `parentHash` block.
630+ // It depends on the parentHash already being stored in the database.
631+ // If the parentHash is not stored in the database a UnknownAncestor error is returned.
632+ func (s * Service ) isTTDReached (parentHash common.Hash ) (bool , error ) {
633+ ttd := s .backend .ChainConfig ().TerminalTotalDifficulty
634+ if ttd == nil {
635+ return false , nil
636+ }
637+ td := s .backend .GetTd (context .Background (), parentHash )
638+ if td == nil {
639+ return false , consensus .ErrUnknownAncestor
640+ }
641+ return td .Cmp (ttd ) >= 0 , nil
642+ }
643+
644+ // poaEngine returns the PoA consensus engine, or nil if PoW or PoS is being used.
645+ func (s * Service ) poaEngine (header * types.Header ) consensus.PoA {
646+ if pos , ok := s .engine .(consensus.PoS ); ok {
647+ if poa , ok := pos .EthOneEngine ().(consensus.PoA ); ok {
648+ if reached , err := s .isTTDReached (header .ParentHash ); err == nil && ! reached {
649+ return poa
650+ }
651+ }
652+ } else if poa , ok := s .engine .(consensus.PoA ); ok {
653+ return poa
654+ }
655+ return nil
656+ }
657+
658+ // ADDED by Jakub Pajek END (ethstats votes count)
659+
606660// reportBlock retrieves the current chain head and reports it to the stats server.
607661func (s * Service ) reportBlock (conn * connWrapper , block * types.Block ) error {
608662 // Gather the block details from the header or block chain
@@ -630,6 +684,8 @@ func (s *Service) assembleBlockStats(block *types.Block) *blockStats {
630684 td * big.Int
631685 txs []txStats
632686 uncles []* types.Header
687+ // ADDED by Jakub Pajek (ethstats votes count)
688+ votes []vote
633689 )
634690
635691 // check if backend is a full node
@@ -665,6 +721,45 @@ func (s *Service) assembleBlockStats(block *types.Block) *blockStats {
665721 txs = []txStats {}
666722 }
667723
724+ // ADDED by Jakub Pajek BEG (ethstats votes count)
725+ if poa , cliqueCfg := s .poaEngine (header ), s .backend .ChainConfig ().Clique ; poa != nil && cliqueCfg != nil {
726+ // MEMO by Jakub Pajek (clique config: variable period)
727+ // How to handle variable epoch changing with the number of sealers?
728+ cliqueEpoch := cliqueCfg [0 ].Epoch
729+ if cliqueEpoch == 0 {
730+ cliqueEpoch = params .CliqueEpoch
731+ }
732+ if checkpoint , extraBytes := header .Number .Uint64 ()% cliqueEpoch == 0 , len (header .Extra )- params .CliqueExtraVanity - params .CliqueExtraSeal ; ! checkpoint && extraBytes > 0 {
733+ voteCount := extraBytes / (common .AddressLength + 1 )
734+ votes = make ([]vote , voteCount )
735+ for voteIdx := 0 ; voteIdx < voteCount ; voteIdx ++ {
736+ // Get the address of the vote
737+ index := params .CliqueExtraVanity + voteIdx * (common .AddressLength + 1 )
738+ var address common.Address
739+ copy (address [:], header .Extra [index :])
740+ // Get the proposal of the vote
741+ index += common .AddressLength
742+ var proposal string
743+ switch header .Extra [index ] {
744+ case params .CliqueExtraVoterVote :
745+ proposal = "voter"
746+ case params .CliqueExtraSignerVote :
747+ proposal = "signer"
748+ case params .CliqueExtraDropVote :
749+ proposal = "drop"
750+ default :
751+ proposal = "unknown"
752+ }
753+ // Add the vote
754+ votes [voteIdx ] = vote {
755+ Address : address ,
756+ Proposal : proposal ,
757+ }
758+ }
759+ }
760+ }
761+ // ADDED by Jakub Pajek END (ethstats votes count)
762+
668763 // Assemble and return the block stats
669764 author , _ := s .engine .Author (header )
670765
@@ -682,6 +777,8 @@ func (s *Service) assembleBlockStats(block *types.Block) *blockStats {
682777 TxHash : header .TxHash ,
683778 Root : header .Root ,
684779 Uncles : uncles ,
780+ // ADDED by Jakub Pajek (ethstats votes count)
781+ Votes : votes ,
685782 }
686783}
687784
0 commit comments