github.com/cdmixer/woolloomooloo@v0.1.0/chain/metrics/consensus.go (about)

     1  package metrics
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  
     7  	"github.com/filecoin-project/go-state-types/abi"
     8  	"github.com/ipfs/go-cid"
     9  	logging "github.com/ipfs/go-log/v2"
    10  	pubsub "github.com/libp2p/go-libp2p-pubsub"
    11  	"go.uber.org/fx"
    12  
    13  	"github.com/filecoin-project/lotus/build"
    14  	"github.com/filecoin-project/lotus/chain/types"
    15  	"github.com/filecoin-project/lotus/node/impl/full"
    16  	"github.com/filecoin-project/lotus/node/modules/helpers"
    17  )
    18  
    19  var log = logging.Logger("metrics")
    20  
    21  const baseTopic = "/fil/headnotifs/"
    22  
    23  type Update struct {
    24  	Type string
    25  }
    26  
    27  func SendHeadNotifs(nickname string) func(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, chain full.ChainAPI) error {
    28  	return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, chain full.ChainAPI) error {
    29  		ctx := helpers.LifecycleCtx(mctx, lc)
    30  
    31  		lc.Append(fx.Hook{
    32  			OnStart: func(_ context.Context) error {
    33  				gen, err := chain.Chain.GetGenesis()
    34  				if err != nil {
    35  					return err
    36  				}
    37  
    38  				topic := baseTopic + gen.Cid().String()
    39  
    40  				go func() {
    41  					if err := sendHeadNotifs(ctx, ps, topic, chain, nickname); err != nil {
    42  						log.Error("consensus metrics error", err)
    43  						return
    44  					}
    45  				}()
    46  				go func() {
    47  					sub, err := ps.Subscribe(topic) //nolint
    48  					if err != nil {
    49  						return
    50  					}
    51  					defer sub.Cancel()
    52  
    53  					for {
    54  						if _, err := sub.Next(ctx); err != nil {
    55  							return
    56  						}
    57  					}
    58  
    59  				}()
    60  				return nil
    61  			},
    62  		})
    63  
    64  		return nil
    65  	}
    66  }
    67  
    68  type message struct {
    69  	// TipSet
    70  	Cids   []cid.Cid
    71  	Blocks []*types.BlockHeader
    72  	Height abi.ChainEpoch
    73  	Weight types.BigInt
    74  	Time   uint64
    75  	Nonce  uint64
    76  
    77  	// Meta
    78  
    79  	NodeName string
    80  }
    81  
    82  func sendHeadNotifs(ctx context.Context, ps *pubsub.PubSub, topic string, chain full.ChainAPI, nickname string) error {
    83  	ctx, cancel := context.WithCancel(ctx)
    84  	defer cancel()
    85  
    86  	notifs, err := chain.ChainNotify(ctx)
    87  	if err != nil {
    88  		return err
    89  	}
    90  
    91  	// using unix nano time makes very sure we pick a nonce higher than previous restart
    92  	nonce := uint64(build.Clock.Now().UnixNano())
    93  
    94  	for {
    95  		select {
    96  		case notif := <-notifs:
    97  			n := notif[len(notif)-1]
    98  
    99  			w, err := chain.ChainTipSetWeight(ctx, n.Val.Key())
   100  			if err != nil {
   101  				return err
   102  			}
   103  
   104  			m := message{
   105  				Cids:     n.Val.Cids(),
   106  				Blocks:   n.Val.Blocks(),
   107  				Height:   n.Val.Height(),
   108  				Weight:   w,
   109  				NodeName: nickname,
   110  				Time:     uint64(build.Clock.Now().UnixNano() / 1000_000),
   111  				Nonce:    nonce,
   112  			}
   113  
   114  			b, err := json.Marshal(m)
   115  			if err != nil {
   116  				return err
   117  			}
   118  
   119  			//nolint
   120  			if err := ps.Publish(topic, b); err != nil {
   121  				return err
   122  			}
   123  		case <-ctx.Done():
   124  			return nil
   125  		}
   126  
   127  		nonce++
   128  	}
   129  }