Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
560 changes: 560 additions & 0 deletions rpc/client_test.go

Large diffs are not rendered by default.

18 changes: 16 additions & 2 deletions rpc/getClusterNodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,18 @@ type GetClusterNodesResult struct {
// TPU QUIC network address for the node.
TPUQUIC *string `json:"tpuQuic,omitempty"`

// TPU forwards network address for the node.
TPUForwards *string `json:"tpuForwards,omitempty"`

// TPU forwards QUIC network address for the node.
TPUForwardsQUIC *string `json:"tpuForwardsQuic,omitempty"`

// TPU vote network address for the node.
TPUVote *string `json:"tpuVote,omitempty"`

// Serve repair network address for the node.
ServeRepair *string `json:"serveRepair,omitempty"`

// RPC WebSocket network address for the node, or empty if the WebSocket RPC service is not enabled.
PubSub *string `json:"pubsub,omitempty"`

Expand All @@ -50,10 +62,12 @@ type GetClusterNodesResult struct {
// The software version of the node, or empty if the version information is not available.
Version *string `json:"version,omitempty"`

// TODO: what type is this?
// The unique identifier of the node's feature set.
FeatureSet uint32 `json:"featureSet,omitempty"`
FeatureSet *uint32 `json:"featureSet,omitempty"`

// The shred version the node has been configured to use.
ShredVersion uint16 `json:"shredVersion,omitempty"`

// The client identifier for the node.
ClientID *string `json:"clientId,omitempty"`
}
2 changes: 1 addition & 1 deletion rpc/getInflationRate.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,5 @@ type GetInflationRateResult struct {
Foundation float64 `json:"foundation"`

// Epoch for which these values are valid.
Epoch float64 `json:"epoch"`
Epoch uint64 `json:"epoch"`
}
5 changes: 4 additions & 1 deletion rpc/getInflationReward.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func (cl *Client) GetInflationReward(
}

type GetInflationRewardResult struct {
// Epoch for which reward occured.
// Epoch for which reward occurred.
Epoch uint64 `json:"epoch"`

// The slot in which the rewards are effective.
Expand All @@ -71,4 +71,7 @@ type GetInflationRewardResult struct {

// Vote account commission when the reward was credited.
Commission *uint8 `json:"commission,omitempty"`

// Vote account commission in basis points when the reward was credited.
CommissionBps *uint16 `json:"commissionBps,omitempty"`
}
33 changes: 28 additions & 5 deletions rpc/getLargestAccounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,43 @@ const (
LargestAccountsFilterNonCirculating LargestAccountsFilterType = "nonCirculating"
)

type GetLargestAccountsOpts struct {
Commitment CommitmentType
Filter LargestAccountsFilterType
SortResults *bool
}

// GetLargestAccounts returns the 20 largest accounts,
// by lamport balance (results may be cached up to two hours).
func (cl *Client) GetLargestAccounts(
ctx context.Context,
commitment CommitmentType,
filter LargestAccountsFilterType, // filter results by account type; currently supported: circulating|nonCirculating
) (out *GetLargestAccountsResult, err error) {
return cl.GetLargestAccountsWithOpts(ctx, &GetLargestAccountsOpts{
Commitment: commitment,
Filter: filter,
})
}

// GetLargestAccountsWithOpts returns the 20 largest accounts,
// by lamport balance (results may be cached up to two hours).
func (cl *Client) GetLargestAccountsWithOpts(
ctx context.Context,
opts *GetLargestAccountsOpts,
) (out *GetLargestAccountsResult, err error) {
params := []any{}
obj := M{}
if commitment != "" {
obj["commitment"] = commitment
}
if filter != "" {
obj["filter"] = filter
if opts != nil {
if opts.Commitment != "" {
obj["commitment"] = opts.Commitment
}
if opts.Filter != "" {
obj["filter"] = opts.Filter
}
if opts.SortResults != nil {
obj["sortResults"] = *opts.SortResults
}
}
if len(obj) > 0 {
params = append(params, obj)
Expand Down
37 changes: 32 additions & 5 deletions rpc/getProgramAccounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,31 @@ func (cl *Client) GetProgramAccountsWithOpts(
publicKey solana.PublicKey,
opts *GetProgramAccountsOpts,
) (out GetProgramAccountsResult, err error) {
params := buildGetProgramAccountsParams(publicKey, opts)
err = cl.rpcClient.CallForInto(ctx, &out, "getProgramAccounts", params)
return
}

// GetProgramAccountsWithContext returns all accounts owned by the provided program publicKey,
// wrapped in an RPC response with context (slot and apiVersion).
// The WithContext option is automatically set to true.
func (cl *Client) GetProgramAccountsWithContext(
ctx context.Context,
publicKey solana.PublicKey,
opts *GetProgramAccountsOpts,
) (out *GetProgramAccountsWithContextResult, err error) {
var o GetProgramAccountsOpts
if opts != nil {
o = *opts
}
withCtx := true
o.WithContext = &withCtx
params := buildGetProgramAccountsParams(publicKey, &o)
err = cl.rpcClient.CallForInto(ctx, &out, "getProgramAccounts", params)
return
}

func buildGetProgramAccountsParams(publicKey solana.PublicKey, opts *GetProgramAccountsOpts) []any {
obj := M{
"encoding": "base64",
}
Expand All @@ -59,10 +84,12 @@ func (cl *Client) GetProgramAccountsWithOpts(
"length": opts.DataSlice.Length,
}
}
if opts.WithContext != nil {
obj["withContext"] = *opts.WithContext
}
if opts.SortResults != nil {
obj["sortResults"] = *opts.SortResults
}
}

params := []any{publicKey, obj}

err = cl.rpcClient.CallForInto(ctx, &out, "getProgramAccounts", params)
return
return []any{publicKey, obj}
}
3 changes: 3 additions & 0 deletions rpc/getRecentPerformanceSamples.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ type GetRecentPerformanceSamplesResult struct {
// Number of transactions in sample.
NumTransactions uint64 `json:"numTransactions"`

// Number of non-vote transactions in sample.
NumNonVoteTransactions *uint64 `json:"numNonVoteTransactions,omitempty"`

// Number of slots in sample.
NumSlots uint64 `json:"numSlots"`

Expand Down
3 changes: 3 additions & 0 deletions rpc/getVoteAccounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ type VoteAccountsResult struct {
// Percentage (0-100) of rewards payout owed to the vote account.
Commission uint8 `json:"commission,omitempty"`

// Commission in basis points for inflation rewards.
InflationRewardsCommissionBps *uint16 `json:"inflationRewardsCommissionBps,omitempty"`

// Most recent slot voted on by this vote account.
LastVote uint64 `json:"lastVote,omitempty"`

Expand Down
36 changes: 32 additions & 4 deletions rpc/requestAirdrop.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,50 @@ import (
"github.com/gagliardetto/solana-go"
)

type RequestAirdropOpts struct {
Commitment CommitmentType

// Must be a recent blockhash as a base-58 encoded string.
// If not provided, a recent blockhash is used.
RecentBlockhash *solana.Hash
}

// RequestAirdrop requests an airdrop of lamports to a publicKey.
// Returns transaction signature of airdrop.
func (cl *Client) RequestAirdrop(
ctx context.Context,
account solana.PublicKey,
lamports uint64,
commitment CommitmentType, // optional; used for retrieving blockhash and verifying airdrop success.
) (signature solana.Signature, err error) {
return cl.RequestAirdropWithOpts(ctx, account, lamports, &RequestAirdropOpts{
Commitment: commitment,
})
}

// RequestAirdropWithOpts requests an airdrop of lamports to a publicKey with additional options.
// Returns transaction signature of airdrop.
func (cl *Client) RequestAirdropWithOpts(
ctx context.Context,
account solana.PublicKey,
lamports uint64,
opts *RequestAirdropOpts,
) (signature solana.Signature, err error) {
params := []any{
account,
lamports,
}
if commitment != "" {
params = append(params,
M{"commitment": commitment},
)
if opts != nil {
obj := M{}
if opts.Commitment != "" {
obj["commitment"] = opts.Commitment
}
if opts.RecentBlockhash != nil {
obj["recentBlockhash"] = opts.RecentBlockhash.String()
}
if len(obj) > 0 {
params = append(params, obj)
}
}
err = cl.rpcClient.CallForInto(ctx, &signature, "requestAirdrop", params)
return
Expand Down
68 changes: 67 additions & 1 deletion rpc/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ import (
)

type Context struct {
Slot uint64 `json:"slot"`
Slot uint64 `json:"slot"`
ApiVersion *string `json:"apiVersion,omitempty"`
}

type RPCContext struct {
Expand Down Expand Up @@ -124,6 +125,57 @@ func (twm TransactionWithMeta) GetTransaction() (*solana.Transaction, error) {
return tx, nil
}

// GetAccountKeys returns the account keys when the block was fetched with
// TransactionDetailsAccounts. In this mode the transaction field contains
// {"signatures": [...], "accountKeys": [...]} instead of the full encoded transaction.
func (twm TransactionWithMeta) GetAccountKeys() (*TransactionAccountKeys, error) {
if twm.Transaction == nil {
return nil, fmt.Errorf("transaction is nil")
}
raw := twm.Transaction.GetRawJSON()
if raw == nil {
return nil, fmt.Errorf("transaction is not JSON (accounts mode requires transactionDetails=accounts)")
}
var out TransactionAccountKeys
if err := json.Unmarshal(raw, &out); err != nil {
return nil, fmt.Errorf("failed to unmarshal account keys: %w", err)
}
return &out, nil
}

// TransactionAccountKeys is the transaction representation returned when
// transactionDetails is "accounts". Instead of the full message, it contains
// only the signatures and the list of account keys with their roles.
type TransactionAccountKeys struct {
Signatures []solana.Signature `json:"signatures"`
AccountKeys []AccountKey `json:"accountKeys"`
}

// AccountKey represents a single account involved in a transaction,
// as returned in the "accounts" transaction detail mode.
type AccountKey struct {
// The account's public key.
Pubkey solana.PublicKey `json:"pubkey"`

// Whether this account signed the transaction.
Signer bool `json:"signer"`

// Whether the transaction marks this account as writable.
Writable bool `json:"writable"`

// The source of the account key: "transaction" for keys from the
// message itself, "lookupTable" for keys resolved from address
// lookup tables. Nil for legacy transactions.
Source *AccountKeySource `json:"source,omitempty"`
}

type AccountKeySource string

const (
AccountKeySourceTransaction AccountKeySource = "transaction"
AccountKeySourceLookupTable AccountKeySource = "lookupTable"
)

type TransactionParsed struct {
Meta *TransactionMeta `json:"meta,omitempty"`
Transaction *solana.Transaction `json:"transaction"`
Expand Down Expand Up @@ -258,6 +310,9 @@ type TransactionSignature struct {
BlockTime *solana.UnixTimeSeconds `json:"blockTime,omitempty"`

ConfirmationStatus ConfirmationStatusType `json:"confirmationStatus,omitempty"`

// The transaction's index within the block.
TransactionIndex *uint32 `json:"transactionIndex,omitempty"`
}

type GetAccountInfoResult struct {
Expand Down Expand Up @@ -406,10 +461,21 @@ type GetProgramAccountsOpts struct {
// Filter results using various filter objects;
// account must meet all filter criteria to be included in results.
Filters []RPCFilter `json:"filters,omitempty"`

// Wrap the result in an RpcResponse JSON object with context.
WithContext *bool `json:"withContext,omitempty"`

// Sort the results (useful for deterministic pagination).
SortResults *bool `json:"sortResults,omitempty"`
}

type GetProgramAccountsResult []*KeyedAccount

type GetProgramAccountsWithContextResult struct {
RPCContext
Value GetProgramAccountsResult `json:"value"`
}

type KeyedAccount struct {
Pubkey solana.PublicKey `json:"pubkey"`
Account *Account `json:"account"`
Expand Down
Loading