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

all: TSS RPC Caller Service #40

Merged
merged 75 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from 72 commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
a58d519
tables and interfaces for TSS
gouthamp-stellar Aug 30, 2024
9920f48
TSS tables and the channel interface
gouthamp-stellar Aug 30, 2024
3f9f9f0
remove empty lines
gouthamp-stellar Aug 30, 2024
373c71a
update
gouthamp-stellar Aug 30, 2024
2de9898
adding semicolons
gouthamp-stellar Aug 30, 2024
c0f9d32
moving all migrations to one file
gouthamp-stellar Aug 30, 2024
a9cf4e3
make hash primary key instead of xdr
gouthamp-stellar Sep 3, 2024
6fc0dc2
missing ,
gouthamp-stellar Sep 3, 2024
fb807aa
remove the index on try_transaction_xdr and add column/index on try_t…
gouthamp-stellar Sep 3, 2024
f8c261b
Squashed commit of the following:
gouthamp-stellar Sep 4, 2024
d774f2a
commit #2
gouthamp-stellar Sep 5, 2024
6b04d62
changing from RpcIngestTxResponse -> RpcGetIngestTxResponse
gouthamp-stellar Sep 5, 2024
f2fefef
Merge branch 'tss_tables_interfaces' into transaction_module
gouthamp-stellar Sep 5, 2024
b441a31
latest changes
gouthamp-stellar Sep 7, 2024
02c7de3
add tests for ValidateOptions
gouthamp-stellar Sep 8, 2024
f9a5611
changes based on comments
gouthamp-stellar Sep 10, 2024
32bd6ce
Merge branch 'main' into tss_tables_interfaces
gouthamp-stellar Sep 10, 2024
5c7db27
Merge branch 'tss_tables_interfaces' into transaction_module
gouthamp-stellar Sep 10, 2024
c3e8de9
latest changes based on changes to interface
gouthamp-stellar Sep 10, 2024
82b12fb
string -> RPCTXStatus
gouthamp-stellar Sep 10, 2024
9a9c9be
Merge branch 'tss_tables_interfaces' into transaction_module
gouthamp-stellar Sep 10, 2024
0662da9
adding a transaction_builder.go which takes a list of operation xdrs …
gouthamp-stellar Sep 11, 2024
8f76d61
moving transaction_service to the utils dir
gouthamp-stellar Sep 11, 2024
456b71f
upper case Channel methods
gouthamp-stellar Sep 11, 2024
7974aa9
Merge branch 'tss_tables_interfaces' into transaction_module
gouthamp-stellar Sep 11, 2024
5bdf8f2
latest changes
gouthamp-stellar Sep 12, 2024
3890bfe
p.txService.NetworkPassPhrase()
gouthamp-stellar Sep 12, 2024
e87c6d6
last commit before writing unit tests
gouthamp-stellar Sep 13, 2024
c1d3786
Making the transaction service more injectible and adding fields to t…
gouthamp-stellar Sep 13, 2024
01ed3eb
typo
gouthamp-stellar Sep 13, 2024
3ddd2bd
typo
gouthamp-stellar Sep 13, 2024
5776cb1
Update 2024-08-28.0-tss_transactions.sql
gouthamp-stellar Sep 13, 2024
2c6db84
Merge branch 'main' into transaction_module
gouthamp-stellar Sep 13, 2024
77a6e4b
lint errors
gouthamp-stellar Sep 13, 2024
01109ab
go mod tidy
gouthamp-stellar Sep 13, 2024
c005a06
Merge branch 'main' into transaction_module
gouthamp-stellar Sep 13, 2024
f560a05
Merge branch 'transaction_module' into rpc_caller_service
gouthamp-stellar Sep 13, 2024
38ba21b
test cases + other changes
gouthamp-stellar Sep 15, 2024
8ddb961
remoce unused mocks
gouthamp-stellar Sep 15, 2024
d32adb1
error handler service returns errorHandlerService
gouthamp-stellar Sep 15, 2024
e0727b5
changes based on comments
gouthamp-stellar Sep 18, 2024
968a6b7
lint deadcode error - suppress for now
gouthamp-stellar Sep 18, 2024
096c7bd
removed deadcode
gouthamp-stellar Sep 18, 2024
6cfc3fd
changes after comments on transaction service pr
gouthamp-stellar Sep 18, 2024
b71e342
Update transaction_service.go
gouthamp-stellar Sep 19, 2024
ccf27f1
responding to comments
gouthamp-stellar Sep 20, 2024
8045d8d
remove commented code
gouthamp-stellar Sep 20, 2024
d062a11
tx service changes
gouthamp-stellar Sep 20, 2024
1a3c17c
remove comment
gouthamp-stellar Sep 20, 2024
174ed45
remove comment
gouthamp-stellar Sep 20, 2024
5d31b01
adding a router + utils file
gouthamp-stellar Sep 20, 2024
a6dc954
removing println
gouthamp-stellar Sep 20, 2024
43fcf10
Code() helper function on RPCTXCode
gouthamp-stellar Sep 21, 2024
b4ab5de
adding a helpers file
gouthamp-stellar Sep 21, 2024
f10d239
removing BuildTestFeeBumpTransaction
gouthamp-stellar Sep 21, 2024
db8714d
casing
gouthamp-stellar Sep 22, 2024
2c0d060
better test for Send
gouthamp-stellar Sep 23, 2024
b82a25a
Merge branch 'transaction_module' into rpc_caller_service
gouthamp-stellar Sep 23, 2024
101bd43
Merge branch 'main' into rpc_caller_service
gouthamp-stellar Sep 25, 2024
637aeaf
incorporating Daniel's changes + comments
gouthamp-stellar Sep 26, 2024
0fb94e3
delete files
gouthamp-stellar Sep 26, 2024
df7ae05
remove unused code
gouthamp-stellar Sep 26, 2024
cf2dc18
name change
gouthamp-stellar Sep 26, 2024
16581fd
remove commented code
gouthamp-stellar Sep 26, 2024
ab7c0d7
moving the mocks file inside servicesmocks dir
gouthamp-stellar Sep 26, 2024
5fe5d0b
name changes
gouthamp-stellar Sep 26, 2024
78042c9
Merge branch 'main' into rpc_caller_service
gouthamp-stellar Sep 26, 2024
9118a06
merging main
gouthamp-stellar Sep 26, 2024
12425f9
fixing parsesendresp tests
gouthamp-stellar Sep 26, 2024
6b2a6f7
changes based on comments
gouthamp-stellar Sep 30, 2024
b4f6052
removing test case that is not relevant anymore
gouthamp-stellar Sep 30, 2024
01ad88d
making sure the pool implements the channel interface
gouthamp-stellar Oct 1, 2024
26e8733
Merge branch 'main' into rpc_caller_service
gouthamp-stellar Oct 9, 2024
33c2b78
adding tracker_dsn and other env vars
gouthamp-stellar Oct 9, 2024
3cdacaa
go mod tidy
gouthamp-stellar Oct 9, 2024
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
3 changes: 3 additions & 0 deletions cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ func (c *serveCmd) Command() *cobra.Command {
utils.NetworkPassphraseOption(&cfg.NetworkPassphrase),
utils.BaseFeeOption(&cfg.BaseFee),
utils.HorizonClientURLOption(&cfg.HorizonClientURL),
utils.RPCURLOption(&cfg.RPCURL),
utils.RPCCallerServiceChannelBufferSizeOption(&cfg.RPCCallerServiceChannelBufferSize),
utils.RPCCallerServiceMaxWorkersOption(&cfg.RPCCallerServiceChannelMaxWorkers),
utils.ChannelAccountEncryptionPassphraseOption(&cfg.EncryptionPassphrase),
utils.SentryDSNOption(&sentryDSN),
utils.StellarEnvironmentOption(&stellarEnvironment),
Expand Down
32 changes: 32 additions & 0 deletions cmd/utils/global_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,38 @@ func HorizonClientURLOption(configKey *string) *config.ConfigOption {
}
}

func RPCURLOption(configKey *string) *config.ConfigOption {
return &config.ConfigOption{
Name: "rpc-url",
Usage: "The URL of the RPC Server.",
OptType: types.String,
ConfigKey: configKey,
FlagDefault: "localhost:8080",
Required: true,
}
}

func RPCCallerServiceChannelBufferSizeOption(configKey *int) *config.ConfigOption {
return &config.ConfigOption{
Name: "tss-rpc-caller-service-channel-buffer-size",
Usage: "Set the buffer size for TSS RPC Caller Service channel.",
OptType: types.Int,
ConfigKey: configKey,
FlagDefault: 1000,
}
}

func RPCCallerServiceMaxWorkersOption(configKey *int) *config.ConfigOption {
return &config.ConfigOption{
Name: "tss-rpc-caller-service-channel-max-workers",
Usage: "Set the maximum number of workers for TSS RPC Caller Service channel.",
OptType: types.Int,
ConfigKey: configKey,
FlagDefault: 100,
}

}

func ChannelAccountEncryptionPassphraseOption(configKey *string) *config.ConfigOption {
return &config.ConfigOption{
Name: "channel-account-encryption-passphrase",
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/stellar/wallet-backend
go 1.22.0

require (
github.com/alitto/pond v1.9.2
github.com/aws/aws-sdk-go v1.45.26
github.com/getsentry/sentry-go v0.28.1
github.com/go-chi/chi v4.1.2+incompatible
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/alitto/pond v1.9.2 h1:9Qb75z/scEZVCoSU+osVmQ0I0JOeLfdTDafrbcJ8CLs=
github.com/alitto/pond v1.9.2/go.mod h1:xQn3P/sHTYcU/1BR3i86IGIrilcrGC2LiS+E2+CJWsI=
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
Expand Down
63 changes: 61 additions & 2 deletions internal/serve/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ import (
"github.com/stellar/wallet-backend/internal/signing"
"github.com/stellar/wallet-backend/internal/signing/store"
signingutils "github.com/stellar/wallet-backend/internal/signing/utils"
"github.com/stellar/wallet-backend/internal/tss"
tsschannel "github.com/stellar/wallet-backend/internal/tss/channels"
tssrouter "github.com/stellar/wallet-backend/internal/tss/router"
tssservices "github.com/stellar/wallet-backend/internal/tss/services"
tssstore "github.com/stellar/wallet-backend/internal/tss/store"
)

// NOTE: perhaps move this to a environment variable.
Expand Down Expand Up @@ -58,7 +63,10 @@ type Configs struct {
HorizonClientURL string
DistributionAccountSignatureClient signing.SignatureClient
ChannelAccountSignatureClient signing.SignatureClient

// TSS
RPCURL string
RPCCallerServiceChannelBufferSize int
RPCCallerServiceChannelMaxWorkers int
// Error Tracker
AppTracker apptracker.AppTracker
}
Expand All @@ -74,7 +82,11 @@ type handlerDeps struct {
AccountService services.AccountService
AccountSponsorshipService services.AccountSponsorshipService
PaymentService services.PaymentService
AppTracker apptracker.AppTracker
// TSS
RPCCallerServiceChannel tss.Channel
TSSRouter tssrouter.Router
// Error Tracker
AppTracker apptracker.AppTracker
}

func Serve(cfg Configs) error {
Expand All @@ -92,6 +104,7 @@ func Serve(cfg Configs) error {
},
OnStopping: func() {
log.Info("Stopping Wallet Backend server")
deps.RPCCallerServiceChannel.Stop()
},
})

Expand Down Expand Up @@ -155,6 +168,49 @@ func initHandlerDeps(cfg Configs) (handlerDeps, error) {
}
go ensureChannelAccounts(channelAccountService, int64(cfg.NumberOfChannelAccounts))

// TSS
txServiceOpts := tssservices.TransactionServiceOptions{
DistributionAccountSignatureClient: cfg.DistributionAccountSignatureClient,
ChannelAccountSignatureClient: cfg.ChannelAccountSignatureClient,
HorizonClient: &horizonClient,
BaseFee: int64(cfg.BaseFee),
}
tssTxService, err := tssservices.NewTransactionService(txServiceOpts)
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)
if err != nil {
return handlerDeps{}, fmt.Errorf("instantiating tss store: %w", err)
}
txManager := tssservices.NewTransactionManager(tssservices.TransactionManagerConfigs{
TxService: tssTxService,
RPCService: rpcService,
Store: store,
})

rpcCallerServiceChannel := tsschannel.NewRPCCallerChannel(tsschannel.RPCCallerChannelConfigs{
TxManager: txManager,
Store: store,
MaxBufferSize: cfg.RPCCallerServiceChannelBufferSize,
MaxWorkers: cfg.RPCCallerServiceChannelMaxWorkers,
})

router := tssrouter.NewRouter(tssrouter.RouterConfigs{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a good idea to check in the NewRouter and NewStore functions that the parameters are passed in correctly and are not nil. If a parameter is invalid, they can return an error.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did add a nil check for NewStore, but kept NewRouter the way it is right now, for reasons I explained in another comment, I would like the option of some of these channels being nil

RPCCallerChannel: rpcCallerServiceChannel,
ErrorJitterChannel: nil,
ErrorNonJitterChannel: nil,
WebhookChannel: nil,
})

rpcCallerServiceChannel.SetRouter(router)

return handlerDeps{
Models: models,
SignatureVerifier: signatureVerifier,
Expand All @@ -163,6 +219,9 @@ func initHandlerDeps(cfg Configs) (handlerDeps, error) {
AccountSponsorshipService: accountSponsorshipService,
PaymentService: paymentService,
AppTracker: cfg.AppTracker,
// TSS
RPCCallerServiceChannel: rpcCallerServiceChannel,
TSSRouter: router,
Comment on lines +223 to +224
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which of the two will be the entrypoint when handling HTTP requests? Probably that one can be our only dependency to be injected in handlerDeps, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We actually need both, because the channel is being closed (via Stop()) in the Serve function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But the entrypoint will be the router

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm got it, maybe we can create an OnStop function on the router for this?

}, nil
}

Expand Down
23 changes: 23 additions & 0 deletions internal/services/servicesmocks/rpc_service_mocks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package servicesmocks

import (
"github.com/stellar/wallet-backend/internal/entities"
"github.com/stellar/wallet-backend/internal/services"
"github.com/stretchr/testify/mock"
)

type RPCServiceMock struct {
mock.Mock
}

var _ services.RPCService = (*RPCServiceMock)(nil)

func (r *RPCServiceMock) SendTransaction(transactionXdr string) (entities.RPCSendTransactionResult, error) {
args := r.Called(transactionXdr)
return args.Get(0).(entities.RPCSendTransactionResult), args.Error(1)
}

func (r *RPCServiceMock) GetTransaction(transactionHash string) (entities.RPCGetTransactionResult, error) {
args := r.Called(transactionHash)
return args.Get(0).(entities.RPCGetTransactionResult), args.Error(1)
}
80 changes: 80 additions & 0 deletions internal/tss/channels/rpc_caller_channel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package channels

import (
"context"

"github.com/alitto/pond"

"github.com/stellar/go/support/log"
"github.com/stellar/wallet-backend/internal/tss"
"github.com/stellar/wallet-backend/internal/tss/router"
"github.com/stellar/wallet-backend/internal/tss/services"
"github.com/stellar/wallet-backend/internal/tss/store"
)

type RPCCallerChannelConfigs struct {
TxManager services.TransactionManager
Router router.Router
Store store.Store
MaxBufferSize int
MaxWorkers int
}

type rpcCallerPool struct {
Pool *pond.WorkerPool
TxManager services.TransactionManager
Router router.Router
Store store.Store
}

var RPCCallerChannelName = "RPCCallerChannel"

var _ tss.Channel = (*rpcCallerPool)(nil)

func NewRPCCallerChannel(cfg RPCCallerChannelConfigs) *rpcCallerPool {
pool := pond.New(cfg.MaxBufferSize, cfg.MaxWorkers, pond.Strategy(pond.Balanced()))
return &rpcCallerPool{
Pool: pool,
TxManager: cfg.TxManager,
Store: cfg.Store,
Router: cfg.Router,
}

}

func (p *rpcCallerPool) Send(payload tss.Payload) {
p.Pool.Submit(func() {
p.Receive(payload)
})
}

func (p *rpcCallerPool) Receive(payload tss.Payload) {

ctx := context.Background()
// Create a new transaction record in the transactions table.
err := p.Store.UpsertTransaction(ctx, payload.WebhookURL, payload.TransactionHash, payload.TransactionXDR, tss.RPCTXStatus{OtherStatus: tss.NewStatus})

if err != nil {
log.Errorf("%s: unable to upsert transaction into transactions table: %e", RPCCallerChannelName, err)
return
}
rpcSendResp, err := p.TxManager.BuildAndSubmitTransaction(ctx, RPCCallerChannelName, payload)

if err != nil {
log.Errorf("%s: unable to sign and submit transaction: %e", RPCCallerChannelName, err)
return
}
payload.RpcSubmitTxResponse = rpcSendResp
err = p.Router.Route(payload)
if err != nil {
log.Errorf("%s: unable to route payload: %e", RPCCallerChannelName, err)
}
}

func (p *rpcCallerPool) SetRouter(router router.Router) {
p.Router = router
}

func (p *rpcCallerPool) Stop() {
p.Pool.StopAndWait()
}
115 changes: 115 additions & 0 deletions internal/tss/channels/rpc_caller_channel_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package channels

import (
"context"
"errors"
"testing"

"github.com/stellar/wallet-backend/internal/db"
"github.com/stellar/wallet-backend/internal/db/dbtest"
"github.com/stellar/wallet-backend/internal/entities"
"github.com/stellar/wallet-backend/internal/tss"
"github.com/stellar/wallet-backend/internal/tss/router"
"github.com/stellar/wallet-backend/internal/tss/services"
"github.com/stellar/wallet-backend/internal/tss/store"
"github.com/stretchr/testify/require"
)

func TestSend(t *testing.T) {
dbt := dbtest.Open(t)
defer dbt.Close()
dbConnectionPool, err := db.OpenDBConnectionPool(dbt.DSN)
require.NoError(t, err)
defer dbConnectionPool.Close()
store, _ := store.NewStore(dbConnectionPool)
txManagerMock := services.TransactionManagerMock{}
routerMock := router.MockRouter{}
cfgs := RPCCallerChannelConfigs{
Store: store,
TxManager: &txManagerMock,
Router: &routerMock,
MaxBufferSize: 10,
MaxWorkers: 10,
}
channel := NewRPCCallerChannel(cfgs)
payload := tss.Payload{}
payload.WebhookURL = "www.stellar.com"
payload.TransactionHash = "hash"
payload.TransactionXDR = "xdr"

rpcResp := tss.RPCSendTxResponse{
Status: tss.RPCTXStatus{RPCStatus: entities.TryAgainLaterStatus},
}
payload.RpcSubmitTxResponse = rpcResp

txManagerMock.
On("BuildAndSubmitTransaction", context.Background(), RPCCallerChannelName, payload).
Return(rpcResp, nil).
Once()

routerMock.
On("Route", payload).
Return(nil).
Once()

channel.Send(payload)
channel.Stop()

routerMock.AssertCalled(t, "Route", payload)
}

func TestReceivee(t *testing.T) {
dbt := dbtest.Open(t)
defer dbt.Close()
dbConnectionPool, err := db.OpenDBConnectionPool(dbt.DSN)
require.NoError(t, err)
defer dbConnectionPool.Close()
store, _ := store.NewStore(dbConnectionPool)
txManagerMock := services.TransactionManagerMock{}
routerMock := router.MockRouter{}
cfgs := RPCCallerChannelConfigs{
Store: store,
TxManager: &txManagerMock,
Router: &routerMock,
MaxBufferSize: 10,
MaxWorkers: 10,
}
channel := NewRPCCallerChannel(cfgs)
payload := tss.Payload{}
payload.WebhookURL = "www.stellar.com"
payload.TransactionHash = "hash"
payload.TransactionXDR = "xdr"

t.Run("build_and_submit_tx_fail", func(t *testing.T) {
txManagerMock.
On("BuildAndSubmitTransaction", context.Background(), RPCCallerChannelName, payload).
Return(tss.RPCSendTxResponse{}, errors.New("build tx failed")).
Once()

channel.Receive(payload)

routerMock.AssertNotCalled(t, "Route", payload)
})

t.Run("payload_routed", func(t *testing.T) {
rpcResp := tss.RPCSendTxResponse{
Status: tss.RPCTXStatus{RPCStatus: entities.ErrorStatus},
}
payload.RpcSubmitTxResponse = rpcResp

txManagerMock.
On("BuildAndSubmitTransaction", context.Background(), RPCCallerChannelName, payload).
Return(rpcResp, nil).
Once()

routerMock.
On("Route", payload).
Return(nil).
Once()

channel.Receive(payload)

routerMock.AssertCalled(t, "Route", payload)
})

}
Loading
Loading