github.com/mavryk-network/mvgo@v1.19.9/rpc/monitor.go (about)

     1  // Copyright (c) 2020-2022 Blockwatch Data Inc.
     2  // Author: alex@blockwatch.cc
     3  
     4  package rpc
     5  
     6  import (
     7  	"context"
     8  	"encoding/binary"
     9  	"errors"
    10  	"io"
    11  	"time"
    12  
    13  	"github.com/mavryk-network/mvgo/mavryk"
    14  )
    15  
    16  var ErrMonitorClosed = errors.New("monitor closed")
    17  
    18  type Monitor interface {
    19  	New() interface{}
    20  	Send(ctx context.Context, val interface{})
    21  	Err(error)
    22  	Closed() <-chan struct{}
    23  	Close()
    24  }
    25  
    26  // BootstrappedBlock represents bootstrapped block stream message
    27  type BootstrappedBlock struct {
    28  	Block     mavryk.BlockHash `json:"block"`
    29  	Timestamp time.Time        `json:"timestamp"`
    30  }
    31  
    32  type BootstrapMonitor struct {
    33  	result chan *BootstrappedBlock
    34  	closed chan struct{}
    35  	err    error
    36  }
    37  
    38  // make sure BootstrapMonitor implements Monitor interface
    39  var _ Monitor = (*BootstrapMonitor)(nil)
    40  
    41  func NewBootstrapMonitor() *BootstrapMonitor {
    42  	return &BootstrapMonitor{
    43  		result: make(chan *BootstrappedBlock),
    44  		closed: make(chan struct{}),
    45  	}
    46  }
    47  
    48  func (m *BootstrapMonitor) New() interface{} {
    49  	return &BootstrappedBlock{}
    50  }
    51  
    52  func (m *BootstrapMonitor) Send(ctx context.Context, val interface{}) {
    53  	select {
    54  	case <-m.closed:
    55  		return
    56  	default:
    57  	}
    58  	select {
    59  	case <-ctx.Done():
    60  	case <-m.closed:
    61  	case m.result <- val.(*BootstrappedBlock):
    62  	}
    63  }
    64  
    65  func (m *BootstrapMonitor) Recv(ctx context.Context) (*BootstrappedBlock, error) {
    66  	select {
    67  	case <-ctx.Done():
    68  		return nil, ctx.Err()
    69  	case <-m.closed:
    70  		err := m.err
    71  		if err == nil {
    72  			err = ErrMonitorClosed
    73  		}
    74  		return nil, err
    75  	case res, ok := <-m.result:
    76  		if !ok {
    77  			if m.err != nil {
    78  				return nil, m.err
    79  			}
    80  			return nil, io.EOF
    81  		}
    82  		return res, nil
    83  	}
    84  }
    85  
    86  func (m *BootstrapMonitor) Err(err error) {
    87  	m.err = err
    88  	m.Close()
    89  }
    90  
    91  func (m *BootstrapMonitor) Closed() <-chan struct{} {
    92  	return m.closed
    93  }
    94  
    95  func (m *BootstrapMonitor) Close() {
    96  	select {
    97  	case <-m.closed:
    98  		return
    99  	default:
   100  	}
   101  	close(m.closed)
   102  	close(m.result)
   103  }
   104  
   105  // BlockHeaderLogEntry is a log entry returned for a new block when monitoring
   106  type BlockHeaderLogEntry struct {
   107  	Hash           mavryk.BlockHash      `json:"hash"`
   108  	Level          int64                 `json:"level"`
   109  	Proto          int                   `json:"proto"`
   110  	Predecessor    mavryk.BlockHash      `json:"predecessor"`
   111  	Timestamp      time.Time             `json:"timestamp"`
   112  	ValidationPass int                   `json:"validation_pass"`
   113  	OperationsHash mavryk.OpListListHash `json:"operations_hash"`
   114  	Fitness        []mavryk.HexBytes     `json:"fitness"`
   115  	Context        mavryk.ContextHash    `json:"context"`
   116  	ProtocolData   mavryk.HexBytes       `json:"protocol_data"`
   117  }
   118  
   119  func (h *BlockHeader) LogEntry() *BlockHeaderLogEntry {
   120  	return &BlockHeaderLogEntry{
   121  		Hash:           h.Hash,
   122  		Level:          h.Level,
   123  		Proto:          h.Proto,
   124  		Predecessor:    h.Predecessor,
   125  		Timestamp:      h.Timestamp,
   126  		ValidationPass: h.ValidationPass,
   127  		OperationsHash: h.OperationsHash,
   128  		Fitness:        h.Fitness,
   129  		Context:        h.Context,
   130  		ProtocolData:   mavryk.HexBytes(h.ProtocolData()),
   131  	}
   132  }
   133  
   134  func (l BlockHeaderLogEntry) Round() int {
   135  	return int(binary.BigEndian.Uint32(l.ProtocolData[32:]))
   136  }
   137  
   138  func (l BlockHeaderLogEntry) PayloadHash() (h mavryk.PayloadHash) {
   139  	copy(h[:], l.ProtocolData[:])
   140  	return
   141  }
   142  
   143  func (l BlockHeaderLogEntry) Pow() (h mavryk.HexBytes) {
   144  	h.UnmarshalBinary(l.ProtocolData[36:44])
   145  	return
   146  }
   147  
   148  func (b *Block) LogEntry() *BlockHeaderLogEntry {
   149  	e := b.Header.LogEntry()
   150  	e.Hash = b.Hash
   151  	return e
   152  }
   153  
   154  type BlockHeaderMonitor struct {
   155  	result chan *BlockHeaderLogEntry
   156  	closed chan struct{}
   157  	err    error
   158  }
   159  
   160  // make sure BlockHeaderMonitor implements Monitor interface
   161  var _ Monitor = (*BlockHeaderMonitor)(nil)
   162  
   163  func NewBlockHeaderMonitor() *BlockHeaderMonitor {
   164  	return &BlockHeaderMonitor{
   165  		result: make(chan *BlockHeaderLogEntry),
   166  		closed: make(chan struct{}),
   167  	}
   168  }
   169  
   170  func (m *BlockHeaderMonitor) New() interface{} {
   171  	return &BlockHeaderLogEntry{}
   172  }
   173  
   174  func (m *BlockHeaderMonitor) Send(ctx context.Context, val interface{}) {
   175  	select {
   176  	case <-m.closed:
   177  		return
   178  	default:
   179  	}
   180  	select {
   181  	case <-ctx.Done():
   182  	case <-m.closed:
   183  	case m.result <- val.(*BlockHeaderLogEntry):
   184  	}
   185  }
   186  
   187  func (m *BlockHeaderMonitor) Recv(ctx context.Context) (*BlockHeaderLogEntry, error) {
   188  	select {
   189  	case <-ctx.Done():
   190  		return nil, ctx.Err()
   191  	case <-m.closed:
   192  		err := m.err
   193  		if err == nil {
   194  			err = ErrMonitorClosed
   195  		}
   196  		return nil, err
   197  	case res, ok := <-m.result:
   198  		if !ok {
   199  			if m.err != nil {
   200  				return nil, m.err
   201  			}
   202  			return nil, io.EOF
   203  		}
   204  		return res, nil
   205  	}
   206  }
   207  
   208  func (m *BlockHeaderMonitor) Err(err error) {
   209  	m.err = err
   210  	m.Close()
   211  }
   212  
   213  func (m *BlockHeaderMonitor) Close() {
   214  	select {
   215  	case <-m.closed:
   216  		return
   217  	default:
   218  	}
   219  	close(m.closed)
   220  	close(m.result)
   221  }
   222  
   223  func (m *BlockHeaderMonitor) Closed() <-chan struct{} {
   224  	return m.closed
   225  }
   226  
   227  // MempoolMonitor is a monitor for the Tezos mempool. Note that the connection
   228  // resets every time a new head is attached to the chain. MempoolMonitor is
   229  // closed with an error in this case and cannot be reused after close.
   230  //
   231  // The Tezos mempool re-evaluates all operations and potentially updates their state
   232  // when the head block changes. This applies to operations in lists branch_delayed
   233  // and branch_refused. After reorg, operations already included in a previous block
   234  // may enter the mempool again.
   235  type MempoolMonitor struct {
   236  	result chan *[]*Operation
   237  	closed chan struct{}
   238  	err    error
   239  }
   240  
   241  // make sure MempoolMonitor implements Monitor interface
   242  var _ Monitor = (*MempoolMonitor)(nil)
   243  
   244  func NewMempoolMonitor() *MempoolMonitor {
   245  	return &MempoolMonitor{
   246  		result: make(chan *[]*Operation),
   247  		closed: make(chan struct{}),
   248  	}
   249  }
   250  
   251  func (m *MempoolMonitor) New() interface{} {
   252  	slice := make([]*Operation, 0)
   253  	return &slice
   254  }
   255  
   256  func (m *MempoolMonitor) Send(ctx context.Context, val interface{}) {
   257  	select {
   258  	case <-m.closed:
   259  		return
   260  	default:
   261  	}
   262  	select {
   263  	case <-ctx.Done():
   264  	case <-m.closed:
   265  	case m.result <- val.(*[]*Operation):
   266  	}
   267  }
   268  
   269  func (m *MempoolMonitor) Recv(ctx context.Context) ([]*Operation, error) {
   270  	select {
   271  	case <-ctx.Done():
   272  		return nil, ctx.Err()
   273  	case <-m.closed:
   274  		err := m.err
   275  		if err == nil {
   276  			err = ErrMonitorClosed
   277  		}
   278  		return nil, err
   279  	case res, ok := <-m.result:
   280  		if !ok {
   281  			if m.err != nil {
   282  				return nil, m.err
   283  			}
   284  			return nil, io.EOF
   285  		}
   286  		return *res, nil
   287  	}
   288  }
   289  
   290  func (m *MempoolMonitor) Err(err error) {
   291  	m.err = err
   292  	m.Close()
   293  }
   294  
   295  func (m *MempoolMonitor) Close() {
   296  	select {
   297  	case <-m.closed:
   298  		return
   299  	default:
   300  	}
   301  	close(m.closed)
   302  	close(m.result)
   303  }
   304  
   305  func (m *MempoolMonitor) Closed() <-chan struct{} {
   306  	return m.closed
   307  }
   308  
   309  // NetworkPeerLogEntry represents peer log entry
   310  type NetworkPeerLogEntry struct {
   311  	NetworkAddress
   312  	Kind      string    `json:"kind"`
   313  	Timestamp time.Time `json:"timestamp"`
   314  }
   315  
   316  type NetworkPeerMonitor struct {
   317  	result chan *NetworkPeerLogEntry
   318  	closed chan struct{}
   319  	err    error
   320  }
   321  
   322  // make sure NetworkPeerMonitor implements Monitor interface
   323  var _ Monitor = (*NetworkPeerMonitor)(nil)
   324  
   325  func NewNetworkPeerMonitor() *NetworkPeerMonitor {
   326  	return &NetworkPeerMonitor{
   327  		result: make(chan *NetworkPeerLogEntry),
   328  		closed: make(chan struct{}),
   329  	}
   330  }
   331  
   332  func (m *NetworkPeerMonitor) New() interface{} {
   333  	return &NetworkPeerLogEntry{}
   334  }
   335  
   336  func (m *NetworkPeerMonitor) Send(ctx context.Context, val interface{}) {
   337  	select {
   338  	case <-m.closed:
   339  		return
   340  	default:
   341  	}
   342  	select {
   343  	case <-ctx.Done():
   344  	case <-m.closed:
   345  	case m.result <- val.(*NetworkPeerLogEntry):
   346  	}
   347  }
   348  
   349  func (m *NetworkPeerMonitor) Recv(ctx context.Context) (*NetworkPeerLogEntry, error) {
   350  	select {
   351  	case <-ctx.Done():
   352  		return nil, ctx.Err()
   353  	case <-m.closed:
   354  		err := m.err
   355  		if err == nil {
   356  			err = ErrMonitorClosed
   357  		}
   358  		return nil, err
   359  	case res, ok := <-m.result:
   360  		if !ok {
   361  			if m.err != nil {
   362  				return nil, m.err
   363  			}
   364  			return nil, io.EOF
   365  		}
   366  		return res, nil
   367  	}
   368  }
   369  
   370  func (m *NetworkPeerMonitor) Err(err error) {
   371  	m.err = err
   372  	m.Close()
   373  }
   374  
   375  func (m *NetworkPeerMonitor) Close() {
   376  	select {
   377  	case <-m.closed:
   378  		return
   379  	default:
   380  	}
   381  	close(m.closed)
   382  	close(m.result)
   383  }
   384  
   385  func (m *NetworkPeerMonitor) Closed() <-chan struct{} {
   386  	return m.closed
   387  }
   388  
   389  // NetworkPointLogEntry represents point's log entry
   390  type NetworkPointLogEntry struct {
   391  	Kind      NetworkPointState `json:"kind"`
   392  	Timestamp time.Time         `json:"timestamp"`
   393  }
   394  
   395  type NetworkPointMonitor struct {
   396  	result chan *NetworkPointLogEntry
   397  	closed chan struct{}
   398  	err    error
   399  }
   400  
   401  // make sure NetworkPointMonitor implements Monitor interface
   402  var _ Monitor = (*NetworkPointMonitor)(nil)
   403  
   404  func NewNetworkPointMonitor() *NetworkPointMonitor {
   405  	return &NetworkPointMonitor{
   406  		result: make(chan *NetworkPointLogEntry),
   407  		closed: make(chan struct{}),
   408  	}
   409  }
   410  
   411  func (m *NetworkPointMonitor) New() interface{} {
   412  	return &NetworkPointLogEntry{}
   413  }
   414  
   415  func (m *NetworkPointMonitor) Send(ctx context.Context, val interface{}) {
   416  	select {
   417  	case <-m.closed:
   418  		return
   419  	default:
   420  	}
   421  	select {
   422  	case <-ctx.Done():
   423  	case <-m.closed:
   424  	case m.result <- val.(*NetworkPointLogEntry):
   425  	}
   426  }
   427  
   428  func (m *NetworkPointMonitor) Recv(ctx context.Context) (*NetworkPointLogEntry, error) {
   429  	select {
   430  	case <-ctx.Done():
   431  		return nil, ctx.Err()
   432  	case <-m.closed:
   433  		err := m.err
   434  		if err == nil {
   435  			err = ErrMonitorClosed
   436  		}
   437  		return nil, err
   438  	case res, ok := <-m.result:
   439  		if !ok {
   440  			if m.err != nil {
   441  				return nil, m.err
   442  			}
   443  			return nil, io.EOF
   444  		}
   445  		return res, nil
   446  	}
   447  }
   448  
   449  func (m *NetworkPointMonitor) Err(err error) {
   450  	m.err = err
   451  	m.Close()
   452  }
   453  
   454  func (m *NetworkPointMonitor) Close() {
   455  	select {
   456  	case <-m.closed:
   457  		return
   458  	default:
   459  	}
   460  	close(m.closed)
   461  	close(m.result)
   462  }
   463  
   464  func (m *NetworkPointMonitor) Closed() <-chan struct{} {
   465  	return m.closed
   466  }
   467  
   468  // MonitorBootstrapped reads from the bootstrapped blocks stream http://protocol.mavryk.org/mainnet/api/rpc.html#get-monitor-bootstrapped
   469  func (c *Client) MonitorBootstrapped(ctx context.Context, monitor *BootstrapMonitor) error {
   470  	return c.GetAsync(ctx, "monitor/bootstrapped", monitor)
   471  }
   472  
   473  // MonitorBlockHeader reads from the chain heads stream http://protocol.mavryk.org/mainnet/api/rpc.html#get-monitor-heads-chain-id
   474  func (c *Client) MonitorBlockHeader(ctx context.Context, monitor *BlockHeaderMonitor) error {
   475  	return c.GetAsync(ctx, "monitor/heads/main", monitor)
   476  }
   477  
   478  // MonitorMempool reads from the chain heads stream http://protocol.mavryk.org/mainnet/api/rpc.html#get-monitor-heads-chain-id
   479  func (c *Client) MonitorMempool(ctx context.Context, monitor *MempoolMonitor) error {
   480  	return c.GetAsync(ctx, "chains/main/mempool/monitor_operations", monitor)
   481  }
   482  
   483  // MonitorNetworkPointLog monitors network events related to an `IP:addr`.
   484  // https://protocol.mavryk.org/mainnet/api/rpc.html#get-network-peers-peer-id-log
   485  func (c *Client) MonitorNetworkPointLog(ctx context.Context, address string, monitor *NetworkPointMonitor) error {
   486  	return c.GetAsync(ctx, "network/points/"+address+"/log?monitor", monitor)
   487  }
   488  
   489  // MonitorNetworkPeerLog monitors network events related to a given peer.
   490  // https://protocol.mavryk.org/mainnet/api/rpc.html#get-network-peers-peer-id-log
   491  func (c *Client) MonitorNetworkPeerLog(ctx context.Context, peerID string, monitor *NetworkPeerMonitor) error {
   492  	return c.GetAsync(ctx, "network/peers/"+peerID+"/log?monitor", monitor)
   493  }