Skip to content

ethstats/ethstats.go

Type MOD
Upstream Lines 844
Changed +33 -4

Add GetTd to the backend interface and report total difficulty (with nil-safe fallback); restore the mining/hashrate node stats (verbatim revert of the #28623 ethstats hunks)

diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go
index c17e22516..7784f7072 100644
--- a/ethstats/ethstats.go
+++ b/ethstats/ethstats.go
@@ -39,6 +39,7 @@ import (
    ethproto "github.com/ethereum/go-ethereum/eth/protocols/eth"
    "github.com/ethereum/go-ethereum/event"
    "github.com/ethereum/go-ethereum/log"
+   "github.com/ethereum/go-ethereum/miner"
    "github.com/ethereum/go-ethereum/node"
    "github.com/ethereum/go-ethereum/p2p"
    "github.com/ethereum/go-ethereum/rpc"
@@ -66,6 +67,7 @@ type backend interface {
    SubscribeNewPayloadEvent(ch chan<- core.NewPayloadEvent) event.Subscription
    CurrentHeader() *types.Header
    HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error)
+   GetTd(ctx context.Context, hash common.Hash) *big.Int
    Stats() (pending int, queued int)
    SyncProgress(ctx context.Context) ethereum.SyncProgress
 }
@@ -79,6 +81,13 @@ type fullNodeBackend interface {
    SuggestGasTipCap(ctx context.Context) (*big.Int, error)
 }

+// miningNodeBackend encompasses the functionality necessary for a mining node
+// reporting to ethstats
+type miningNodeBackend interface {
+   fullNodeBackend
+   Miner() *miner.Miner
+}
+
 // Service implements an Ethereum netstats reporting daemon that pushes local
 // chain statistics up to a monitoring server.
 type Service struct {
@@ -673,6 +682,7 @@ func (s *Service) reportBlock(conn *connWrapper, header *types.Header) error {
 func (s *Service) assembleBlockStats(header *types.Header) *blockStats {
    // Gather the block infos from the local blockchain
    var (
+       td     *big.Int
        txs    []txStats
        uncles []*types.Header
    )
@@ -688,6 +698,7 @@ func (s *Service) assembleBlockStats(header *types.Header) *blockStats {
        if block == nil {
            return nil
        }
+       td = s.backend.GetTd(context.Background(), header.Hash())
        txs = make([]txStats, len(block.Transactions()))
        for i, tx := range block.Transactions() {
            txs[i].Hash = tx.Hash()
@@ -698,11 +709,18 @@ func (s *Service) assembleBlockStats(header *types.Header) *blockStats {
        if header == nil {
            header = s.backend.CurrentHeader()
        }
+       td = s.backend.GetTd(context.Background(), header.Hash())
        txs = []txStats{}
    }
    // Assemble and return the block stats
    author, _ := s.engine.Author(header)

+   // Handle nil TD gracefully (shouldn't happen but be safe)
+   tdStr := "0"
+   if td != nil {
+       tdStr = td.String()
+   }
+
    return &blockStats{
        Number:     header.Number,
        Hash:       header.Hash(),
@@ -712,7 +730,7 @@ func (s *Service) assembleBlockStats(header *types.Header) *blockStats {
        GasUsed:    header.GasUsed,
        GasLimit:   header.GasLimit,
        Diff:       header.Difficulty.String(),
-       TotalDiff:  "0", // unknown post-merge with pruned chain tail
+       TotalDiff:  tdStr,
        Txs:        txs,
        TxHash:     header.TxHash,
        Root:       header.Root,
@@ -797,21 +815,30 @@ func (s *Service) reportPending(conn *connWrapper) error {
 type nodeStats struct {
    Active   bool `json:"active"`
    Syncing  bool `json:"syncing"`
+   Mining   bool `json:"mining"`
+   Hashrate int  `json:"hashrate"`
    Peers    int  `json:"peers"`
    GasPrice int  `json:"gasPrice"`
    Uptime   int  `json:"uptime"`
 }

-// reportStats retrieves various stats about the node at the networking layer
-// and reports it to the stats server.
+// reportStats retrieves various stats about the node at the networking and
+// mining layer and reports it to the stats server.
 func (s *Service) reportStats(conn *connWrapper) error {
-   // Gather the syncing infos from the local miner instance
+   // Gather the syncing and mining infos from the local miner instance
    var (
+       mining   bool
+       hashrate int
        syncing  bool
        gasprice int
    )
    // check if backend is a full node
    if fullBackend, ok := s.backend.(fullNodeBackend); ok {
+       if miningBackend, ok := s.backend.(miningNodeBackend); ok {
+           mining = miningBackend.Miner().Mining()
+           hashrate = int(miningBackend.Miner().Hashrate())
+       }
+
        sync := fullBackend.SyncProgress(context.Background())
        syncing = !sync.Done()

@@ -831,6 +858,8 @@ func (s *Service) reportStats(conn *connWrapper) error {
        "id": s.node,
        "stats": &nodeStats{
            Active:   true,
+           Mining:   mining,
+           Hashrate: hashrate,
            Peers:    s.server.PeerCount(),
            GasPrice: gasprice,
            Syncing:  syncing,

← Back to RPC & API