Skip to content

Commit 6726c10

Browse files
authored
Replace Horizon calls with RPC (#93)
Replace horizon with RPC
1 parent f0d66c0 commit 6726c10

16 files changed

+549
-302
lines changed

.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,6 @@
33
captive-core*/
44
.env
55
.DS_Store
6-
env.sh
6+
env.sh
7+
.idea
8+
__debug_bin*

cmd/channel_account.go

+2-10
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@ package cmd
22

33
import (
44
"fmt"
5-
"net/http"
65
"strconv"
7-
"time"
86

97
"github.com/spf13/cobra"
10-
"github.com/stellar/go/clients/horizonclient"
118
"github.com/stellar/go/support/config"
129
"github.com/stellar/go/support/log"
10+
1311
"github.com/stellar/wallet-backend/cmd/utils"
1412
"github.com/stellar/wallet-backend/internal/db"
1513
"github.com/stellar/wallet-backend/internal/services"
@@ -19,7 +17,6 @@ import (
1917

2018
type channelAccountCmdConfigOptions struct {
2119
DatabaseURL string
22-
HorizonClientURL string
2320
NetworkPassphrase string
2421
BaseFee int
2522
DistributionAccountPrivateKey string
@@ -36,7 +33,6 @@ func (c *channelAccountCmd) Command() *cobra.Command {
3633
utils.DatabaseURLOption(&cfg.DatabaseURL),
3734
utils.NetworkPassphraseOption(&cfg.NetworkPassphrase),
3835
utils.BaseFeeOption(&cfg.BaseFee),
39-
utils.HorizonClientURLOption(&cfg.HorizonClientURL),
4036
utils.ChannelAccountEncryptionPassphraseOption(&cfg.EncryptionPassphrase),
4137
}
4238

@@ -78,11 +74,7 @@ func (c *channelAccountCmd) Command() *cobra.Command {
7874
channelAccountModel := store.ChannelAccountModel{DB: dbConnectionPool}
7975
privateKeyEncrypter := signingutils.DefaultPrivateKeyEncrypter{}
8076
c.channelAccountService, err = services.NewChannelAccountService(services.ChannelAccountServiceOptions{
81-
DB: dbConnectionPool,
82-
HorizonClient: &horizonclient.Client{
83-
HorizonURL: cfg.HorizonClientURL,
84-
HTTP: &http.Client{Timeout: 40 * time.Second},
85-
},
77+
DB: dbConnectionPool,
8678
BaseFee: int64(cfg.BaseFee),
8779
DistributionAccountSignatureClient: signatureClient,
8880
ChannelAccountStore: &channelAccountModel,

cmd/serve.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/spf13/cobra"
99
"github.com/stellar/go/support/config"
1010
"github.com/stellar/go/support/log"
11+
1112
"github.com/stellar/wallet-backend/cmd/utils"
1213
"github.com/stellar/wallet-backend/internal/apptracker/sentry"
1314
"github.com/stellar/wallet-backend/internal/db"
@@ -28,7 +29,6 @@ func (c *serveCmd) Command() *cobra.Command {
2829
utils.LogLevelOption(&cfg.LogLevel),
2930
utils.NetworkPassphraseOption(&cfg.NetworkPassphrase),
3031
utils.BaseFeeOption(&cfg.BaseFee),
31-
utils.HorizonClientURLOption(&cfg.HorizonClientURL),
3232
utils.RPCURLOption(&cfg.RPCURL),
3333
utils.RPCCallerChannelBufferSizeOption(&cfg.RPCCallerServiceChannelBufferSize),
3434
utils.RPCCallerChannelMaxWorkersOption(&cfg.RPCCallerServiceChannelMaxWorkers),

cmd/utils/global_options.go

+1-12
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import (
44
"go/types"
55

66
"github.com/sirupsen/logrus"
7-
"github.com/stellar/go/clients/horizonclient"
87
"github.com/stellar/go/network"
98
"github.com/stellar/go/support/config"
109
"github.com/stellar/go/txnbuild"
10+
1111
"github.com/stellar/wallet-backend/internal/signing"
1212
)
1313

@@ -56,17 +56,6 @@ func BaseFeeOption(configKey *int) *config.ConfigOption {
5656
}
5757
}
5858

59-
func HorizonClientURLOption(configKey *string) *config.ConfigOption {
60-
return &config.ConfigOption{
61-
Name: "horizon-url",
62-
Usage: "The URL of the Stellar Horizon server which this application will communicate with.",
63-
OptType: types.String,
64-
ConfigKey: configKey,
65-
FlagDefault: horizonclient.DefaultTestNetClient.HorizonURL,
66-
Required: true,
67-
}
68-
}
69-
7059
func RPCURLOption(configKey *string) *config.ConfigOption {
7160
return &config.ConfigOption{
7261
Name: "rpc-url",

go.mod

-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ require (
4444
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
4545
github.com/leodido/go-urn v1.4.0 // indirect
4646
github.com/magiconair/properties v1.8.7 // indirect
47-
github.com/manucorporat/sse v0.0.0-20160126180136-ee05b128a739 // indirect
4847
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
4948
github.com/mitchellh/mapstructure v1.5.0 // indirect
5049
github.com/pelletier/go-toml/v2 v2.2.2 // indirect

internal/entities/rpc.go

+14
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,19 @@ type RPCSendTransactionResult struct {
7777
ErrorResultXDR string `json:"errorResultXdr"`
7878
}
7979

80+
type LedgerEntryResult struct {
81+
KeyXDR string `json:"key,omitempty"`
82+
DataXDR string `json:"xdr,omitempty"`
83+
LastModifiedLedger uint32 `json:"lastModifiedLedgerSeq"`
84+
// The ledger sequence until the entry is live, available for entries that have associated ttl ledger entries.
85+
LiveUntilLedgerSeq *uint32 `json:"liveUntilLedgerSeq,omitempty"`
86+
}
87+
88+
type RPCGetLedgerEntriesResult struct {
89+
LatestLedger uint32 `json:"latestLedger"`
90+
Entries []LedgerEntryResult `json:"entries"`
91+
}
92+
8093
type RPCPagination struct {
8194
Cursor string `json:"cursor,omitempty"`
8295
Limit int `json:"limit"`
@@ -87,4 +100,5 @@ type RPCParams struct {
87100
Hash string `json:"hash,omitempty"`
88101
StartLedger int64 `json:"startLedger,omitempty"`
89102
Pagination RPCPagination `json:"pagination,omitempty"`
103+
LedgerKeys []string `json:"keys,omitempty"`
90104
}

internal/serve/serve.go

+27-32
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ import (
88

99
"github.com/go-chi/chi"
1010
"github.com/sirupsen/logrus"
11-
"github.com/stellar/go/clients/horizonclient"
1211
supporthttp "github.com/stellar/go/support/http"
1312
"github.com/stellar/go/support/log"
1413
"github.com/stellar/go/support/render/health"
1514
"github.com/stellar/go/xdr"
15+
1616
"github.com/stellar/wallet-backend/internal/apptracker"
1717
"github.com/stellar/wallet-backend/internal/data"
1818
"github.com/stellar/wallet-backend/internal/db"
@@ -60,7 +60,6 @@ type Configs struct {
6060
NetworkPassphrase string
6161
MaxSponsoredBaseReserves int
6262
BaseFee int
63-
HorizonClientURL string
6463
DistributionAccountSignatureClient signing.SignatureClient
6564
ChannelAccountSignatureClient signing.SignatureClient
6665
// TSS
@@ -150,9 +149,10 @@ func initHandlerDeps(cfg Configs) (handlerDeps, error) {
150149
return handlerDeps{}, fmt.Errorf("instantiating stellar signature verifier: %w", err)
151150
}
152151

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

158158
accountService, err := services.NewAccountService(models)
@@ -163,7 +163,7 @@ func initHandlerDeps(cfg Configs) (handlerDeps, error) {
163163
accountSponsorshipService, err := services.NewAccountSponsorshipService(services.AccountSponsorshipServiceOptions{
164164
DistributionAccountSignatureClient: cfg.DistributionAccountSignatureClient,
165165
ChannelAccountSignatureClient: cfg.ChannelAccountSignatureClient,
166-
HorizonClient: &horizonClient,
166+
RPCService: rpcService,
167167
MaxSponsoredBaseReserves: cfg.MaxSponsoredBaseReserves,
168168
BaseFee: int64(cfg.BaseFee),
169169
Models: models,
@@ -178,50 +178,31 @@ func initHandlerDeps(cfg Configs) (handlerDeps, error) {
178178
return handlerDeps{}, fmt.Errorf("instantiating payment service: %w", err)
179179
}
180180

181-
channelAccountService, err := services.NewChannelAccountService(services.ChannelAccountServiceOptions{
182-
DB: dbConnectionPool,
183-
HorizonClient: &horizonClient,
184-
BaseFee: int64(cfg.BaseFee),
185-
DistributionAccountSignatureClient: cfg.DistributionAccountSignatureClient,
186-
ChannelAccountStore: store.NewChannelAccountModel(dbConnectionPool),
187-
PrivateKeyEncrypter: &signingutils.DefaultPrivateKeyEncrypter{},
188-
EncryptionPassphrase: cfg.EncryptionPassphrase,
189-
})
190-
if err != nil {
191-
return handlerDeps{}, fmt.Errorf("instantiating channel account service: %w", err)
192-
}
193-
go ensureChannelAccounts(channelAccountService, int64(cfg.NumberOfChannelAccounts))
194-
195181
// TSS setup
196182
tssTxService, err := tssservices.NewTransactionService(tssservices.TransactionServiceOptions{
197183
DistributionAccountSignatureClient: cfg.DistributionAccountSignatureClient,
198184
ChannelAccountSignatureClient: cfg.ChannelAccountSignatureClient,
199-
HorizonClient: &horizonClient,
185+
RPCService: rpcService,
200186
BaseFee: int64(cfg.BaseFee),
201187
})
202188

203189
if err != nil {
204190
return handlerDeps{}, fmt.Errorf("instantiating tss transaction service: %w", err)
205191
}
206-
httpClient := http.Client{Timeout: time.Duration(30 * time.Second)}
207-
rpcService, err := services.NewRPCService(cfg.RPCURL, &httpClient)
208-
if err != nil {
209-
return handlerDeps{}, fmt.Errorf("instantiating rpc service: %w", err)
210-
}
211192

212-
store, err := tssstore.NewStore(dbConnectionPool)
193+
tssStore, err := tssstore.NewStore(dbConnectionPool)
213194
if err != nil {
214195
return handlerDeps{}, fmt.Errorf("instantiating tss store: %w", err)
215196
}
216197
txManager := tssservices.NewTransactionManager(tssservices.TransactionManagerConfigs{
217198
TxService: tssTxService,
218199
RPCService: rpcService,
219-
Store: store,
200+
Store: tssStore,
220201
})
221202

222203
rpcCallerChannel := tsschannel.NewRPCCallerChannel(tsschannel.RPCCallerChannelConfigs{
223204
TxManager: txManager,
224-
Store: store,
205+
Store: tssStore,
225206
MaxBufferSize: cfg.RPCCallerServiceChannelBufferSize,
226207
MaxWorkers: cfg.RPCCallerServiceChannelMaxWorkers,
227208
})
@@ -245,7 +226,7 @@ func initHandlerDeps(cfg Configs) (handlerDeps, error) {
245226
httpClient = http.Client{Timeout: time.Duration(30 * time.Second)}
246227
webhookChannel := tsschannel.NewWebhookChannel(tsschannel.WebhookChannelConfigs{
247228
HTTPClient: &httpClient,
248-
Store: store,
229+
Store: tssStore,
249230
MaxBufferSize: cfg.WebhookHandlerServiceChannelMaxBufferSize,
250231
MaxWorkers: cfg.WebhookHandlerServiceChannelMaxWorkers,
251232
MaxRetries: cfg.WebhookHandlerServiceChannelMaxRetries,
@@ -263,11 +244,25 @@ func initHandlerDeps(cfg Configs) (handlerDeps, error) {
263244
errorJitterChannel.SetRouter(router)
264245
errorNonJitterChannel.SetRouter(router)
265246

266-
poolPopulator, err := tssservices.NewPoolPopulator(router, store, rpcService)
247+
poolPopulator, err := tssservices.NewPoolPopulator(router, tssStore, rpcService)
267248
if err != nil {
268249
return handlerDeps{}, fmt.Errorf("instantiating tss pool populator")
269250
}
270251

252+
channelAccountService, err := services.NewChannelAccountService(services.ChannelAccountServiceOptions{
253+
DB: dbConnectionPool,
254+
RPCService: rpcService,
255+
BaseFee: int64(cfg.BaseFee),
256+
DistributionAccountSignatureClient: cfg.DistributionAccountSignatureClient,
257+
ChannelAccountStore: store.NewChannelAccountModel(dbConnectionPool),
258+
PrivateKeyEncrypter: &signingutils.DefaultPrivateKeyEncrypter{},
259+
EncryptionPassphrase: cfg.EncryptionPassphrase,
260+
})
261+
if err != nil {
262+
return handlerDeps{}, fmt.Errorf("instantiating channel account service: %w", err)
263+
}
264+
go ensureChannelAccounts(channelAccountService, int64(cfg.NumberOfChannelAccounts))
265+
271266
return handlerDeps{
272267
Models: models,
273268
SignatureVerifier: signatureVerifier,
@@ -284,7 +279,7 @@ func initHandlerDeps(cfg Configs) (handlerDeps, error) {
284279
WebhookChannel: webhookChannel,
285280
TSSRouter: router,
286281
PoolPopulator: poolPopulator,
287-
TSSStore: store,
282+
TSSStore: tssStore,
288283
TSSTransactionService: tssTxService,
289284
}, nil
290285
}

internal/services/account_sponsorship_service.go

+17-13
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ import (
66
"fmt"
77
"slices"
88

9-
"github.com/stellar/go/clients/horizonclient"
109
"github.com/stellar/go/support/log"
1110
"github.com/stellar/go/txnbuild"
1211
"github.com/stellar/go/xdr"
12+
1313
"github.com/stellar/wallet-backend/internal/data"
1414
"github.com/stellar/wallet-backend/internal/entities"
1515
"github.com/stellar/wallet-backend/internal/signing"
@@ -21,6 +21,7 @@ var (
2121
ErrAccountNotEligibleForBeingSponsored = errors.New("account not eligible for being sponsored")
2222
ErrFeeExceedsMaximumBaseFee = errors.New("fee exceeds maximum base fee to sponsor")
2323
ErrNoSignaturesProvided = errors.New("should have at least one signature")
24+
ErrAccountNotFound = errors.New("account not found")
2425
)
2526

2627
type ErrOperationNotAllowed struct {
@@ -45,7 +46,7 @@ type AccountSponsorshipService interface {
4546
type accountSponsorshipService struct {
4647
DistributionAccountSignatureClient signing.SignatureClient
4748
ChannelAccountSignatureClient signing.SignatureClient
48-
HorizonClient horizonclient.ClientInterface
49+
RPCService RPCService
4950
MaxSponsoredBaseReserves int
5051
BaseFee int64
5152
Models *data.Models
@@ -56,11 +57,11 @@ var _ AccountSponsorshipService = (*accountSponsorshipService)(nil)
5657

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

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

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

133134
tx, err := txnbuild.NewTransaction(
134135
txnbuild.TransactionParams{
135-
SourceAccount: &channelAccount,
136+
SourceAccount: &txnbuild.SimpleAccount{
137+
AccountID: channelAccountPublicKey,
138+
Sequence: channelAccountSeq,
139+
},
136140
IncrementSequenceNum: true,
137141
Operations: ops,
138142
BaseFee: s.BaseFee,
@@ -228,7 +232,7 @@ func (s *accountSponsorshipService) WrapTransaction(ctx context.Context, tx *txn
228232
type AccountSponsorshipServiceOptions struct {
229233
DistributionAccountSignatureClient signing.SignatureClient
230234
ChannelAccountSignatureClient signing.SignatureClient
231-
HorizonClient horizonclient.ClientInterface
235+
RPCService RPCService
232236
MaxSponsoredBaseReserves int
233237
BaseFee int64
234238
Models *data.Models
@@ -240,12 +244,12 @@ func (o *AccountSponsorshipServiceOptions) Validate() error {
240244
return fmt.Errorf("distribution account signature client cannot be nil")
241245
}
242246

243-
if o.ChannelAccountSignatureClient == nil {
244-
return fmt.Errorf("channel account signature client cannot be nil")
247+
if o.RPCService == nil {
248+
return fmt.Errorf("rpc client cannot be nil")
245249
}
246250

247-
if o.HorizonClient == nil {
248-
return fmt.Errorf("horizon client cannot be nil")
251+
if o.ChannelAccountSignatureClient == nil {
252+
return fmt.Errorf("channel account signature client cannot be nil")
249253
}
250254

251255
if o.BaseFee < int64(txnbuild.MinBaseFee) {
@@ -267,7 +271,7 @@ func NewAccountSponsorshipService(opts AccountSponsorshipServiceOptions) (*accou
267271
return &accountSponsorshipService{
268272
DistributionAccountSignatureClient: opts.DistributionAccountSignatureClient,
269273
ChannelAccountSignatureClient: opts.ChannelAccountSignatureClient,
270-
HorizonClient: opts.HorizonClient,
274+
RPCService: opts.RPCService,
271275
MaxSponsoredBaseReserves: opts.MaxSponsoredBaseReserves,
272276
BaseFee: opts.BaseFee,
273277
Models: opts.Models,

0 commit comments

Comments
 (0)