From caebe005dd94d9e146f54ad1be3cabf10f5ecb1c Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Fri, 31 Jan 2025 05:58:45 +0800 Subject: [PATCH 1/4] docs(keyring): add keyctl docs (#23563) --- docs/user/run-node/00-keyring.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/user/run-node/00-keyring.md b/docs/user/run-node/00-keyring.md index 0c95e1f13136..0b621439b050 100644 --- a/docs/user/run-node/00-keyring.md +++ b/docs/user/run-node/00-keyring.md @@ -29,12 +29,14 @@ is a list of the most popular operating systems and their respective passwords m * GNU/Linux: * [libsecret](https://gitlab.gnome.org/GNOME/libsecret) * [kwallet](https://api.kde.org/frameworks/kwallet/html/index.html) + * [keyctl](https://www.kernel.org/doc/html/latest/security/keys/core.html) GNU/Linux distributions that use GNOME as default desktop environment typically come with [Seahorse](https://wiki.gnome.org/Apps/Seahorse). Users of KDE based distributions are commonly provided with [KDE Wallet Manager](https://userbase.kde.org/KDE_Wallet_Manager). Whilst the former is in fact a `libsecret` convenient frontend, the latter is a `kwallet` -client. +client. `keyctl` is a secure backend leverages the Linux's kernel security key management system +to store cryptographic keys securely in memory. `os` is the default option since operating system's default credentials managers are designed to meet users' most common needs and provide them with a comfortable @@ -93,6 +95,15 @@ GNU/Linux distributions that ships KDE as default desktop environment. Please re [KWallet Handbook](https://docs.kde.org/stable5/en/kwalletmanager/kwallet5/index.html) for more information. +### The `keyctl` backend + +The *Kernel Key Retention Service* is a security facility that +has been added to the Linux kernel relatively recently. It allows sensitive +cryptographic data such as passwords, private key, authentication tokens, etc +to be stored securely in memory. + +The `keyctl` backend is available on Linux platforms only. + ### The `test` backend The `test` backend is a password-less variation of the `file` backend. Keys are stored From 8eb6822d258377eb3f683fbdb2fd2138154d092d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Jan 2025 11:18:26 +0100 Subject: [PATCH 2/4] build(deps): Bump actions/create-github-app-token from 1.11.1 to 1.11.2 (#23567) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/dependabot-update-all.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependabot-update-all.yml b/.github/workflows/dependabot-update-all.yml index b07cf17d0d42..eabe80537cc3 100644 --- a/.github/workflows/dependabot-update-all.yml +++ b/.github/workflows/dependabot-update-all.yml @@ -14,7 +14,7 @@ jobs: if: ${{ github.actor == 'dependabot[bot]' }} steps: - name: Generate Token - uses: actions/create-github-app-token@c1a285145b9d317df6ced56c09f525b5c2b6f755 # v1 + uses: actions/create-github-app-token@136412a57a7081aa63c935a2cc2918f76c34f514 # v1 id: app-token with: app-id: "${{ secrets.APP_ID }}" From ddf9e18ee49ee96fff7984d5ed32b9e6b44be736 Mon Sep 17 00:00:00 2001 From: Facundo Medica <14063057+facundomedica@users.noreply.github.com> Date: Fri, 31 Jan 2025 16:27:13 +0100 Subject: [PATCH 3/4] fix(auth): audit issues with unordered txs (#23392) Co-authored-by: Alex | Interchain Labs Co-authored-by: Alexander Peters --- types/mempool/mempool_test.go | 17 ++++++++ types/mempool/priority_nonce.go | 20 ++++----- types/mempool/priority_nonce_test.go | 37 ++++++++++++++++ types/mempool/sender_nonce.go | 28 ++++++------ types/mempool/sender_nonce_test.go | 65 ++++++++++++++++++++++++++++ x/auth/ante/ante_test.go | 32 ++++++++++++++ x/auth/ante/sigverify.go | 22 ++++++---- x/auth/ante/testutil_test.go | 62 ++++++++++++++++++++++++++ x/auth/ante/unordered.go | 48 ++++++++++++++++++-- 9 files changed, 296 insertions(+), 35 deletions(-) diff --git a/types/mempool/mempool_test.go b/types/mempool/mempool_test.go index e1351414644e..ac79723ec98b 100644 --- a/types/mempool/mempool_test.go +++ b/types/mempool/mempool_test.go @@ -5,6 +5,7 @@ import ( "fmt" "math/rand" "testing" + "time" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" @@ -55,6 +56,21 @@ type testTx struct { address sdk.AccAddress // useful for debugging strAddress string + unordered bool + timeout *time.Time +} + +// GetTimeoutTimeStamp implements types.TxWithUnordered. +func (tx testTx) GetTimeoutTimeStamp() time.Time { + if tx.timeout == nil { + return time.Time{} + } + return *tx.timeout +} + +// GetUnordered implements types.TxWithUnordered. +func (tx testTx) GetUnordered() bool { + return tx.unordered } func (tx testTx) GetSigners() ([][]byte, error) { panic("not implemented") } @@ -73,6 +89,7 @@ func (tx testTx) GetSignaturesV2() (res []txsigning.SignatureV2, err error) { var ( _ sdk.Tx = (*testTx)(nil) + _ sdk.TxWithUnordered = (*testTx)(nil) _ signing.SigVerifiableTx = (*testTx)(nil) _ cryptotypes.PubKey = (*testPubKey)(nil) ) diff --git a/types/mempool/priority_nonce.go b/types/mempool/priority_nonce.go index b324801ff5ec..b3ff3870e0c5 100644 --- a/types/mempool/priority_nonce.go +++ b/types/mempool/priority_nonce.go @@ -224,13 +224,13 @@ func (mp *PriorityNonceMempool[C]) Insert(ctx context.Context, tx sdk.Tx) error priority := mp.cfg.TxPriority.GetTxPriority(ctx, tx) nonce := sig.Sequence - // if it's an unordered tx, we use the gas instead of the nonce + // if it's an unordered tx, we use the timeout timestamp instead of the nonce if unordered, ok := tx.(sdk.TxWithUnordered); ok && unordered.GetUnordered() { - gasLimit, err := unordered.GetGasLimit() - nonce = gasLimit - if err != nil { - return err + timestamp := unordered.GetTimeoutTimeStamp().Unix() + if timestamp < 0 { + return errors.New("invalid timestamp value") } + nonce = uint64(timestamp) } key := txMeta[C]{nonce: nonce, priority: priority, sender: sender} @@ -469,13 +469,13 @@ func (mp *PriorityNonceMempool[C]) Remove(tx sdk.Tx) error { sender := sig.Signer.String() nonce := sig.Sequence - // if it's an unordered tx, we use the gas instead of the nonce + // if it's an unordered tx, we use the timeout timestamp instead of the nonce if unordered, ok := tx.(sdk.TxWithUnordered); ok && unordered.GetUnordered() { - gasLimit, err := unordered.GetGasLimit() - nonce = gasLimit - if err != nil { - return err + timestamp := unordered.GetTimeoutTimeStamp().Unix() + if timestamp < 0 { + return errors.New("invalid timestamp value") } + nonce = uint64(timestamp) } scoreKey := txMeta[C]{nonce: nonce, sender: sender} diff --git a/types/mempool/priority_nonce_test.go b/types/mempool/priority_nonce_test.go index 73d61cb9c2e9..aa4f73ac01d5 100644 --- a/types/mempool/priority_nonce_test.go +++ b/types/mempool/priority_nonce_test.go @@ -970,3 +970,40 @@ func TestNextSenderTx_TxReplacement(t *testing.T) { iter := mp.Select(ctx, nil) require.Equal(t, txs[3], iter.Tx()) } + +func TestPriorityNonceMempool_UnorderedTx(t *testing.T) { + ctx := sdk.NewContext(nil, false, log.NewNopLogger()) + accounts := simtypes.RandomAccounts(rand.New(rand.NewSource(0)), 2) + sa := accounts[0].Address + sb := accounts[1].Address + + mp := mempool.DefaultPriorityMempool() + + now := time.Now() + oneHour := now.Add(1 * time.Hour) + thirtyMin := now.Add(30 * time.Minute) + twoHours := now.Add(2 * time.Hour) + fifteenMin := now.Add(15 * time.Minute) + + txs := []testTx{ + {id: 1, priority: 0, address: sa, timeout: &thirtyMin, unordered: true}, + {id: 0, priority: 0, address: sa, timeout: &oneHour, unordered: true}, + {id: 3, priority: 0, address: sb, timeout: &fifteenMin, unordered: true}, + {id: 2, priority: 0, address: sb, timeout: &twoHours, unordered: true}, + } + + for _, tx := range txs { + c := ctx.WithPriority(tx.priority) + require.NoError(t, mp.Insert(c, tx)) + } + + require.Equal(t, 4, mp.CountTx()) + + orderedTxs := fetchTxs(mp.Select(ctx, nil), 100000) + require.Equal(t, len(txs), len(orderedTxs)) + + // check order + for i, tx := range orderedTxs { + require.Equal(t, txs[i].id, tx.(testTx).id) + } +} diff --git a/types/mempool/sender_nonce.go b/types/mempool/sender_nonce.go index 60d1e2991940..118acd85c39d 100644 --- a/types/mempool/sender_nonce.go +++ b/types/mempool/sender_nonce.go @@ -139,21 +139,21 @@ func (snm *SenderNonceMempool) Insert(_ context.Context, tx sdk.Tx) error { sender := sdk.AccAddress(sig.PubKey.Address()).String() nonce := sig.Sequence + // if it's an unordered tx, we use the timeout timestamp instead of the nonce + if unordered, ok := tx.(sdk.TxWithUnordered); ok && unordered.GetUnordered() { + timestamp := unordered.GetTimeoutTimeStamp().Unix() + if timestamp < 0 { + return errors.New("invalid timestamp value") + } + nonce = uint64(timestamp) + } + senderTxs, found := snm.senders[sender] if !found { senderTxs = skiplist.New(skiplist.Uint64) snm.senders[sender] = senderTxs } - // if it's an unordered tx, we use the gas instead of the nonce - if unordered, ok := tx.(sdk.TxWithUnordered); ok && unordered.GetUnordered() { - gasLimit, err := unordered.GetGasLimit() - nonce = gasLimit - if err != nil { - return err - } - } - senderTxs.Set(nonce, tx) key := txKey{nonce: nonce, address: sender} @@ -236,13 +236,13 @@ func (snm *SenderNonceMempool) Remove(tx sdk.Tx) error { sender := sdk.AccAddress(sig.PubKey.Address()).String() nonce := sig.Sequence - // if it's an unordered tx, we use the gas instead of the nonce + // if it's an unordered tx, we use the timeout timestamp instead of the nonce if unordered, ok := tx.(sdk.TxWithUnordered); ok && unordered.GetUnordered() { - gasLimit, err := unordered.GetGasLimit() - nonce = gasLimit - if err != nil { - return err + timestamp := unordered.GetTimeoutTimeStamp().Unix() + if timestamp < 0 { + return errors.New("invalid timestamp value") } + nonce = uint64(timestamp) } senderTxs, found := snm.senders[sender] diff --git a/types/mempool/sender_nonce_test.go b/types/mempool/sender_nonce_test.go index d4e4fe565ee3..9db801c83f85 100644 --- a/types/mempool/sender_nonce_test.go +++ b/types/mempool/sender_nonce_test.go @@ -4,6 +4,7 @@ import ( "fmt" "math/rand" "testing" + "time" "github.com/stretchr/testify/require" @@ -192,3 +193,67 @@ func (s *MempoolTestSuite) TestTxNotFoundOnSender() { err = mp.Remove(tx) require.Equal(t, mempool.ErrTxNotFound, err) } + +func (s *MempoolTestSuite) TestUnorderedTx() { + t := s.T() + + ctx := sdk.NewContext(nil, false, log.NewNopLogger()) + accounts := simtypes.RandomAccounts(rand.New(rand.NewSource(0)), 2) + sa := accounts[0].Address + sb := accounts[1].Address + + mp := mempool.NewSenderNonceMempool(mempool.SenderNonceMaxTxOpt(5000)) + + now := time.Now() + oneHour := now.Add(1 * time.Hour) + thirtyMin := now.Add(30 * time.Minute) + twoHours := now.Add(2 * time.Hour) + fifteenMin := now.Add(15 * time.Minute) + + txs := []testTx{ + {id: 0, address: sa, timeout: &oneHour, unordered: true}, + {id: 1, address: sa, timeout: &thirtyMin, unordered: true}, + {id: 2, address: sb, timeout: &twoHours, unordered: true}, + {id: 3, address: sb, timeout: &fifteenMin, unordered: true}, + } + + for _, tx := range txs { + c := ctx.WithPriority(tx.priority) + require.NoError(t, mp.Insert(c, tx)) + } + + require.Equal(t, 4, mp.CountTx()) + + orderedTxs := fetchTxs(mp.Select(ctx, nil), 100000) + require.Equal(t, len(txs), len(orderedTxs)) + + // Because the sender is selected randomly it can be any of these options + acceptableOptions := [][]int{ + {3, 1, 2, 0}, + {3, 1, 0, 2}, + {3, 2, 1, 0}, + {1, 3, 0, 2}, + {1, 3, 2, 0}, + {1, 0, 3, 2}, + } + + orderedTxsIds := make([]int, len(orderedTxs)) + for i, tx := range orderedTxs { + orderedTxsIds[i] = tx.(testTx).id + } + + anyAcceptableOrder := false + for _, option := range acceptableOptions { + for i, tx := range orderedTxs { + if tx.(testTx).id != txs[option[i]].id { + break + } + + if i == len(orderedTxs)-1 { + anyAcceptableOrder = true + } + } + } + + require.True(t, anyAcceptableOrder, "expected any of %v but got %v", acceptableOptions, orderedTxsIds) +} diff --git a/x/auth/ante/ante_test.go b/x/auth/ante/ante_test.go index 32d8e3641871..87eb660b815c 100644 --- a/x/auth/ante/ante_test.go +++ b/x/auth/ante/ante_test.go @@ -6,6 +6,7 @@ import ( "fmt" "strings" "testing" + "time" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" @@ -1384,3 +1385,34 @@ func TestAnteHandlerReCheck(t *testing.T) { _, err = suite.anteHandler(suite.ctx, tx, false) require.NotNil(t, err, "antehandler on recheck did not fail once feePayer no longer has sufficient funds") } + +func TestAnteHandlerUnorderedTx(t *testing.T) { + suite := SetupTestSuite(t, false) + accs := suite.CreateTestAccounts(1) + msg := testdata.NewTestMsg(accs[0].acc.GetAddress()) + + // First send a normal sequential tx with sequence 0 + suite.bankKeeper.EXPECT().SendCoinsFromAccountToModule(gomock.Any(), accs[0].acc.GetAddress(), authtypes.FeeCollectorName, testdata.NewTestFeeAmount()).Return(nil).AnyTimes() + + privs, accNums, accSeqs := []cryptotypes.PrivKey{accs[0].priv}, []uint64{1000}, []uint64{0} + _, err := suite.DeliverMsgs(t, privs, []sdk.Msg{msg}, testdata.NewTestFeeAmount(), testdata.NewTestGasLimit(), accNums, accSeqs, suite.ctx.ChainID(), false) + require.NoError(t, err) + + // we try to send another tx with the same sequence, it will fail + _, err = suite.DeliverMsgs(t, privs, []sdk.Msg{msg}, testdata.NewTestFeeAmount(), testdata.NewTestGasLimit(), accNums, accSeqs, suite.ctx.ChainID(), false) + require.Error(t, err) + + // now we'll still use the same sequence but because it's unordered, it will be ignored and accepted anyway + msgs := []sdk.Msg{msg} + require.NoError(t, suite.txBuilder.SetMsgs(msgs...)) + suite.txBuilder.SetFeeAmount(testdata.NewTestFeeAmount()) + suite.txBuilder.SetGasLimit(testdata.NewTestGasLimit()) + + tx, txErr := suite.CreateTestUnorderedTx(suite.ctx, privs, accNums, accSeqs, suite.ctx.ChainID(), apisigning.SignMode_SIGN_MODE_DIRECT, true, time.Now().Add(time.Minute)) + require.NoError(t, txErr) + txBytes, err := suite.clientCtx.TxConfig.TxEncoder()(tx) + bytesCtx := suite.ctx.WithTxBytes(txBytes) + require.NoError(t, err) + _, err = suite.anteHandler(bytesCtx, tx, false) + require.NoError(t, err) +} diff --git a/x/auth/ante/sigverify.go b/x/auth/ante/sigverify.go index 0e52f349a381..cbd0ae619afa 100644 --- a/x/auth/ante/sigverify.go +++ b/x/auth/ante/sigverify.go @@ -320,18 +320,24 @@ func (svd SigVerificationDecorator) consumeSignatureGas( // verifySig will verify the signature of the provided signer account. func (svd SigVerificationDecorator) verifySig(ctx context.Context, tx sdk.Tx, acc sdk.AccountI, sig signing.SignatureV2, newlyCreated bool) error { execMode := svd.ak.GetEnvironment().TransactionService.ExecMode(ctx) - if execMode == transaction.ExecModeCheck { - if sig.Sequence < acc.GetSequence() { + unorderedTx, ok := tx.(sdk.TxWithUnordered) + isUnordered := ok && unorderedTx.GetUnordered() + + // only check sequence if the tx is not unordered + if !isUnordered { + if execMode == transaction.ExecModeCheck { + if sig.Sequence < acc.GetSequence() { + return errorsmod.Wrapf( + sdkerrors.ErrWrongSequence, + "account sequence mismatch: expected higher than or equal to %d, got %d", acc.GetSequence(), sig.Sequence, + ) + } + } else if sig.Sequence != acc.GetSequence() { return errorsmod.Wrapf( sdkerrors.ErrWrongSequence, - "account sequence mismatch, expected higher than or equal to %d, got %d", acc.GetSequence(), sig.Sequence, + "account sequence mismatch: expected %d, got %d", acc.GetSequence(), sig.Sequence, ) } - } else if sig.Sequence != acc.GetSequence() { - return errorsmod.Wrapf( - sdkerrors.ErrWrongSequence, - "account sequence mismatch: expected %d, got %d", acc.GetSequence(), sig.Sequence, - ) } // we're in simulation mode, or in ReCheckTx, or context is not diff --git a/x/auth/ante/testutil_test.go b/x/auth/ante/testutil_test.go index 51f1e2b215bd..b9af2bb77694 100644 --- a/x/auth/ante/testutil_test.go +++ b/x/auth/ante/testutil_test.go @@ -3,6 +3,7 @@ package ante_test import ( "context" "testing" + "time" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" @@ -241,6 +242,67 @@ func (suite *AnteTestSuite) RunTestCase(t *testing.T, tc TestCase, args TestCase } } +func (suite *AnteTestSuite) CreateTestUnorderedTx( + ctx sdk.Context, privs []cryptotypes.PrivKey, + accNums, accSeqs []uint64, + chainID string, signMode apisigning.SignMode, + unordered bool, unorderedTimeout time.Time, +) (xauthsigning.Tx, error) { + suite.txBuilder.SetUnordered(unordered) + suite.txBuilder.SetTimeoutTimestamp(unorderedTimeout) + + // First round: we gather all the signer infos. We use the "set empty + // signature" hack to do that. + var sigsV2 []signing.SignatureV2 + for i, priv := range privs { + sigV2 := signing.SignatureV2{ + PubKey: priv.PubKey(), + Data: &signing.SingleSignatureData{ + SignMode: signMode, + Signature: nil, + }, + Sequence: accSeqs[i], + } + + sigsV2 = append(sigsV2, sigV2) + } + err := suite.txBuilder.SetSignatures(sigsV2...) + if err != nil { + return nil, err + } + + // Second round: all signer infos are set, so each signer can sign. + sigsV2 = []signing.SignatureV2{} + for i, priv := range privs { + anyPk, err := codectypes.NewAnyWithValue(priv.PubKey()) + if err != nil { + return nil, err + } + + signerData := txsigning.SignerData{ + Address: sdk.AccAddress(priv.PubKey().Address()).String(), + ChainID: chainID, + AccountNumber: accNums[i], + Sequence: accSeqs[i], + PubKey: &anypb.Any{TypeUrl: anyPk.TypeUrl, Value: anyPk.Value}, + } + sigV2, err := tx.SignWithPrivKey( + ctx, signMode, signerData, + suite.txBuilder, priv, suite.clientCtx.TxConfig, accSeqs[i]) + if err != nil { + return nil, err + } + + sigsV2 = append(sigsV2, sigV2) + } + err = suite.txBuilder.SetSignatures(sigsV2...) + if err != nil { + return nil, err + } + + return suite.txBuilder.GetTx(), nil +} + // CreateTestTx is a helper function to create a tx given multiple inputs. func (suite *AnteTestSuite) CreateTestTx( ctx sdk.Context, privs []cryptotypes.PrivKey, diff --git a/x/auth/ante/unordered.go b/x/auth/ante/unordered.go index 1d1b36c852fa..abd14d43e9a2 100644 --- a/x/auth/ante/unordered.go +++ b/x/auth/ante/unordered.go @@ -17,7 +17,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/tx/signing" "github.com/cosmos/cosmos-sdk/x/auth/ante/unorderedtx" + authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" ) // bufPool is a pool of bytes.Buffer objects to reduce memory allocations. @@ -146,8 +148,12 @@ func (d *UnorderedTxDecorator) ValidateTx(ctx context.Context, tx transaction.Tx // TxIdentifier returns a unique identifier for a transaction that is intended to be unordered. func TxIdentifier(timeout uint64, tx sdk.Tx) ([32]byte, error) { - feetx := tx.(sdk.FeeTx) - if feetx.GetFee().IsZero() { + sigTx, ok := tx.(authsigning.Tx) + if !ok { + return [32]byte{}, errorsmod.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type") + } + + if sigTx.GetFee().IsZero() { return [32]byte{}, errorsmod.Wrap( sdkerrors.ErrInvalidRequest, "unordered transaction must have a fee", @@ -159,6 +165,18 @@ func TxIdentifier(timeout uint64, tx sdk.Tx) ([32]byte, error) { buf.Reset() defer bufPool.Put(buf) + // Add signatures to the transaction identifier + signatures, err := sigTx.GetSignaturesV2() + if err != nil { + return [32]byte{}, err + } + + for _, sig := range signatures { + if err := addSignatures(sig.Data, buf); err != nil { + return [32]byte{}, err + } + } + // Use the buffer for _, msg := range tx.GetMsgs() { // loop through the messages and write them to the buffer @@ -189,7 +207,7 @@ func TxIdentifier(timeout uint64, tx sdk.Tx) ([32]byte, error) { } // write gas to the buffer - if err := binary.Write(buf, binary.LittleEndian, feetx.GetGas()); err != nil { + if err := binary.Write(buf, binary.LittleEndian, sigTx.GetGas()); err != nil { return [32]byte{}, errorsmod.Wrap( sdkerrors.ErrInvalidRequest, "failed to write unordered to buffer", @@ -201,3 +219,27 @@ func TxIdentifier(timeout uint64, tx sdk.Tx) ([32]byte, error) { // Return the Buffer to the pool return txHash, nil } + +func addSignatures(sig signing.SignatureData, buf *bytes.Buffer) error { + switch data := sig.(type) { + case *signing.SingleSignatureData: + if _, err := buf.Write(data.Signature); err != nil { + return errorsmod.Wrap( + sdkerrors.ErrInvalidRequest, + "failed to write single signature to buffer", + ) + } + return nil + + case *signing.MultiSignatureData: + for _, sigdata := range data.Signatures { + if err := addSignatures(sigdata, buf); err != nil { + return err + } + } + default: + return fmt.Errorf("unexpected SignatureData %T", data) + } + + return nil +} From 009bcc38e5fe5109281f570e9a557a55af905517 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 31 Jan 2025 16:34:37 +0100 Subject: [PATCH 4/4] fix(simapp/v2): wire swagger in testnet cmd (#23570) --- server/v2/api/swagger/server.go | 9 +++++++++ simapp/v2/simdv2/cmd/testnet.go | 11 ++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/server/v2/api/swagger/server.go b/server/v2/api/swagger/server.go index 8592968ae1fa..1966610fd925 100644 --- a/server/v2/api/swagger/server.go +++ b/server/v2/api/swagger/server.go @@ -64,6 +64,15 @@ func New[T transaction.Tx]( return s, nil } +// NewWithConfigOptions creates a new telemetry server with the provided config options. +// It is *not* a fully functional server (since it has been created without dependencies) +// The returned server should only be used to get and set configuration. +func NewWithConfigOptions[T transaction.Tx](opts ...CfgOption) *Server[T] { + return &Server[T]{ + cfgOptions: opts, + } +} + // Name returns the server's name func (s *Server[T]) Name() string { return ServerName diff --git a/simapp/v2/simdv2/cmd/testnet.go b/simapp/v2/simdv2/cmd/testnet.go index 1b280b7161b3..ccd8c871249e 100644 --- a/simapp/v2/simdv2/cmd/testnet.go +++ b/simapp/v2/simdv2/cmd/testnet.go @@ -22,6 +22,7 @@ import ( "cosmossdk.io/server/v2/api/grpc" "cosmossdk.io/server/v2/api/grpcgateway" "cosmossdk.io/server/v2/api/rest" + "cosmossdk.io/server/v2/api/swagger" "cosmossdk.io/server/v2/api/telemetry" "cosmossdk.io/server/v2/cometbft" "cosmossdk.io/server/v2/store" @@ -188,6 +189,7 @@ func initTestnetFiles[T transaction.Tx]( grpcPort = 9090 restPort = 8080 telemetryPort = 7180 + swaggerPort = 8090 ) p2pPortStart := 26656 @@ -199,6 +201,7 @@ func initTestnetFiles[T transaction.Tx]( grpcgatewayConfig := grpcgateway.DefaultConfig() restConfig := rest.DefaultConfig() telemetryConfig := telemetry.DefaultConfig() + swaggerConfig := swagger.DefaultConfig() if args.singleMachine { portOffset = i @@ -228,6 +231,11 @@ func initTestnetFiles[T transaction.Tx]( Enable: true, Address: fmt.Sprintf("127.0.0.1:%d", telemetryPort+portOffset), } + + swaggerConfig = &swagger.Config{ + Enable: true, + Address: fmt.Sprintf("127.0.0.1:%d", swaggerPort+portOffset), + } } nodeDirName := fmt.Sprintf("%s%d", args.nodeDirPrefix, i) @@ -364,7 +372,8 @@ func initTestnetFiles[T transaction.Tx]( grpcgatewayServer := grpcgateway.NewWithConfigOptions[T](grpcgateway.OverwriteDefaultConfig(grpcgatewayConfig)) restServer := rest.NewWithConfigOptions[T](rest.OverwriteDefaultConfig(restConfig)) telemetryServer := telemetry.NewWithConfigOptions[T](telemetry.OverwriteDefaultConfig(telemetryConfig)) - server := serverv2.NewServer[T](serverCfg, cometServer, storeServer, grpcServer, grpcgatewayServer, restServer, telemetryServer) + swaggerServer := swagger.NewWithConfigOptions[T](swagger.OverwriteDefaultConfig(swaggerConfig)) + server := serverv2.NewServer[T](serverCfg, cometServer, storeServer, grpcServer, grpcgatewayServer, restServer, telemetryServer, swaggerServer) err = server.WriteConfig(filepath.Join(nodeDir, "config")) if err != nil { return err