Skip to content

Commit

Permalink
Refactor getVersionInfo and getNetwork RPC to not use HTTP endpoint /…
Browse files Browse the repository at this point in the history
…info on core (#198)

* Refactor getVersionInfo and getNetwork to not use HTTP endpoint /info

* Fix lint errors

* Fix lint errors part2

* Change log level

* Fix review comments

* Add benchmark and tests for getProtocolVersion
  • Loading branch information
psheth9 authored Jul 18, 2024
1 parent de7b040 commit d3f0c65
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 37 deletions.
2 changes: 2 additions & 0 deletions cmd/soroban-rpc/internal/daemon/interfaces/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/prometheus/client_golang/prometheus"

"github.com/stellar/go/ingest/ledgerbackend"
proto "github.com/stellar/go/protocols/stellarcore"
)

Expand All @@ -15,6 +16,7 @@ type Daemon interface {
MetricsRegistry() *prometheus.Registry
MetricsNamespace() string
CoreClient() CoreClient
GetCore() *ledgerbackend.CaptiveStellarCore
}

type CoreClient interface {
Expand Down
6 changes: 6 additions & 0 deletions cmd/soroban-rpc/internal/daemon/interfaces/noOpDaemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/prometheus/client_golang/prometheus"

"github.com/stellar/go/ingest/ledgerbackend"
proto "github.com/stellar/go/protocols/stellarcore"
)

Expand All @@ -14,6 +15,7 @@ type NoOpDaemon struct {
metricsRegistry *prometheus.Registry
metricsNamespace string
coreClient noOpCoreClient
core *ledgerbackend.CaptiveStellarCore
}

func MakeNoOpDeamon() *NoOpDaemon {
Expand All @@ -36,6 +38,10 @@ func (d *NoOpDaemon) CoreClient() CoreClient {
return d.coreClient
}

func (d *NoOpDaemon) GetCore() *ledgerbackend.CaptiveStellarCore {
return d.core
}

type noOpCoreClient struct{}

func (s noOpCoreClient) Info(context.Context) (*proto.InfoResponse, error) {
Expand Down
5 changes: 5 additions & 0 deletions cmd/soroban-rpc/internal/daemon/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/prometheus/client_golang/prometheus/collectors"

"github.com/stellar/go/clients/stellarcore"
"github.com/stellar/go/ingest/ledgerbackend"
proto "github.com/stellar/go/protocols/stellarcore"
supportlog "github.com/stellar/go/support/log"
"github.com/stellar/go/support/logmetrics"
Expand Down Expand Up @@ -106,6 +107,10 @@ func (d *Daemon) CoreClient() interfaces.CoreClient {
return d.coreClient
}

func (d *Daemon) GetCore() *ledgerbackend.CaptiveStellarCore {
return d.core
}

func (d *Daemon) Logger() *supportlog.Entry {
return d.logger
}
9 changes: 7 additions & 2 deletions cmd/soroban-rpc/internal/jsonrpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,13 @@ func NewJSONRPCHandler(cfg *config.Config, params HandlerParams) Handler {
requestDurationLimit: cfg.MaxGetEventsExecutionDuration,
},
{
methodName: "getNetwork",
underlyingHandler: methods.NewGetNetworkHandler(params.Daemon, cfg.NetworkPassphrase, cfg.FriendbotURL),
methodName: "getNetwork",
underlyingHandler: methods.NewGetNetworkHandler(
cfg.NetworkPassphrase,
cfg.FriendbotURL,
params.LedgerEntryReader,
params.LedgerReader,
),
longName: "get_network",
queueLimit: cfg.RequestBacklogGetNetworkQueueLimit,
requestDurationLimit: cfg.MaxGetNetworkExecutionDuration,
Expand Down
19 changes: 12 additions & 7 deletions cmd/soroban-rpc/internal/methods/get_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (

"github.com/creachadair/jrpc2"

"github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/daemon/interfaces"
"github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/db"
)

type GetNetworkRequest struct{}
Expand All @@ -17,20 +17,25 @@ type GetNetworkResponse struct {
}

// NewGetNetworkHandler returns a json rpc handler to for the getNetwork method
func NewGetNetworkHandler(daemon interfaces.Daemon, networkPassphrase, friendbotURL string) jrpc2.Handler {
coreClient := daemon.CoreClient()
func NewGetNetworkHandler(
networkPassphrase string,
friendbotURL string,
ledgerEntryReader db.LedgerEntryReader,
ledgerReader db.LedgerReader,
) jrpc2.Handler {
return NewHandler(func(ctx context.Context, request GetNetworkRequest) (GetNetworkResponse, error) {
info, err := coreClient.Info(ctx)
protocolVersion, err := getProtocolVersion(ctx, ledgerEntryReader, ledgerReader)
if err != nil {
return GetNetworkResponse{}, (&jrpc2.Error{
return GetNetworkResponse{}, &jrpc2.Error{
Code: jrpc2.InternalError,
Message: err.Error(),
})
}
}

return GetNetworkResponse{
FriendbotURL: friendbotURL,
Passphrase: networkPassphrase,
ProtocolVersion: info.Info.ProtocolVersion,
ProtocolVersion: int(protocolVersion),
}, nil
})
}
38 changes: 11 additions & 27 deletions cmd/soroban-rpc/internal/methods/get_version_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,35 +22,19 @@ type GetVersionInfoResponse struct {
ProtocolVersion uint32 `json:"protocol_version"` //nolint:tagliatelle
}

func NewGetVersionInfoHandler(logger *log.Entry, ledgerEntryReader db.LedgerEntryReader, ledgerReader db.LedgerReader, daemon interfaces.Daemon) jrpc2.Handler {
coreClient := daemon.CoreClient()
return handler.New(func(ctx context.Context) (GetVersionInfoResponse, error) {
var captiveCoreVersion string
info, err := coreClient.Info(ctx)
if err != nil {
logger.WithError(err).Info("error occurred while calling Info endpoint of core")
} else {
captiveCoreVersion = info.Info.Build
}

// Fetch Protocol version
var protocolVersion uint32
readTx, err := ledgerEntryReader.NewCachedTx(ctx)
if err != nil {
logger.WithError(err).Info("Cannot create read transaction")
}
defer func() {
_ = readTx.Done()
}()
func NewGetVersionInfoHandler(
logger *log.Entry,
ledgerEntryReader db.LedgerEntryReader,
ledgerReader db.LedgerReader,
daemon interfaces.Daemon,
) jrpc2.Handler {
core := daemon.GetCore()

latestLedger, err := readTx.GetLatestLedgerSequence()
if err != nil {
logger.WithError(err).Info("error occurred while getting latest ledger")
}

_, protocolVersion, err = getBucketListSizeAndProtocolVersion(ctx, ledgerReader, latestLedger)
return handler.New(func(ctx context.Context) (GetVersionInfoResponse, error) {
captiveCoreVersion := core.GetCoreVersion()
protocolVersion, err := getProtocolVersion(ctx, ledgerEntryReader, ledgerReader)
if err != nil {
logger.WithError(err).Info("error occurred while fetching protocol version")
logger.WithError(err).Error("failed to fetch protocol version")
}

return GetVersionInfoResponse{
Expand Down
6 changes: 5 additions & 1 deletion cmd/soroban-rpc/internal/methods/simulate_transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,11 @@ func base64EncodeSlice(in [][]byte) []string {
return result
}

func getBucketListSizeAndProtocolVersion(ctx context.Context, ledgerReader db.LedgerReader, latestLedger uint32) (uint64, uint32, error) {
func getBucketListSizeAndProtocolVersion(
ctx context.Context,
ledgerReader db.LedgerReader,
latestLedger uint32,
) (uint64, uint32, error) {
// obtain bucket size
closeMeta, ok, err := ledgerReader.GetLedger(ctx, latestLedger)
if err != nil {
Expand Down
32 changes: 32 additions & 0 deletions cmd/soroban-rpc/internal/methods/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package methods

import (
"context"
"fmt"

"github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/db"
)

func getProtocolVersion(
ctx context.Context,
ledgerEntryReader db.LedgerEntryReader,
ledgerReader db.LedgerReader,
) (uint32, error) {
latestLedger, err := ledgerEntryReader.GetLatestLedgerSequence(ctx)
if err != nil {
return 0, err
}

// obtain bucket size
closeMeta, ok, err := ledgerReader.GetLedger(ctx, latestLedger)
if err != nil {
return 0, err
}
if !ok {
return 0, fmt.Errorf("missing meta for latest ledger (%d)", latestLedger)
}
if closeMeta.V != 1 {
return 0, fmt.Errorf("latest ledger (%d) meta has unexpected verion (%d)", latestLedger, closeMeta.V)
}
return uint32(closeMeta.V1.LedgerHeader.Header.LedgerVersion), nil
}
92 changes: 92 additions & 0 deletions cmd/soroban-rpc/internal/methods/util_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package methods

import (
"context"
"path"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/stellar/go/support/log"
"github.com/stellar/go/xdr"

"github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/daemon/interfaces"
"github.com/stellar/soroban-rpc/cmd/soroban-rpc/internal/db"
)

func BenchmarkGetProtocolVersion(b *testing.B) {
dbx := NewTestDB(b)
daemon := interfaces.MakeNoOpDeamon()

ledgerReader := db.NewLedgerReader(dbx)
_, exists, err := ledgerReader.GetLedger(context.Background(), 1)
require.NoError(b, err)
assert.False(b, exists)

ledgerSequence := uint32(1)
tx, err := db.NewReadWriter(log.DefaultLogger, dbx, daemon, 150, 15, "passphrase").NewTx(context.Background())
require.NoError(b, err)
require.NoError(b, tx.LedgerWriter().InsertLedger(createMockLedgerCloseMeta(ledgerSequence)))
require.NoError(b, tx.Commit(ledgerSequence))

ledgerEntryReader := db.NewLedgerEntryReader(dbx)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := getProtocolVersion(context.TODO(), ledgerEntryReader, ledgerReader)
if err != nil {
b.Fatalf("getProtocolVersion failed: %v", err)
}
}
}

func TestGetProtocolVersion(t *testing.T) {
dbx := NewTestDB(t)
daemon := interfaces.MakeNoOpDeamon()

ledgerReader := db.NewLedgerReader(dbx)
_, exists, err := ledgerReader.GetLedger(context.Background(), 1)
require.NoError(t, err)
assert.False(t, exists)

ledgerSequence := uint32(1)
tx, err := db.NewReadWriter(log.DefaultLogger, dbx, daemon, 150, 15, "passphrase").NewTx(context.Background())
require.NoError(t, err)
require.NoError(t, tx.LedgerWriter().InsertLedger(createMockLedgerCloseMeta(ledgerSequence)))
require.NoError(t, tx.Commit(ledgerSequence))

ledgerEntryReader := db.NewLedgerEntryReader(dbx)
protocolVersion, err := getProtocolVersion(context.TODO(), ledgerEntryReader, ledgerReader)
require.NoError(t, err)
require.Equal(t, uint32(20), protocolVersion)
}

func createMockLedgerCloseMeta(ledgerSequence uint32) xdr.LedgerCloseMeta {
return xdr.LedgerCloseMeta{
V: 1,
V1: &xdr.LedgerCloseMetaV1{
LedgerHeader: xdr.LedgerHeaderHistoryEntry{
Hash: xdr.Hash{},
Header: xdr.LedgerHeader{
LedgerSeq: xdr.Uint32(ledgerSequence),
LedgerVersion: xdr.Uint32(20),
},
},
TxSet: xdr.GeneralizedTransactionSet{
V: 1,
V1TxSet: &xdr.TransactionSetV1{},
},
},
}
}

func NewTestDB(tb testing.TB) *db.DB {
tmp := tb.TempDir()
dbPath := path.Join(tmp, "db.sqlite")
db, err := db.OpenSQLiteDB(dbPath)
require.NoError(tb, err)
tb.Cleanup(func() {
require.NoError(tb, db.Close())
})
return db
}

0 comments on commit d3f0c65

Please sign in to comment.