Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace Horizon calls with RPC #93

Merged
merged 35 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
4843c66
Add GetLedgerEntries and GetAccountLedgerSeq to rpcService
aditya1702 Dec 19, 2024
8952c39
Use RPC ledgerEntries to get account detail instead of horizon
aditya1702 Dec 19, 2024
317d52f
Replace horizon in account sponsorship and transaction services
aditya1702 Dec 19, 2024
212b05a
Change function naming
aditya1702 Dec 19, 2024
f78b9ea
Change function naming - 2
aditya1702 Dec 19, 2024
eb33f06
Fix failing tests
aditya1702 Dec 19, 2024
1c17a60
Fix failing tests - 2
aditya1702 Dec 19, 2024
d480194
Fix failing tests - 3
aditya1702 Dec 19, 2024
e26a503
Merge remote-tracking branch 'refs/remotes/upstream/main' into replac…
aditya1702 Dec 20, 2024
cd7c6f0
Fix tests after merging from master
aditya1702 Dec 20, 2024
6caa7cb
Replace horizon with tss.Router for creating channel accounts
aditya1702 Dec 20, 2024
4c89e14
Remove unused variable
aditya1702 Dec 20, 2024
eeeb0c3
Go mod tidy
aditya1702 Dec 20, 2024
38cd52b
Add new tests
aditya1702 Dec 20, 2024
7cb4091
Add other cases in switch-case
aditya1702 Dec 20, 2024
b634c74
Add other cases in switch-case - 2
aditya1702 Dec 20, 2024
2f70661
Add other cases in switch-case - 3
aditya1702 Dec 20, 2024
8a8d1f2
Add account public key to error string
aditya1702 Dec 20, 2024
319d1e6
Small nit changes
aditya1702 Jan 2, 2025
0b12aa3
small nit changes - 2
aditya1702 Jan 2, 2025
167fc63
Fix how error is checked
aditya1702 Jan 3, 2025
ae218a1
Merge remote-tracking branch 'upstream/main' into replace-horizon
aditya1702 Jan 3, 2025
f2b4f36
Use RPC to submit create channel account txn instead of TSS
aditya1702 Jan 7, 2025
01a64ad
add rpc health check before creating channel accounts
aditya1702 Jan 7, 2025
64a2e97
Use ctx to cancel the running goroutine for trackingRPCHealth
aditya1702 Jan 7, 2025
e29f01d
update tests to account for new changes
aditya1702 Jan 7, 2025
ca87960
remove router from channel account service
aditya1702 Jan 7, 2025
cf55a99
ignore switch-case linter
aditya1702 Jan 7, 2025
54b438d
change function name
aditya1702 Jan 8, 2025
7e67128
add context timeouts to avoid waiting for rpc health indefinitely
aditya1702 Jan 8, 2025
a5528ae
add cancelTimeout()
aditya1702 Jan 8, 2025
f75bd37
do not close heartbeat channel
aditya1702 Jan 9, 2025
d860d8b
timeout message
aditya1702 Jan 9, 2025
f5579ab
remove timeout for rpc in channel accounts
aditya1702 Jan 9, 2025
269abe3
change number of retries
aditya1702 Jan 9, 2025
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
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@
captive-core*/
.env
.DS_Store
env.sh
env.sh
.idea
__debug_bin*
12 changes: 2 additions & 10 deletions cmd/channel_account.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@ package cmd

import (
"fmt"
"net/http"
"strconv"
"time"

"github.com/spf13/cobra"
"github.com/stellar/go/clients/horizonclient"
"github.com/stellar/go/support/config"
"github.com/stellar/go/support/log"

"github.com/stellar/wallet-backend/cmd/utils"
"github.com/stellar/wallet-backend/internal/db"
"github.com/stellar/wallet-backend/internal/services"
Expand All @@ -19,7 +17,6 @@ import (

type channelAccountCmdConfigOptions struct {
DatabaseURL string
HorizonClientURL string
NetworkPassphrase string
BaseFee int
DistributionAccountPrivateKey string
Expand All @@ -36,7 +33,6 @@ func (c *channelAccountCmd) Command() *cobra.Command {
utils.DatabaseURLOption(&cfg.DatabaseURL),
utils.NetworkPassphraseOption(&cfg.NetworkPassphrase),
utils.BaseFeeOption(&cfg.BaseFee),
utils.HorizonClientURLOption(&cfg.HorizonClientURL),
utils.ChannelAccountEncryptionPassphraseOption(&cfg.EncryptionPassphrase),
}

Expand Down Expand Up @@ -78,11 +74,7 @@ func (c *channelAccountCmd) Command() *cobra.Command {
channelAccountModel := store.ChannelAccountModel{DB: dbConnectionPool}
privateKeyEncrypter := signingutils.DefaultPrivateKeyEncrypter{}
c.channelAccountService, err = services.NewChannelAccountService(services.ChannelAccountServiceOptions{
DB: dbConnectionPool,
HorizonClient: &horizonclient.Client{
HorizonURL: cfg.HorizonClientURL,
HTTP: &http.Client{Timeout: 40 * time.Second},
},
DB: dbConnectionPool,
BaseFee: int64(cfg.BaseFee),
DistributionAccountSignatureClient: signatureClient,
ChannelAccountStore: &channelAccountModel,
Expand Down
2 changes: 1 addition & 1 deletion cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/spf13/cobra"
"github.com/stellar/go/support/config"
"github.com/stellar/go/support/log"

"github.com/stellar/wallet-backend/cmd/utils"
"github.com/stellar/wallet-backend/internal/apptracker/sentry"
"github.com/stellar/wallet-backend/internal/db"
Expand All @@ -28,7 +29,6 @@ func (c *serveCmd) Command() *cobra.Command {
utils.LogLevelOption(&cfg.LogLevel),
utils.NetworkPassphraseOption(&cfg.NetworkPassphrase),
utils.BaseFeeOption(&cfg.BaseFee),
utils.HorizonClientURLOption(&cfg.HorizonClientURL),
utils.RPCURLOption(&cfg.RPCURL),
utils.RPCCallerChannelBufferSizeOption(&cfg.RPCCallerServiceChannelBufferSize),
utils.RPCCallerChannelMaxWorkersOption(&cfg.RPCCallerServiceChannelMaxWorkers),
Expand Down
13 changes: 1 addition & 12 deletions cmd/utils/global_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import (
"go/types"

"github.com/sirupsen/logrus"
"github.com/stellar/go/clients/horizonclient"
"github.com/stellar/go/network"
"github.com/stellar/go/support/config"
"github.com/stellar/go/txnbuild"

"github.com/stellar/wallet-backend/internal/signing"
)

Expand Down Expand Up @@ -56,17 +56,6 @@ func BaseFeeOption(configKey *int) *config.ConfigOption {
}
}

func HorizonClientURLOption(configKey *string) *config.ConfigOption {
return &config.ConfigOption{
Name: "horizon-url",
Usage: "The URL of the Stellar Horizon server which this application will communicate with.",
OptType: types.String,
ConfigKey: configKey,
FlagDefault: horizonclient.DefaultTestNetClient.HorizonURL,
Required: true,
}
}

func RPCURLOption(configKey *string) *config.ConfigOption {
return &config.ConfigOption{
Name: "rpc-url",
Expand Down
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ require (
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/manucorporat/sse v0.0.0-20160126180136-ee05b128a739 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
Expand Down
14 changes: 14 additions & 0 deletions internal/entities/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,19 @@ type RPCSendTransactionResult struct {
ErrorResultXDR string `json:"errorResultXdr"`
}

type LedgerEntryResult struct {
KeyXDR string `json:"key,omitempty"`
DataXDR string `json:"xdr,omitempty"`
LastModifiedLedger uint32 `json:"lastModifiedLedgerSeq"`
// The ledger sequence until the entry is live, available for entries that have associated ttl ledger entries.
LiveUntilLedgerSeq *uint32 `json:"liveUntilLedgerSeq,omitempty"`
}

type RPCGetLedgerEntriesResult struct {
LatestLedger uint32 `json:"latestLedger"`
Entries []LedgerEntryResult `json:"entries"`
}

type RPCPagination struct {
Cursor string `json:"cursor,omitempty"`
Limit int `json:"limit"`
Expand All @@ -87,4 +100,5 @@ type RPCParams struct {
Hash string `json:"hash,omitempty"`
StartLedger int64 `json:"startLedger,omitempty"`
Pagination RPCPagination `json:"pagination,omitempty"`
LedgerKeys []string `json:"keys,omitempty"`
}
59 changes: 27 additions & 32 deletions internal/serve/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import (

"github.com/go-chi/chi"
"github.com/sirupsen/logrus"
"github.com/stellar/go/clients/horizonclient"
supporthttp "github.com/stellar/go/support/http"
"github.com/stellar/go/support/log"
"github.com/stellar/go/support/render/health"
"github.com/stellar/go/xdr"

"github.com/stellar/wallet-backend/internal/apptracker"
"github.com/stellar/wallet-backend/internal/data"
"github.com/stellar/wallet-backend/internal/db"
Expand Down Expand Up @@ -60,7 +60,6 @@ type Configs struct {
NetworkPassphrase string
MaxSponsoredBaseReserves int
BaseFee int
HorizonClientURL string
DistributionAccountSignatureClient signing.SignatureClient
ChannelAccountSignatureClient signing.SignatureClient
// TSS
Expand Down Expand Up @@ -150,9 +149,10 @@ func initHandlerDeps(cfg Configs) (handlerDeps, error) {
return handlerDeps{}, fmt.Errorf("instantiating stellar signature verifier: %w", err)
}

horizonClient := horizonclient.Client{
HorizonURL: cfg.HorizonClientURL,
HTTP: &http.Client{Timeout: 40 * time.Second},
httpClient := http.Client{Timeout: time.Duration(30 * time.Second)}
rpcService, err := services.NewRPCService(cfg.RPCURL, &httpClient)
if err != nil {
return handlerDeps{}, fmt.Errorf("instantiating rpc service: %w", err)
}

accountService, err := services.NewAccountService(models)
Expand All @@ -163,7 +163,7 @@ func initHandlerDeps(cfg Configs) (handlerDeps, error) {
accountSponsorshipService, err := services.NewAccountSponsorshipService(services.AccountSponsorshipServiceOptions{
DistributionAccountSignatureClient: cfg.DistributionAccountSignatureClient,
ChannelAccountSignatureClient: cfg.ChannelAccountSignatureClient,
HorizonClient: &horizonClient,
RPCService: rpcService,
MaxSponsoredBaseReserves: cfg.MaxSponsoredBaseReserves,
BaseFee: int64(cfg.BaseFee),
Models: models,
Expand All @@ -178,50 +178,31 @@ func initHandlerDeps(cfg Configs) (handlerDeps, error) {
return handlerDeps{}, fmt.Errorf("instantiating payment service: %w", err)
}

channelAccountService, err := services.NewChannelAccountService(services.ChannelAccountServiceOptions{
DB: dbConnectionPool,
HorizonClient: &horizonClient,
BaseFee: int64(cfg.BaseFee),
DistributionAccountSignatureClient: cfg.DistributionAccountSignatureClient,
ChannelAccountStore: store.NewChannelAccountModel(dbConnectionPool),
PrivateKeyEncrypter: &signingutils.DefaultPrivateKeyEncrypter{},
EncryptionPassphrase: cfg.EncryptionPassphrase,
})
if err != nil {
return handlerDeps{}, fmt.Errorf("instantiating channel account service: %w", err)
}
go ensureChannelAccounts(channelAccountService, int64(cfg.NumberOfChannelAccounts))

// TSS setup
tssTxService, err := tssservices.NewTransactionService(tssservices.TransactionServiceOptions{
DistributionAccountSignatureClient: cfg.DistributionAccountSignatureClient,
ChannelAccountSignatureClient: cfg.ChannelAccountSignatureClient,
HorizonClient: &horizonClient,
RPCService: rpcService,
BaseFee: int64(cfg.BaseFee),
})

if err != nil {
return handlerDeps{}, fmt.Errorf("instantiating tss transaction service: %w", err)
}
httpClient := http.Client{Timeout: time.Duration(30 * time.Second)}
rpcService, err := services.NewRPCService(cfg.RPCURL, &httpClient)
if err != nil {
return handlerDeps{}, fmt.Errorf("instantiating rpc service: %w", err)
}

store, err := tssstore.NewStore(dbConnectionPool)
tssStore, err := tssstore.NewStore(dbConnectionPool)
if err != nil {
return handlerDeps{}, fmt.Errorf("instantiating tss store: %w", err)
}
txManager := tssservices.NewTransactionManager(tssservices.TransactionManagerConfigs{
TxService: tssTxService,
RPCService: rpcService,
Store: store,
Store: tssStore,
})

rpcCallerChannel := tsschannel.NewRPCCallerChannel(tsschannel.RPCCallerChannelConfigs{
TxManager: txManager,
Store: store,
Store: tssStore,
MaxBufferSize: cfg.RPCCallerServiceChannelBufferSize,
MaxWorkers: cfg.RPCCallerServiceChannelMaxWorkers,
})
Expand All @@ -245,7 +226,7 @@ func initHandlerDeps(cfg Configs) (handlerDeps, error) {
httpClient = http.Client{Timeout: time.Duration(30 * time.Second)}
webhookChannel := tsschannel.NewWebhookChannel(tsschannel.WebhookChannelConfigs{
HTTPClient: &httpClient,
Store: store,
Store: tssStore,
MaxBufferSize: cfg.WebhookHandlerServiceChannelMaxBufferSize,
MaxWorkers: cfg.WebhookHandlerServiceChannelMaxWorkers,
MaxRetries: cfg.WebhookHandlerServiceChannelMaxRetries,
Expand All @@ -263,11 +244,25 @@ func initHandlerDeps(cfg Configs) (handlerDeps, error) {
errorJitterChannel.SetRouter(router)
errorNonJitterChannel.SetRouter(router)

poolPopulator, err := tssservices.NewPoolPopulator(router, store, rpcService)
poolPopulator, err := tssservices.NewPoolPopulator(router, tssStore, rpcService)
if err != nil {
return handlerDeps{}, fmt.Errorf("instantiating tss pool populator")
}

channelAccountService, err := services.NewChannelAccountService(services.ChannelAccountServiceOptions{
DB: dbConnectionPool,
RPCService: rpcService,
BaseFee: int64(cfg.BaseFee),
DistributionAccountSignatureClient: cfg.DistributionAccountSignatureClient,
ChannelAccountStore: store.NewChannelAccountModel(dbConnectionPool),
PrivateKeyEncrypter: &signingutils.DefaultPrivateKeyEncrypter{},
EncryptionPassphrase: cfg.EncryptionPassphrase,
})
if err != nil {
return handlerDeps{}, fmt.Errorf("instantiating channel account service: %w", err)
}
go ensureChannelAccounts(channelAccountService, int64(cfg.NumberOfChannelAccounts))

return handlerDeps{
Models: models,
SignatureVerifier: signatureVerifier,
Expand All @@ -284,7 +279,7 @@ func initHandlerDeps(cfg Configs) (handlerDeps, error) {
WebhookChannel: webhookChannel,
TSSRouter: router,
PoolPopulator: poolPopulator,
TSSStore: store,
TSSStore: tssStore,
TSSTransactionService: tssTxService,
}, nil
}
Expand Down
30 changes: 17 additions & 13 deletions internal/services/account_sponsorship_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import (
"fmt"
"slices"

"github.com/stellar/go/clients/horizonclient"
"github.com/stellar/go/support/log"
"github.com/stellar/go/txnbuild"
"github.com/stellar/go/xdr"

"github.com/stellar/wallet-backend/internal/data"
"github.com/stellar/wallet-backend/internal/entities"
"github.com/stellar/wallet-backend/internal/signing"
Expand All @@ -21,6 +21,7 @@ var (
ErrAccountNotEligibleForBeingSponsored = errors.New("account not eligible for being sponsored")
ErrFeeExceedsMaximumBaseFee = errors.New("fee exceeds maximum base fee to sponsor")
ErrNoSignaturesProvided = errors.New("should have at least one signature")
ErrAccountNotFound = errors.New("account not found")
)

type ErrOperationNotAllowed struct {
Expand All @@ -45,7 +46,7 @@ type AccountSponsorshipService interface {
type accountSponsorshipService struct {
DistributionAccountSignatureClient signing.SignatureClient
ChannelAccountSignatureClient signing.SignatureClient
HorizonClient horizonclient.ClientInterface
RPCService RPCService
MaxSponsoredBaseReserves int
BaseFee int64
Models *data.Models
Expand All @@ -56,11 +57,11 @@ var _ AccountSponsorshipService = (*accountSponsorshipService)(nil)

func (s *accountSponsorshipService) SponsorAccountCreationTransaction(ctx context.Context, accountToSponsor string, signers []entities.Signer, supportedAssets []entities.Asset) (string, string, error) {
// Check the accountToSponsor does not exist on Stellar
_, err := s.HorizonClient.AccountDetail(horizonclient.AccountRequest{AccountID: accountToSponsor})
_, err := s.RPCService.GetAccountLedgerSequence(accountToSponsor)
if err == nil {
return "", "", ErrAccountAlreadyExists
}
if !horizonclient.IsNotFoundError(err) {
if !errors.Is(err, ErrAccountNotFound) {
return "", "", fmt.Errorf("getting details for account %s: %w", accountToSponsor, err)
}

Expand Down Expand Up @@ -125,14 +126,17 @@ func (s *accountSponsorshipService) SponsorAccountCreationTransaction(ctx contex
return "", "", fmt.Errorf("getting channel account public key: %w", err)
}

channelAccount, err := s.HorizonClient.AccountDetail(horizonclient.AccountRequest{AccountID: channelAccountPublicKey})
channelAccountSeq, err := s.RPCService.GetAccountLedgerSequence(channelAccountPublicKey)
if err != nil {
return "", "", fmt.Errorf("getting distribution account details: %w", err)
return "", "", fmt.Errorf("getting sequence number for channel account public key: %s: %w", channelAccountPublicKey, err)
}

tx, err := txnbuild.NewTransaction(
txnbuild.TransactionParams{
SourceAccount: &channelAccount,
SourceAccount: &txnbuild.SimpleAccount{
AccountID: channelAccountPublicKey,
Sequence: channelAccountSeq,
},
IncrementSequenceNum: true,
Operations: ops,
BaseFee: s.BaseFee,
Expand Down Expand Up @@ -228,7 +232,7 @@ func (s *accountSponsorshipService) WrapTransaction(ctx context.Context, tx *txn
type AccountSponsorshipServiceOptions struct {
DistributionAccountSignatureClient signing.SignatureClient
ChannelAccountSignatureClient signing.SignatureClient
HorizonClient horizonclient.ClientInterface
RPCService RPCService
MaxSponsoredBaseReserves int
BaseFee int64
Models *data.Models
Expand All @@ -240,12 +244,12 @@ func (o *AccountSponsorshipServiceOptions) Validate() error {
return fmt.Errorf("distribution account signature client cannot be nil")
}

if o.ChannelAccountSignatureClient == nil {
return fmt.Errorf("channel account signature client cannot be nil")
if o.RPCService == nil {
return fmt.Errorf("rpc client cannot be nil")
}

if o.HorizonClient == nil {
return fmt.Errorf("horizon client cannot be nil")
if o.ChannelAccountSignatureClient == nil {
return fmt.Errorf("channel account signature client cannot be nil")
}

if o.BaseFee < int64(txnbuild.MinBaseFee) {
Expand All @@ -267,7 +271,7 @@ func NewAccountSponsorshipService(opts AccountSponsorshipServiceOptions) (*accou
return &accountSponsorshipService{
DistributionAccountSignatureClient: opts.DistributionAccountSignatureClient,
ChannelAccountSignatureClient: opts.ChannelAccountSignatureClient,
HorizonClient: opts.HorizonClient,
RPCService: opts.RPCService,
MaxSponsoredBaseReserves: opts.MaxSponsoredBaseReserves,
BaseFee: opts.BaseFee,
Models: opts.Models,
Expand Down
Loading
Loading