github.com/MetalBlockchain/metalgo@v1.11.9/api/info/client.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package info 5 6 import ( 7 "context" 8 "net/netip" 9 "time" 10 11 "github.com/MetalBlockchain/metalgo/ids" 12 "github.com/MetalBlockchain/metalgo/utils/rpc" 13 "github.com/MetalBlockchain/metalgo/vms/platformvm/signer" 14 ) 15 16 var _ Client = (*client)(nil) 17 18 // Client interface for an Info API Client. 19 // See also AwaitBootstrapped. 20 type Client interface { 21 GetNodeVersion(context.Context, ...rpc.Option) (*GetNodeVersionReply, error) 22 GetNodeID(context.Context, ...rpc.Option) (ids.NodeID, *signer.ProofOfPossession, error) 23 GetNodeIP(context.Context, ...rpc.Option) (netip.AddrPort, error) 24 GetNetworkID(context.Context, ...rpc.Option) (uint32, error) 25 GetNetworkName(context.Context, ...rpc.Option) (string, error) 26 GetBlockchainID(context.Context, string, ...rpc.Option) (ids.ID, error) 27 Peers(context.Context, ...rpc.Option) ([]Peer, error) 28 IsBootstrapped(context.Context, string, ...rpc.Option) (bool, error) 29 GetTxFee(context.Context, ...rpc.Option) (*GetTxFeeResponse, error) 30 Uptime(context.Context, ids.ID, ...rpc.Option) (*UptimeResponse, error) 31 GetVMs(context.Context, ...rpc.Option) (map[ids.ID][]string, error) 32 } 33 34 // Client implementation for an Info API Client 35 type client struct { 36 requester rpc.EndpointRequester 37 } 38 39 // NewClient returns a new Info API Client 40 func NewClient(uri string) Client { 41 return &client{requester: rpc.NewEndpointRequester( 42 uri + "/ext/info", 43 )} 44 } 45 46 func (c *client) GetNodeVersion(ctx context.Context, options ...rpc.Option) (*GetNodeVersionReply, error) { 47 res := &GetNodeVersionReply{} 48 err := c.requester.SendRequest(ctx, "info.getNodeVersion", struct{}{}, res, options...) 49 return res, err 50 } 51 52 func (c *client) GetNodeID(ctx context.Context, options ...rpc.Option) (ids.NodeID, *signer.ProofOfPossession, error) { 53 res := &GetNodeIDReply{} 54 err := c.requester.SendRequest(ctx, "info.getNodeID", struct{}{}, res, options...) 55 return res.NodeID, res.NodePOP, err 56 } 57 58 func (c *client) GetNodeIP(ctx context.Context, options ...rpc.Option) (netip.AddrPort, error) { 59 res := &GetNodeIPReply{} 60 err := c.requester.SendRequest(ctx, "info.getNodeIP", struct{}{}, res, options...) 61 return res.IP, err 62 } 63 64 func (c *client) GetNetworkID(ctx context.Context, options ...rpc.Option) (uint32, error) { 65 res := &GetNetworkIDReply{} 66 err := c.requester.SendRequest(ctx, "info.getNetworkID", struct{}{}, res, options...) 67 return uint32(res.NetworkID), err 68 } 69 70 func (c *client) GetNetworkName(ctx context.Context, options ...rpc.Option) (string, error) { 71 res := &GetNetworkNameReply{} 72 err := c.requester.SendRequest(ctx, "info.getNetworkName", struct{}{}, res, options...) 73 return res.NetworkName, err 74 } 75 76 func (c *client) GetBlockchainID(ctx context.Context, alias string, options ...rpc.Option) (ids.ID, error) { 77 res := &GetBlockchainIDReply{} 78 err := c.requester.SendRequest(ctx, "info.getBlockchainID", &GetBlockchainIDArgs{ 79 Alias: alias, 80 }, res, options...) 81 return res.BlockchainID, err 82 } 83 84 func (c *client) Peers(ctx context.Context, options ...rpc.Option) ([]Peer, error) { 85 res := &PeersReply{} 86 err := c.requester.SendRequest(ctx, "info.peers", struct{}{}, res, options...) 87 return res.Peers, err 88 } 89 90 func (c *client) IsBootstrapped(ctx context.Context, chainID string, options ...rpc.Option) (bool, error) { 91 res := &IsBootstrappedResponse{} 92 err := c.requester.SendRequest(ctx, "info.isBootstrapped", &IsBootstrappedArgs{ 93 Chain: chainID, 94 }, res, options...) 95 return res.IsBootstrapped, err 96 } 97 98 func (c *client) GetTxFee(ctx context.Context, options ...rpc.Option) (*GetTxFeeResponse, error) { 99 res := &GetTxFeeResponse{} 100 err := c.requester.SendRequest(ctx, "info.getTxFee", struct{}{}, res, options...) 101 return res, err 102 } 103 104 func (c *client) Uptime(ctx context.Context, subnetID ids.ID, options ...rpc.Option) (*UptimeResponse, error) { 105 res := &UptimeResponse{} 106 err := c.requester.SendRequest(ctx, "info.uptime", &UptimeRequest{ 107 SubnetID: subnetID, 108 }, res, options...) 109 return res, err 110 } 111 112 func (c *client) GetVMs(ctx context.Context, options ...rpc.Option) (map[ids.ID][]string, error) { 113 res := &GetVMsReply{} 114 err := c.requester.SendRequest(ctx, "info.getVMs", struct{}{}, res, options...) 115 return res.VMs, err 116 } 117 118 // AwaitBootstrapped polls the node every [freq] to check if [chainID] has 119 // finished bootstrapping. Returns true once [chainID] reports that it has 120 // finished bootstrapping. 121 // Only returns an error if [ctx] returns an error. 122 func AwaitBootstrapped(ctx context.Context, c Client, chainID string, freq time.Duration, options ...rpc.Option) (bool, error) { 123 ticker := time.NewTicker(freq) 124 defer ticker.Stop() 125 126 for { 127 res, err := c.IsBootstrapped(ctx, chainID, options...) 128 if err == nil && res { 129 return true, nil 130 } 131 132 select { 133 case <-ticker.C: 134 case <-ctx.Done(): 135 return false, ctx.Err() 136 } 137 } 138 }