diff --git a/pkg/solana/client/client.go b/pkg/solana/client/client.go index f5a36a6fe..5e1ada287 100644 --- a/pkg/solana/client/client.go +++ b/pkg/solana/client/client.go @@ -87,6 +87,8 @@ func (c *Client) latency(name string) func() { } func (c *Client) Balance(addr solana.PublicKey) (uint64, error) { + defer c.latency("balance")() + ctx, cancel := context.WithTimeout(context.Background(), c.contextDuration) defer cancel() @@ -105,6 +107,8 @@ func (c *Client) SlotHeight() (uint64, error) { } func (c *Client) SlotHeightWithCommitment(commitment rpc.CommitmentType) (uint64, error) { + defer c.latency("slot_height")() + ctx, cancel := context.WithTimeout(context.Background(), c.contextDuration) defer cancel() v, err, _ := c.requestGroup.Do("GetSlotHeight", func() (interface{}, error) { @@ -114,6 +118,8 @@ func (c *Client) SlotHeightWithCommitment(commitment rpc.CommitmentType) (uint64 } func (c *Client) GetAccountInfoWithOpts(ctx context.Context, addr solana.PublicKey, opts *rpc.GetAccountInfoOpts) (*rpc.GetAccountInfoResult, error) { + defer c.latency("account_info")() + ctx, cancel := context.WithTimeout(ctx, c.contextDuration) defer cancel() opts.Commitment = c.commitment // overrides passed in value - use defined client commitment type @@ -121,6 +127,8 @@ func (c *Client) GetAccountInfoWithOpts(ctx context.Context, addr solana.PublicK } func (c *Client) LatestBlockhash() (*rpc.GetLatestBlockhashResult, error) { + defer c.latency("latest_blockhash")() + ctx, cancel := context.WithTimeout(context.Background(), c.contextDuration) defer cancel() @@ -131,6 +139,8 @@ func (c *Client) LatestBlockhash() (*rpc.GetLatestBlockhashResult, error) { } func (c *Client) ChainID() (string, error) { + defer c.latency("chain_id")() + ctx, cancel := context.WithTimeout(context.Background(), c.contextDuration) defer cancel() v, err, _ := c.requestGroup.Do("GetGenesisHash", func() (interface{}, error) { @@ -157,6 +167,8 @@ func (c *Client) ChainID() (string, error) { } func (c *Client) GetFeeForMessage(msg string) (uint64, error) { + defer c.latency("fee_for_message")() + // msg is base58 encoded data ctx, cancel := context.WithTimeout(context.Background(), c.contextDuration) @@ -174,6 +186,8 @@ func (c *Client) GetFeeForMessage(msg string) (uint64, error) { // https://docs.solana.com/developing/clients/jsonrpc-api#getsignaturestatuses func (c *Client) SignatureStatuses(ctx context.Context, sigs []solana.Signature) ([]*rpc.SignatureStatusesResult, error) { + defer c.latency("signature_statuses")() + ctx, cancel := context.WithTimeout(ctx, c.contextDuration) defer cancel() @@ -192,6 +206,8 @@ func (c *Client) SignatureStatuses(ctx context.Context, sigs []solana.Signature) // https://docs.solana.com/developing/clients/jsonrpc-api#simulatetransaction // opts - (optional) use `nil` to use defaults func (c *Client) SimulateTx(ctx context.Context, tx *solana.Transaction, opts *rpc.SimulateTransactionOpts) (*rpc.SimulateTransactionResult, error) { + defer c.latency("simulate_tx")() + ctx, cancel := context.WithTimeout(ctx, c.contextDuration) defer cancel() @@ -215,6 +231,8 @@ func (c *Client) SimulateTx(ctx context.Context, tx *solana.Transaction, opts *r } func (c *Client) SendTx(ctx context.Context, tx *solana.Transaction) (solana.Signature, error) { + defer c.latency("send_tx")() + ctx, cancel := context.WithTimeout(ctx, c.txTimeout) defer cancel() @@ -235,6 +253,7 @@ func (c *Client) GetLatestBlock() (*rpc.GetBlockResult, error) { } // get block based on slot + defer c.latency("latest_block")() ctx, cancel := context.WithTimeout(context.Background(), c.txTimeout) defer cancel() v, err, _ := c.requestGroup.Do("GetBlockWithOpts", func() (interface{}, error) { diff --git a/pkg/solana/client/client_test.go b/pkg/solana/client/client_test.go index 4427330c4..1cad435df 100644 --- a/pkg/solana/client/client_test.go +++ b/pkg/solana/client/client_test.go @@ -13,12 +13,15 @@ import ( "github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go/programs/system" "github.com/gagliardetto/solana-go/rpc" + "github.com/google/uuid" + "github.com/prometheus/client_golang/prometheus/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" + "github.com/smartcontractkit/chainlink-solana/pkg/solana/monitor" ) func TestClient_Reader_Integration(t *testing.T) { @@ -292,3 +295,21 @@ func TestClient_SendTxDuplicates_Integration(t *testing.T) { assert.NoError(t, err) assert.Equal(t, uint64(5_000), initBal-endBal) } + +func TestClientLatency(t *testing.T) { + c := Client{} + v := 100 + n := t.Name() + uuid.NewString() + f := func() { + defer c.latency(n)() + time.Sleep(time.Duration(v) * time.Millisecond) + } + f() + g, err := monitor.GetClientLatency(n, c.url) + require.NoError(t, err) + val := testutil.ToFloat64(g) + + // check within expected range + assert.GreaterOrEqual(t, val, float64(v)) + assert.LessOrEqual(t, val, float64(v)*1.05) +} diff --git a/pkg/solana/monitor/prom.go b/pkg/solana/monitor/prom.go index a87167b6b..ea1ecadef 100644 --- a/pkg/solana/monitor/prom.go +++ b/pkg/solana/monitor/prom.go @@ -44,3 +44,10 @@ func SetClientLatency(d time.Duration, request, url string) { "url": url, }).Set(float64(d.Milliseconds())) } + +func GetClientLatency(request, url string) (prometheus.Gauge, error) { + return promClientReq.GetMetricWith(prometheus.Labels{ + "request": request, + "url": url, + }) +}