Skip to content

Commit

Permalink
Add getBlockTime method; closes #50
Browse files Browse the repository at this point in the history
  • Loading branch information
gagliardetto committed Sep 18, 2023
1 parent c24f03f commit a03ae27
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 19 deletions.
18 changes: 8 additions & 10 deletions cmd-rpc-server-car-getSignaturesForAddress.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,20 @@ type GetSignaturesForAddressParams struct {
func parseGetSignaturesForAddressParams(raw *json.RawMessage) (*GetSignaturesForAddressParams, error) {
var params []any
if err := json.Unmarshal(*raw, &params); err != nil {
klog.Errorf("failed to unmarshal params: %v", err)
return nil, err
return nil, fmt.Errorf("failed to unmarshal params: %w", err)
}
if len(params) < 1 {
return nil, fmt.Errorf("expected at least 1 param")
}
sigRaw, ok := params[0].(string)
if !ok {
klog.Errorf("first argument must be a string")
return nil, nil
return nil, fmt.Errorf("first argument must be a string")
}

out := &GetSignaturesForAddressParams{}
pk, err := solana.PublicKeyFromBase58(sigRaw)
if err != nil {
klog.Errorf("failed to parse pubkey from base58: %v", err)
return nil, err
return nil, fmt.Errorf("failed to parse pubkey from base58: %w", err)
}
out.Address = pk

Expand All @@ -60,8 +60,7 @@ func parseGetSignaturesForAddressParams(raw *json.RawMessage) (*GetSignaturesFor
if before, ok := before.(string); ok {
sig, err := solana.SignatureFromBase58(before)
if err != nil {
klog.Errorf("failed to parse signature from base58: %v", err)
return nil, err
return nil, fmt.Errorf("failed to parse signature from base58: %w", err)
}
out.Before = &sig
}
Expand All @@ -70,8 +69,7 @@ func parseGetSignaturesForAddressParams(raw *json.RawMessage) (*GetSignaturesFor
if after, ok := after.(string); ok {
sig, err := solana.SignatureFromBase58(after)
if err != nil {
klog.Errorf("failed to parse signature from base58: %v", err)
return nil, err
return nil, fmt.Errorf("failed to parse signature from base58: %w", err)
}
out.Until = &sig
}
Expand Down
55 changes: 55 additions & 0 deletions multiepoch-getBlockTime.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package main

import (
"context"
"errors"
"fmt"

"github.com/rpcpool/yellowstone-faithful/compactindex36"
"github.com/sourcegraph/jsonrpc2"
)

func (multi *MultiEpoch) handleGetBlockTime(ctx context.Context, conn *requestContext, req *jsonrpc2.Request) (*jsonrpc2.Error, error) {
blockNum, err := parseGetBlockTimeRequest(req.Params)
if err != nil {
return &jsonrpc2.Error{
Code: jsonrpc2.CodeInvalidParams,
Message: "Invalid params",
}, fmt.Errorf("failed to parse params: %w", err)
}

// find the epoch that contains the requested slot
epochNumber := CalcEpochForSlot(blockNum)
epochHandler, err := multi.GetEpoch(epochNumber)
if err != nil {
return &jsonrpc2.Error{
Code: CodeNotFound,
Message: fmt.Sprintf("Epoch %d is not available", epochNumber),
}, fmt.Errorf("failed to get epoch %d: %w", epochNumber, err)
}

block, err := epochHandler.GetBlock(WithSubrapghPrefetch(ctx, false), blockNum)
if err != nil {
if errors.Is(err, compactindex36.ErrNotFound) {
return &jsonrpc2.Error{
Code: CodeNotFound,
Message: fmt.Sprintf("Slot %d was skipped, or missing in long-term storage", blockNum),
}, err
} else {
return &jsonrpc2.Error{
Code: jsonrpc2.CodeInternalError,
Message: "Failed to get block",
}, fmt.Errorf("failed to get block: %w", err)
}
}
blockTime := uint64(block.Meta.Blocktime)
err = conn.ReplyRaw(
ctx,
req.ID,
blockTime,
)
if err != nil {
return nil, fmt.Errorf("failed to reply: %w", err)
}
return nil, nil
}
10 changes: 6 additions & 4 deletions multiepoch.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ func newMultiEpochHandler(handler *MultiEpoch, lsConf *ListenerConfig) func(ctx

klog.Infof("[%s] received request: %q", reqID, strings.TrimSpace(string(body)))

if proxy != nil && !isValidMethod(rpcRequest.Method) {
if proxy != nil && !isValidLocalMethod(rpcRequest.Method) {
klog.Infof("[%s] Unhandled method %q, proxying to %q", reqID, rpcRequest.Method, proxy.Addr)
// proxy the request to the target
proxyReq := fasthttp.AcquireRequest()
Expand Down Expand Up @@ -355,15 +355,15 @@ func newMultiEpochHandler(handler *MultiEpoch, lsConf *ListenerConfig) func(ctx
}

func sanitizeMethod(method string) string {
if isValidMethod(method) {
if isValidLocalMethod(method) {
return method
}
return "<unknown>"
}

func isValidMethod(method string) bool {
func isValidLocalMethod(method string) bool {
switch method {
case "getBlock", "getTransaction", "getSignaturesForAddress":
case "getBlock", "getTransaction", "getSignaturesForAddress", "getBlockTime":
return true
default:
return false
Expand All @@ -379,6 +379,8 @@ func (ser *MultiEpoch) handleRequest(ctx context.Context, conn *requestContext,
return ser.handleGetTransaction(ctx, conn, req)
case "getSignaturesForAddress":
return ser.handleGetSignaturesForAddress(ctx, conn, req)
case "getBlockTime":
return ser.handleGetBlockTime(ctx, conn, req)
default:
return &jsonrpc2.Error{
Code: jsonrpc2.CodeMethodNotFound,
Expand Down
28 changes: 23 additions & 5 deletions request-response.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"github.com/mr-tron/base58"
"github.com/sourcegraph/jsonrpc2"
"github.com/valyala/fasthttp"
"k8s.io/klog/v2"
)

type requestContext struct {
Expand Down Expand Up @@ -175,13 +174,14 @@ func (req *GetBlockRequest) Validate() error {
func parseGetBlockRequest(raw *json.RawMessage) (*GetBlockRequest, error) {
var params []any
if err := json.Unmarshal(*raw, &params); err != nil {
klog.Errorf("failed to unmarshal params: %v", err)
return nil, err
return nil, fmt.Errorf("failed to unmarshal params: %w", err)
}
if len(params) < 1 {
return nil, fmt.Errorf("params must have at least one argument")
}
slotRaw, ok := params[0].(float64)
if !ok {
klog.Errorf("first argument must be a number, got %T", params[0])
return nil, nil
return nil, fmt.Errorf("first argument must be a number, got %T", params[0])
}

out := &GetBlockRequest{
Expand Down Expand Up @@ -313,6 +313,9 @@ func parseGetTransactionRequest(raw *json.RawMessage) (*GetTransactionRequest, e
if err := json.Unmarshal(*raw, &params); err != nil {
return nil, fmt.Errorf("failed to unmarshal params: %w", err)
}
if len(params) < 1 {
return nil, fmt.Errorf("params must have at least one argument")
}
sigRaw, ok := params[0].(string)
if !ok {
return nil, fmt.Errorf("first argument must be a string, got %T", params[0])
Expand Down Expand Up @@ -412,3 +415,18 @@ func encodeBytesResponseBasedOnWantedEncoding(
return nil, fmt.Errorf("unsupported encoding %q", encoding)
}
}

func parseGetBlockTimeRequest(raw *json.RawMessage) (uint64, error) {
var params []any
if err := json.Unmarshal(*raw, &params); err != nil {
return 0, fmt.Errorf("failed to unmarshal params: %w", err)
}
if len(params) < 1 {
return 0, fmt.Errorf("params must have at least one argument")
}
blockRaw, ok := params[0].(float64)
if !ok {
return 0, fmt.Errorf("first argument must be a number, got %T", params[0])
}
return uint64(blockRaw), nil
}

0 comments on commit a03ae27

Please sign in to comment.