Skip to content

Commit

Permalink
Update Solana Client for LogPoller (#933)
Browse files Browse the repository at this point in the history
* Add required methods

* Add GetBlocks

* Add GetBlocks method
  • Loading branch information
DylanTinianov authored Dec 5, 2024
1 parent 75e06e6 commit f7ecca8
Show file tree
Hide file tree
Showing 3 changed files with 279 additions and 0 deletions.
53 changes: 53 additions & 0 deletions pkg/solana/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,11 @@ type Reader interface {
ChainID(ctx context.Context) (mn.StringID, error)
GetFeeForMessage(ctx context.Context, msg string) (uint64, error)
GetLatestBlock(ctx context.Context) (*rpc.GetBlockResult, error)
GetTransaction(ctx context.Context, txHash solana.Signature, opts *rpc.GetTransactionOpts) (*rpc.GetTransactionResult, error)
GetBlocks(ctx context.Context, startSlot uint64, endSlot *uint64) (rpc.BlocksResult, error)
GetBlocksWithLimit(ctx context.Context, startSlot uint64, limit uint64) (*rpc.BlocksResult, error)
GetBlock(ctx context.Context, slot uint64) (*rpc.GetBlockResult, error)
GetSignaturesForAddressWithOpts(ctx context.Context, addr solana.PublicKey, opts *rpc.GetSignaturesForAddressOpts) ([]*rpc.TransactionSignature, error)
}

// AccountReader is an interface that allows users to pass either the solana rpc client or the relay client
Expand Down Expand Up @@ -121,6 +124,43 @@ func (c *Client) SlotHeightWithCommitment(ctx context.Context, commitment rpc.Co
return v.(uint64), err
}

func (c *Client) GetSignaturesForAddressWithOpts(ctx context.Context, addr solana.PublicKey, opts *rpc.GetSignaturesForAddressOpts) ([]*rpc.TransactionSignature, error) {
done := c.latency("signatures_for_address")
defer done()

ctx, cancel := context.WithTimeout(ctx, c.contextDuration)
defer cancel()
if opts == nil {
opts = &rpc.GetSignaturesForAddressOpts{}
}
if opts.Commitment == "" {
opts.Commitment = c.commitment
}
return c.rpc.GetSignaturesForAddressWithOpts(ctx, addr, opts)
}

func (c *Client) GetTransaction(ctx context.Context, txHash solana.Signature, opts *rpc.GetTransactionOpts) (*rpc.GetTransactionResult, error) {
done := c.latency("transaction")
defer done()

ctx, cancel := context.WithTimeout(ctx, c.contextDuration)
defer cancel()

if opts == nil {
opts = &rpc.GetTransactionOpts{
Encoding: solana.EncodingBase64,
}
}
if opts.Commitment == "" {
opts.Commitment = c.commitment
}

v, err, _ := c.requestGroup.Do("GetTransaction", func() (interface{}, error) {
return c.rpc.GetTransaction(ctx, txHash, opts)
})
return v.(*rpc.GetTransactionResult), err
}

func (c *Client) GetAccountInfoWithOpts(ctx context.Context, addr solana.PublicKey, opts *rpc.GetAccountInfoOpts) (*rpc.GetAccountInfoResult, error) {
done := c.latency("account_info")
defer done()
Expand All @@ -131,6 +171,19 @@ func (c *Client) GetAccountInfoWithOpts(ctx context.Context, addr solana.PublicK
return c.rpc.GetAccountInfoWithOpts(ctx, addr, opts)
}

func (c *Client) GetBlocks(ctx context.Context, startSlot uint64, endSlot *uint64) (out rpc.BlocksResult, err error) {
done := c.latency("blocks")
defer done()

ctx, cancel := context.WithTimeout(ctx, c.contextDuration)
defer cancel()

v, err, _ := c.requestGroup.Do("GetBlocks", func() (interface{}, error) {
return c.rpc.GetBlocks(ctx, startSlot, endSlot, c.commitment)
})
return v.(rpc.BlocksResult), err
}

func (c *Client) LatestBlockhash(ctx context.Context) (*rpc.GetLatestBlockhashResult, error) {
done := c.latency("latest_blockhash")
defer done()
Expand Down
46 changes: 46 additions & 0 deletions pkg/solana/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,52 @@ func TestClient_Writer_Integration(t *testing.T) {

assert.Nil(t, statuses[0].Err)
assert.NotNil(t, statuses[1].Err)

getTxResult, err := c.GetTransaction(ctx, sigSuccess, nil)
assert.NoError(t, err)
assert.NotNil(t, getTxResult)

sigs, err := c.GetSignaturesForAddressWithOpts(ctx, pubKey, nil)
assert.NoError(t, err)
requiredSigs := map[solana.Signature]bool{
sigSuccess: false,
sigFail: false,
}
for _, sig := range sigs {
if _, required := requiredSigs[sig.Signature]; required {
requiredSigs[sig.Signature] = true
}
}
require.True(t, requiredSigs[sigSuccess] && requiredSigs[sigFail])
}

func TestClient_GetBlocks(t *testing.T) {
url := SetupLocalSolNode(t)
privKey, err := solana.NewRandomPrivateKey()
require.NoError(t, err)
pubKey := privKey.PublicKey()
FundTestAccounts(t, []solana.PublicKey{pubKey}, url)

requestTimeout := 5 * time.Second
lggr := logger.Test(t)
cfg := config.NewDefault()

ctx := tests.Context(t)
c, err := NewClient(url, cfg, requestTimeout, lggr)
require.NoError(t, err)

// Verify we can retrieve blocks
startSlot := uint64(1)
endSlot := uint64(6)
require.Eventually(t,
func() bool {
blocks, err := c.GetBlocks(ctx, startSlot, &endSlot)
if err != nil {
return false
}
return len(blocks) == 5
},
requestTimeout, 500*time.Millisecond)
}

func TestClient_SendTxDuplicates_Integration(t *testing.T) {
Expand Down
180 changes: 180 additions & 0 deletions pkg/solana/client/mocks/reader_writer.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit f7ecca8

Please sign in to comment.