Skip to content

Commit cac0ef0

Browse files
committed
ethstats: added votes count to block stats (#2)
ethstats: added votes count to block stats
1 parent 2548bae commit cac0ef0

File tree

1 file changed

+97
-0
lines changed

1 file changed

+97
-0
lines changed

ethstats/ethstats.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
607661
func (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

Comments
 (0)