Skip to content

Commit 1ae6bf4

Browse files
authoredNov 13, 2024
final TSS changes (stellar#74)
* final TSS changes * final changes * uncomment
1 parent ee0fb0e commit 1ae6bf4

File tree

9 files changed

+161
-48
lines changed

9 files changed

+161
-48
lines changed
 

‎Dockerfile

+10
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,21 @@ FROM stellar/soroban-rpc
1414
# Install bash or sh
1515
RUN apt-get update && apt-get install -y bash
1616

17+
1718
# Step 2: Install Stellar Core and copy over app binary
1819
FROM ubuntu:jammy AS core-build
1920

21+
RUN apt-get update && \
22+
apt-get install -y --no-install-recommends ca-certificates curl wget gnupg apt-utils gpg && \
23+
curl -sSL https://apt.stellar.org/SDF.asc | gpg --dearmor >/etc/apt/trusted.gpg.d/SDF.gpg && \
24+
echo "deb https://apt.stellar.org jammy stable" >/etc/apt/sources.list.d/SDF.list && \
25+
echo "deb https://apt.stellar.org jammy testing" >/etc/apt/sources.list.d/SDF-testing.list && \
26+
echo "deb https://apt.stellar.org jammy unstable" >/etc/apt/sources.list.d/SDF-unstable.list
27+
2028
COPY --from=api-build /bin/wallet-backend /app/
2129

2230
EXPOSE 8001
2331
WORKDIR /app
2432
ENTRYPOINT ["./wallet-backend"]
33+
34+

‎cmd/serve.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ func (c *serveCmd) Command() *cobra.Command {
9393
Usage: "The minimum number of Channel Accounts that must exist in the database.",
9494
OptType: types.Int,
9595
ConfigKey: &cfg.NumberOfChannelAccounts,
96-
FlagDefault: 5,
96+
FlagDefault: 15,
9797
Required: true,
9898
},
9999
}

‎cmd/utils/tss_options.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func ErrorHandlerJitterChannelBufferSizeOption(configKey *int) *config.ConfigOpt
3333
Usage: "Set the buffer size of the Error Handler Jitter channel.",
3434
OptType: types.Int,
3535
ConfigKey: configKey,
36-
FlagDefault: 100,
36+
FlagDefault: 1000,
3737
Required: true,
3838
}
3939
}
@@ -44,7 +44,7 @@ func ErrorHandlerJitterChannelMaxWorkersOption(configKey *int) *config.ConfigOpt
4444
Usage: "Set the maximum number of workers for the Error Handler Jitter channel.",
4545
OptType: types.Int,
4646
ConfigKey: configKey,
47-
FlagDefault: 10,
47+
FlagDefault: 100,
4848
Required: true,
4949
}
5050
}
@@ -55,7 +55,7 @@ func ErrorHandlerNonJitterChannelBufferSizeOption(configKey *int) *config.Config
5555
Usage: "Set the buffer size of the Error Handler Non Jitter channel.",
5656
OptType: types.Int,
5757
ConfigKey: configKey,
58-
FlagDefault: 100,
58+
FlagDefault: 1000,
5959
Required: true,
6060
}
6161

@@ -67,7 +67,7 @@ func ErrorHandlerNonJitterChannelMaxWorkersOption(configKey *int) *config.Config
6767
Usage: "Set the maximum number of workers for the Error Handler Non Jitter channel.",
6868
OptType: types.Int,
6969
ConfigKey: configKey,
70-
FlagDefault: 10,
70+
FlagDefault: 100,
7171
Required: true,
7272
}
7373
}
@@ -100,7 +100,7 @@ func ErrorHandlerJitterChannelMaxRetriesOptions(configKey *int) *config.ConfigOp
100100
Usage: "Set the number of retries for each task in the Error Handler Jitter channel.",
101101
OptType: types.Int,
102102
ConfigKey: configKey,
103-
FlagDefault: 10,
103+
FlagDefault: 3,
104104
Required: true,
105105
}
106106

@@ -112,7 +112,7 @@ func ErrorHandlerNonJitterChannelMaxRetriesOption(configKey *int) *config.Config
112112
Usage: "Set the number of retries for each task in the Error Handler Service Jitter channel.",
113113
OptType: types.Int,
114114
ConfigKey: configKey,
115-
FlagDefault: 10,
115+
FlagDefault: 3,
116116
Required: true,
117117
}
118118
}
@@ -123,7 +123,7 @@ func WebhookHandlerChannelMaxBufferSizeOption(configKey *int) *config.ConfigOpti
123123
Usage: "Set the buffer size of the webhook channel.",
124124
OptType: types.Int,
125125
ConfigKey: configKey,
126-
FlagDefault: 100,
126+
FlagDefault: 1000,
127127
Required: true,
128128
}
129129
}
@@ -134,7 +134,7 @@ func WebhookHandlerChannelMaxWorkersOptions(configKey *int) *config.ConfigOption
134134
Usage: "Set the max number of workers for the webhook channel.",
135135
OptType: types.Int,
136136
ConfigKey: configKey,
137-
FlagDefault: 10,
137+
FlagDefault: 100,
138138
Required: true,
139139
}
140140
}

‎internal/tss/channels/webhook_channel.go

+12-12
Original file line numberDiff line numberDiff line change
@@ -68,20 +68,20 @@ func (p *webhookPool) Receive(payload tss.Payload) {
6868
httpResp, err := p.HTTPClient.Post(payload.WebhookURL, "application/json", bytes.NewBuffer(jsonData))
6969
if err != nil {
7070
log.Errorf("%s: error making POST request to webhook: %e", WebhookChannelName, err)
71-
}
72-
defer httpResp.Body.Close()
73-
74-
if httpResp.StatusCode == http.StatusOK {
75-
sent = true
76-
err := p.Store.UpsertTransaction(
77-
ctx, payload.WebhookURL, payload.TransactionHash, payload.TransactionXDR, tss.RPCTXStatus{OtherStatus: tss.SentStatus})
78-
if err != nil {
79-
log.Errorf("%s: error updating transaction status: %e", WebhookChannelName, err)
71+
} else {
72+
defer httpResp.Body.Close()
73+
if httpResp.StatusCode == http.StatusOK {
74+
sent = true
75+
err := p.Store.UpsertTransaction(
76+
ctx, payload.WebhookURL, payload.TransactionHash, payload.TransactionXDR, tss.RPCTXStatus{OtherStatus: tss.SentStatus})
77+
if err != nil {
78+
log.Errorf("%s: error updating transaction status: %e", WebhookChannelName, err)
79+
}
80+
break
8081
}
81-
break
82+
currentBackoff := p.MinWaitBtwnRetriesMS * (1 << i)
83+
time.Sleep(jitter(time.Duration(currentBackoff)) * time.Millisecond)
8284
}
83-
currentBackoff := p.MinWaitBtwnRetriesMS * (1 << i)
84-
time.Sleep(jitter(time.Duration(currentBackoff)) * time.Millisecond)
8585
}
8686
if !sent {
8787
err := p.Store.UpsertTransaction(

‎internal/tss/router/router.go

+2
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ func (r *router) Route(payload tss.Payload) error {
6565
}
6666
} else if payload.RpcGetIngestTxResponse.Status != "" {
6767
channel = r.WebhookChannel
68+
} else {
69+
channel = r.RPCCallerChannel
6870
}
6971
if channel == nil {
7072
return fmt.Errorf("payload could not be routed - channel is nil")

‎internal/tss/router/router_test.go

+8-3
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,17 @@ func TestRouter(t *testing.T) {
172172
assert.NoError(t, err)
173173
webhookChannel.AssertCalled(t, "Send", payload)
174174
})
175-
t.Run("nil_channel_does_not_route", func(t *testing.T) {
175+
t.Run("empty_payload_routes_to_rpc_caller_channel", func(t *testing.T) {
176176
payload := tss.Payload{}
177177

178+
rpcCallerChannel.
179+
On("Send", payload).
180+
Return().
181+
Once()
182+
178183
err := router.Route(payload)
179184

180-
errorJitterChannel.AssertNotCalled(t, "Send", payload)
181-
assert.Equal(t, "payload could not be routed - channel is nil", err.Error())
185+
assert.NoError(t, err)
186+
rpcCallerChannel.AssertCalled(t, "Send", payload)
182187
})
183188
}

‎internal/tss/services/transaction_service.go

+36-4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66

77
"github.com/stellar/go/clients/horizonclient"
8+
"github.com/stellar/go/support/log"
89
"github.com/stellar/go/txnbuild"
910
"github.com/stellar/wallet-backend/internal/signing"
1011
tsserror "github.com/stellar/wallet-backend/internal/tss/errors"
@@ -67,6 +68,25 @@ func (t *transactionService) NetworkPassphrase() string {
6768
return t.DistributionAccountSignatureClient.NetworkPassphrase()
6869
}
6970

71+
func buildPayments(srcAccount string, operations []txnbuild.Operation) ([]txnbuild.Operation, error) {
72+
var payments []txnbuild.Operation
73+
for _, op := range operations {
74+
origPayment, ok := op.(*txnbuild.Payment)
75+
if !ok {
76+
return nil, fmt.Errorf("unable to convert operation to payment op")
77+
}
78+
payment := &txnbuild.Payment{
79+
SourceAccount: srcAccount,
80+
Amount: origPayment.Amount,
81+
Destination: origPayment.Destination,
82+
Asset: origPayment.Asset,
83+
}
84+
payments = append(payments, payment)
85+
86+
}
87+
return payments, nil
88+
}
89+
7090
func (t *transactionService) SignAndBuildNewFeeBumpTransaction(ctx context.Context, origTxXdr string) (*txnbuild.FeeBumpTransaction, error) {
7191
genericTx, err := txnbuild.TransactionFromXDR(origTxXdr)
7292
if err != nil {
@@ -84,10 +104,22 @@ func (t *transactionService) SignAndBuildNewFeeBumpTransaction(ctx context.Conte
84104
if err != nil {
85105
return nil, fmt.Errorf("getting channel account details from horizon: %w", err)
86106
}
107+
108+
distributionAccountPublicKey, err := t.DistributionAccountSignatureClient.GetAccountPublicKey(ctx)
109+
if err != nil {
110+
return nil, fmt.Errorf("getting distribution account public key: %w", err)
111+
}
112+
113+
operations, err := buildPayments(distributionAccountPublicKey, originalTx.Operations())
114+
if err != nil {
115+
return nil, fmt.Errorf("building payment operations: %w", err)
116+
}
117+
log.Info(operations)
118+
87119
tx, err := txnbuild.NewTransaction(
88120
txnbuild.TransactionParams{
89121
SourceAccount: &channelAccount,
90-
Operations: originalTx.Operations(),
122+
Operations: operations,
91123
BaseFee: int64(t.BaseFee),
92124
Preconditions: txnbuild.Preconditions{
93125
TimeBounds: txnbuild.NewTimeout(120),
@@ -102,10 +134,10 @@ func (t *transactionService) SignAndBuildNewFeeBumpTransaction(ctx context.Conte
102134
if err != nil {
103135
return nil, fmt.Errorf("signing transaction with channel account: %w", err)
104136
}
105-
// Wrap the transaction in a fee bump tx, signed by the distribution account
106-
distributionAccountPublicKey, err := t.DistributionAccountSignatureClient.GetAccountPublicKey(ctx)
137+
138+
tx, err = t.DistributionAccountSignatureClient.SignStellarTransaction(ctx, tx, distributionAccountPublicKey)
107139
if err != nil {
108-
return nil, fmt.Errorf("getting distribution account public key: %w", err)
140+
return nil, fmt.Errorf("signing transaction with distribution account: %w", err)
109141
}
110142

111143
feeBumpTx, err := txnbuild.NewFeeBumpTransaction(

‎internal/tss/services/transaction_service_test.go

+76-20
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,23 @@ func TestValidateOptions(t *testing.T) {
6363
})
6464
}
6565

66+
func TestBuildPayments(t *testing.T) {
67+
dest := "ABCD"
68+
operations := []txnbuild.Operation{
69+
&txnbuild.Payment{
70+
Destination: dest,
71+
Amount: "1.0",
72+
Asset: txnbuild.NativeAsset{},
73+
},
74+
}
75+
src := "EFGH"
76+
payments, error := buildPayments(src, operations)
77+
assert.Empty(t, error)
78+
assert.Equal(t, src, payments[0].(*txnbuild.Payment).SourceAccount)
79+
assert.Equal(t, dest, payments[0].(*txnbuild.Payment).Destination)
80+
assert.Equal(t, txnbuild.NativeAsset{}, payments[0].(*txnbuild.Payment).Asset)
81+
}
82+
6683
func TestSignAndBuildNewFeeBumpTransaction(t *testing.T) {
6784
distributionAccountSignatureClient := signing.SignatureClientMock{}
6885
defer distributionAccountSignatureClient.AssertExpectations(t)
@@ -115,7 +132,31 @@ func TestSignAndBuildNewFeeBumpTransaction(t *testing.T) {
115132
assert.Equal(t, "getting channel account details from horizon: horizon down", err.Error())
116133
})
117134

118-
t.Run("horizon_client_sign_stellar_transaction_w_channel_account_err", func(t *testing.T) {
135+
t.Run("distribution_account_signature_client_get_account_public_key_err", func(t *testing.T) {
136+
channelAccount := keypair.MustRandom()
137+
channelAccountSignatureClient.
138+
On("GetAccountPublicKey", context.Background()).
139+
Return(channelAccount.Address(), nil).
140+
Once()
141+
142+
distributionAccountSignatureClient.
143+
On("GetAccountPublicKey", context.Background()).
144+
Return("", errors.New("client down")).
145+
Once()
146+
147+
horizonClient.
148+
On("AccountDetail", horizonclient.AccountRequest{
149+
AccountID: channelAccount.Address(),
150+
}).
151+
Return(horizon.Account{AccountID: channelAccount.Address(), Sequence: 1}, nil).
152+
Once()
153+
154+
feeBumpTx, err := txService.SignAndBuildNewFeeBumpTransaction(context.Background(), txStr)
155+
assert.Empty(t, feeBumpTx)
156+
assert.Equal(t, "getting distribution account public key: client down", err.Error())
157+
})
158+
159+
t.Run("sign_stellar_transaction_w_channel_account_err", func(t *testing.T) {
119160
channelAccount := keypair.MustRandom()
120161
channelAccountSignatureClient.
121162
On("GetAccountPublicKey", context.Background()).
@@ -124,6 +165,11 @@ func TestSignAndBuildNewFeeBumpTransaction(t *testing.T) {
124165
On("SignStellarTransaction", context.Background(), mock.AnythingOfType("*txnbuild.Transaction"), []string{channelAccount.Address()}).
125166
Return(nil, errors.New("unable to sign")).
126167
Once()
168+
distributionAccount := keypair.MustRandom()
169+
distributionAccountSignatureClient.
170+
On("GetAccountPublicKey", context.Background()).
171+
Return(distributionAccount.Address(), nil).
172+
Once()
127173

128174
horizonClient.
129175
On("AccountDetail", horizonclient.AccountRequest{
@@ -137,20 +183,24 @@ func TestSignAndBuildNewFeeBumpTransaction(t *testing.T) {
137183
assert.Equal(t, "signing transaction with channel account: unable to sign", err.Error())
138184
})
139185

140-
t.Run("distribution_account_signature_client_get_account_public_key_err", func(t *testing.T) {
186+
t.Run("sign_stellar_transaction_w_distribition_account_err", func(t *testing.T) {
141187
channelAccount := keypair.MustRandom()
142-
signedTx := txnbuild.Transaction{}
188+
signedTx := utils.BuildTestTransaction()
143189
channelAccountSignatureClient.
144190
On("GetAccountPublicKey", context.Background()).
145191
Return(channelAccount.Address(), nil).
146192
Once().
147193
On("SignStellarTransaction", context.Background(), mock.AnythingOfType("*txnbuild.Transaction"), []string{channelAccount.Address()}).
148-
Return(&signedTx, nil).
194+
Return(signedTx, nil).
149195
Once()
150196

197+
distributionAccount := keypair.MustRandom()
151198
distributionAccountSignatureClient.
152199
On("GetAccountPublicKey", context.Background()).
153-
Return("", errors.New("client down")).
200+
Return(distributionAccount.Address(), nil).
201+
Once().
202+
On("SignStellarTransaction", context.Background(), mock.AnythingOfType("*txnbuild.Transaction"), []string{distributionAccount.Address()}).
203+
Return(nil, errors.New("unable to sign")).
154204
Once()
155205

156206
horizonClient.
@@ -162,33 +212,36 @@ func TestSignAndBuildNewFeeBumpTransaction(t *testing.T) {
162212

163213
feeBumpTx, err := txService.SignAndBuildNewFeeBumpTransaction(context.Background(), txStr)
164214
assert.Empty(t, feeBumpTx)
165-
assert.Equal(t, "getting distribution account public key: client down", err.Error())
215+
assert.Equal(t, "signing transaction with distribution account: unable to sign", err.Error())
166216
})
167217

168-
t.Run("horizon_client_sign_stellar_transaction_w_distribition_account_err", func(t *testing.T) {
169-
account := keypair.MustRandom()
218+
t.Run("sign_feebump_transaction_w_distribition_account_err", func(t *testing.T) {
219+
channelAccount := keypair.MustRandom()
170220
signedTx := utils.BuildTestTransaction()
171221
channelAccountSignatureClient.
172222
On("GetAccountPublicKey", context.Background()).
173-
Return(account.Address(), nil).
223+
Return(channelAccount.Address(), nil).
174224
Once().
175-
On("SignStellarTransaction", context.Background(), mock.AnythingOfType("*txnbuild.Transaction"), []string{account.Address()}).
225+
On("SignStellarTransaction", context.Background(), mock.AnythingOfType("*txnbuild.Transaction"), []string{channelAccount.Address()}).
176226
Return(signedTx, nil).
177227
Once()
178228

229+
distributionAccount := keypair.MustRandom()
179230
distributionAccountSignatureClient.
180231
On("GetAccountPublicKey", context.Background()).
181-
Return(account.Address(), nil).
232+
Return(distributionAccount.Address(), nil).
182233
Once().
234+
On("SignStellarTransaction", context.Background(), mock.AnythingOfType("*txnbuild.Transaction"), []string{distributionAccount.Address()}).
235+
Return(signedTx, nil).
183236
On("SignStellarFeeBumpTransaction", context.Background(), mock.AnythingOfType("*txnbuild.FeeBumpTransaction")).
184237
Return(nil, errors.New("unable to sign")).
185238
Once()
186239

187240
horizonClient.
188241
On("AccountDetail", horizonclient.AccountRequest{
189-
AccountID: account.Address(),
242+
AccountID: channelAccount.Address(),
190243
}).
191-
Return(horizon.Account{AccountID: account.Address(), Sequence: 1}, nil).
244+
Return(horizon.Account{AccountID: channelAccount.Address(), Sequence: 1}, nil).
192245
Once()
193246

194247
feeBumpTx, err := txService.SignAndBuildNewFeeBumpTransaction(context.Background(), txStr)
@@ -197,36 +250,39 @@ func TestSignAndBuildNewFeeBumpTransaction(t *testing.T) {
197250
})
198251

199252
t.Run("returns_signed_tx", func(t *testing.T) {
200-
account := keypair.MustRandom()
253+
channelAccount := keypair.MustRandom()
201254
signedTx := utils.BuildTestTransaction()
202255
testFeeBumpTx, _ := txnbuild.NewFeeBumpTransaction(
203256
txnbuild.FeeBumpTransactionParams{
204257
Inner: signedTx,
205-
FeeAccount: account.Address(),
258+
FeeAccount: channelAccount.Address(),
206259
BaseFee: int64(100),
207260
},
208261
)
209262
channelAccountSignatureClient.
210263
On("GetAccountPublicKey", context.Background()).
211-
Return(account.Address(), nil).
264+
Return(channelAccount.Address(), nil).
212265
Once().
213-
On("SignStellarTransaction", context.Background(), mock.AnythingOfType("*txnbuild.Transaction"), []string{account.Address()}).
266+
On("SignStellarTransaction", context.Background(), mock.AnythingOfType("*txnbuild.Transaction"), []string{channelAccount.Address()}).
214267
Return(signedTx, nil).
215268
Once()
216269

270+
distributionAccount := keypair.MustRandom()
217271
distributionAccountSignatureClient.
218272
On("GetAccountPublicKey", context.Background()).
219-
Return(account.Address(), nil).
273+
Return(distributionAccount.Address(), nil).
220274
Once().
275+
On("SignStellarTransaction", context.Background(), mock.AnythingOfType("*txnbuild.Transaction"), []string{distributionAccount.Address()}).
276+
Return(signedTx, nil).
221277
On("SignStellarFeeBumpTransaction", context.Background(), mock.AnythingOfType("*txnbuild.FeeBumpTransaction")).
222278
Return(testFeeBumpTx, nil).
223279
Once()
224280

225281
horizonClient.
226282
On("AccountDetail", horizonclient.AccountRequest{
227-
AccountID: account.Address(),
283+
AccountID: channelAccount.Address(),
228284
}).
229-
Return(horizon.Account{AccountID: account.Address(), Sequence: 1}, nil).
285+
Return(horizon.Account{AccountID: channelAccount.Address(), Sequence: 1}, nil).
230286
Once()
231287

232288
feeBumpTx, err := txService.SignAndBuildNewFeeBumpTransaction(context.Background(), txStr)

‎internal/tss/types.go

+8
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,16 @@ var FinalCodes = []xdr.TransactionResultCode{
100100
xdr.TransactionResultCodeTxFailed,
101101
xdr.TransactionResultCodeTxMissingOperation,
102102
xdr.TransactionResultCodeTxInsufficientBalance,
103+
xdr.TransactionResultCodeTxBadAuth,
103104
xdr.TransactionResultCodeTxBadAuthExtra,
104105
xdr.TransactionResultCodeTxMalformed,
106+
xdr.TransactionResultCodeTxNotSupported,
107+
xdr.TransactionResultCodeTxFeeBumpInnerFailed,
108+
xdr.TransactionResultCodeTxFeeBumpInnerSuccess,
109+
xdr.TransactionResultCodeTxNoAccount,
110+
xdr.TransactionResultCodeTxBadSponsorship,
111+
xdr.TransactionResultCodeTxSorobanInvalid,
112+
xdr.TransactionResultCodeTxBadMinSeqAgeOrGap,
105113
}
106114

107115
var NonJitterErrorCodes = []xdr.TransactionResultCode{

0 commit comments

Comments
 (0)
Please sign in to comment.