Skip to content

Commit

Permalink
feat(rpc): add get program account
Browse files Browse the repository at this point in the history
  • Loading branch information
yihau committed Sep 3, 2021
1 parent df34078 commit a6ac85c
Show file tree
Hide file tree
Showing 2 changed files with 319 additions and 60 deletions.
134 changes: 74 additions & 60 deletions client/rpc/get_program_accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,93 +2,107 @@ package rpc

import (
"context"
"encoding/json"
"errors"
)

type GetProgramAccountsConfig struct {
Encoding Encoding `json:"encoding"`
Commitment Commitment `json:"commitment"`
DataSlice GetProgramAccountsConfigDataSlice `json:"dataSlice"`
// filter should be either GetProgramAccountsConfigFilterMemCmp or GetProgramAccountsConfigFilterDataSize
Filters []interface{} `json:"filters"`
// GetProgramAccountsResponse is a full rpc response for `getProgramAccounts`
type GetProgramAccountsResponse struct {
GeneralResponse
Result []GetProgramAccounts `json:"result"`
}

type getProgramAccountsConfig struct {
Encoding *Encoding `json:"encoding,omitempty"`
Commitment *Commitment `json:"commitment,omitempty"`
DataSlice *GetProgramAccountsConfigDataSlice `json:"dataSlice,omitempty"`
Filters *[]interface{} `json:"filters,omitempty"`
WithContext bool `json:"withContext"`
// GetProgramAccountsResponse is a full rpc response for `getProgramAccounts` with context
type GetProgramAccountsWithContextResponse struct {
GeneralResponse
Result GetProgramAccountsWithContextResult `json:"result"`
}

func (cfg GetProgramAccountsConfig) MarshalJSON() ([]byte, error) {
config := getProgramAccountsConfig{}

if cfg.Encoding != "" {
config.Encoding = &cfg.Encoding
}
type GetProgramAccountsConfigEncoding string

if cfg.Commitment != "" {
config.Commitment = &cfg.Commitment
}
const (
// GetProgramAccountsConfigEncodingBase58 limited to Account data of less than 128 bytes
GetProgramAccountsConfigEncodingBase58 GetProgramAccountsConfigEncoding = "base58"
GetProgramAccountsConfigEncodingJsonParsed GetProgramAccountsConfigEncoding = "jsonParsed"
GetProgramAccountsConfigEncodingBase64 GetProgramAccountsConfigEncoding = "base64"
GetProgramAccountsConfigEncodingBase64Zstd GetProgramAccountsConfigEncoding = "base64+zstd"
)

if cfg.DataSlice != (GetProgramAccountsConfigDataSlice{}) {
config.DataSlice = &cfg.DataSlice
}
// GetProgramAccountsConfig is a option config for `getProgramAccounts`
type GetProgramAccountsConfig struct {
Encoding GetProgramAccountsConfigEncoding `json:"encoding,omitempty"`
Commitment Commitment `json:"commitment,omitempty"`
DataSlice *GetProgramAccountsConfigDataSlice `json:"dataSlice,omitempty"`
Filters []GetProgramAccountsConfigFilter `json:"filters,omitempty"`
}

if len(cfg.Filters) != 0 {
config.Filters = &cfg.Filters
}
type getProgramAccountsConfig struct {
GetProgramAccountsConfig
WithContext bool `json:"withContext,omitempty"`
}

config.WithContext = true
// GetProgramAccountsConfigDataSlice is a part of GetProgramAccountsConfig
type GetProgramAccountsConfigDataSlice struct {
Offset uint64 `json:"offset"`
Length uint64 `json:"length"`
}

return json.Marshal(config)
// GetProgramAccountsConfigFilter you can set either MemCmp or DataSize but can be both, if needed, separate them into two
type GetProgramAccountsConfigFilter struct {
MemCmp *GetProgramAccountsConfigFilterMemCmp `json:"memcmp,omitempty"`
DataSize uint64 `json:"dataSize,omitempty"`
}

type GetProgramAccountsConfigFilterMemCmp struct {
Offset uint64 `json:"offset"`
Bytes string `json:"bytes"`
}

type GetProgramAccountsConfigFilterDataSize struct {
DataSize uint64 `json:"dataSize"`
}

type GetProgramAccountsConfigDataSlice struct {
Offset uint64 `json:"offset"`
Length uint64 `json:"length"`
type GetProgramAccounts struct {
Pubkey string `json:"pubkey"`
Account GetProgramAccountsAccount `json:"account"`
}

type GetProgramAccountsAccount struct {
Data interface{} `json:"data"`
Executable bool `json:"executable"`
Lamports uint64 `json:"lamports"`
Owner string `json:"owner"`
Rentepoch uint64 `json:"rentEpoch"`
RentEpoch uint64 `json:"rentEpoch"`
Data interface{} `json:"data"`
Executable bool `json:"executable"`
}

type GetProgramAccounts struct {
Account GetProgramAccountsAccount `json:"account"`
Pubkey string `json:"pubkey"`
type GetProgramAccountsWithContextResult struct {
Context Context `json:"context"`
Value []GetProgramAccounts `json:"value"`
}

// GetProgramAccounts returns all accounts owned by the provided program pubkey
func (s *RpcClient) GetProgramAccounts(ctx context.Context, base58Addr string, cfg GetProgramAccountsConfig) ([]GetProgramAccounts, error) {
res := struct {
GeneralResponse
Result struct {
Context Context `json:"context"`
Value []GetProgramAccounts `json:"value"`
} `json:"result"`
}{}
func (c *RpcClient) GetProgramAccounts(ctx context.Context, programId string) (GetProgramAccountsResponse, error) {
return c.processGetProgramAccounts(c.Call(ctx, "getProgramAccounts", programId))
}

err := s.request(ctx, "getProgramAccounts", []interface{}{base58Addr, cfg}, &res)
if err != nil {
return []GetProgramAccounts{}, err
}
if res.Error != nil {
return []GetProgramAccounts{}, errors.New(res.Error.Message)
func (c *RpcClient) GetProgramAccountsWithConfig(ctx context.Context, programId string, cfg GetProgramAccountsConfig) (GetProgramAccountsResponse, error) {
return c.processGetProgramAccounts(c.Call(ctx, "getProgramAccounts", programId, c.toInternalGetProgramAccountsConfig(cfg, false)))
}

func (c *RpcClient) processGetProgramAccounts(body []byte, rpcErr error) (res GetProgramAccountsResponse, err error) {
err = c.processRpcCall(body, rpcErr, &res)
return
}

func (c *RpcClient) GetProgramAccountsWithContext(ctx context.Context, programId string) (GetProgramAccountsWithContextResponse, error) {
return c.processGetProgramAccountsWithContext(c.Call(ctx, "getProgramAccounts", programId, c.toInternalGetProgramAccountsConfig(GetProgramAccountsConfig{}, true)))
}

func (c *RpcClient) GetProgramAccountsWithContextAndConfig(ctx context.Context, programId string, cfg GetProgramAccountsConfig) (GetProgramAccountsWithContextResponse, error) {
return c.processGetProgramAccountsWithContext(c.Call(ctx, "getProgramAccounts", programId, c.toInternalGetProgramAccountsConfig(cfg, true)))
}

func (c *RpcClient) processGetProgramAccountsWithContext(body []byte, rpcErr error) (res GetProgramAccountsWithContextResponse, err error) {
err = c.processRpcCall(body, rpcErr, &res)
return
}

func (c *RpcClient) toInternalGetProgramAccountsConfig(cfg GetProgramAccountsConfig, withContext bool) getProgramAccountsConfig {
return getProgramAccountsConfig{
GetProgramAccountsConfig: cfg,
WithContext: withContext,
}
return res.Result.Value, nil
}
Loading

0 comments on commit a6ac85c

Please sign in to comment.