github.com/cosmos/cosmos-sdk@v0.50.10/types/mempool/mempool_test.go (about)

     1  package mempool_test
     2  
     3  import (
     4  	"fmt"
     5  	"math/rand"
     6  	"testing"
     7  
     8  	cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
     9  	"github.com/stretchr/testify/require"
    10  	"github.com/stretchr/testify/suite"
    11  	protov2 "google.golang.org/protobuf/proto"
    12  
    13  	"cosmossdk.io/log"
    14  
    15  	cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
    16  	sdk "github.com/cosmos/cosmos-sdk/types"
    17  	"github.com/cosmos/cosmos-sdk/types/mempool"
    18  	moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
    19  	simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
    20  	txsigning "github.com/cosmos/cosmos-sdk/types/tx/signing"
    21  	"github.com/cosmos/cosmos-sdk/x/auth/signing"
    22  	"github.com/cosmos/cosmos-sdk/x/distribution"
    23  	"github.com/cosmos/cosmos-sdk/x/gov"
    24  )
    25  
    26  // testPubKey is a dummy implementation of PubKey used for testing.
    27  type testPubKey struct {
    28  	address sdk.AccAddress
    29  }
    30  
    31  func (t testPubKey) Reset() { panic("not implemented") }
    32  
    33  func (t testPubKey) String() string { panic("not implemented") }
    34  
    35  func (t testPubKey) ProtoMessage() { panic("not implemented") }
    36  
    37  func (t testPubKey) Address() cryptotypes.Address { return t.address.Bytes() }
    38  
    39  func (t testPubKey) Bytes() []byte { panic("not implemented") }
    40  
    41  func (t testPubKey) VerifySignature(msg, sig []byte) bool { panic("not implemented") }
    42  
    43  func (t testPubKey) Equals(key cryptotypes.PubKey) bool { panic("not implemented") }
    44  
    45  func (t testPubKey) Type() string { panic("not implemented") }
    46  
    47  // testTx is a dummy implementation of Tx used for testing.
    48  type testTx struct {
    49  	id       int
    50  	priority int64
    51  	nonce    uint64
    52  	address  sdk.AccAddress
    53  	// useful for debugging
    54  	strAddress string
    55  }
    56  
    57  func (tx testTx) GetSigners() ([][]byte, error) { panic("not implemented") }
    58  
    59  func (tx testTx) GetPubKeys() ([]cryptotypes.PubKey, error) { panic("not implemented") }
    60  
    61  func (tx testTx) GetSignaturesV2() (res []txsigning.SignatureV2, err error) {
    62  	res = append(res, txsigning.SignatureV2{
    63  		PubKey:   testPubKey{address: tx.address},
    64  		Data:     nil,
    65  		Sequence: tx.nonce,
    66  	})
    67  
    68  	return res, nil
    69  }
    70  
    71  var (
    72  	_ sdk.Tx                  = (*testTx)(nil)
    73  	_ signing.SigVerifiableTx = (*testTx)(nil)
    74  	_ cryptotypes.PubKey      = (*testPubKey)(nil)
    75  )
    76  
    77  func (tx testTx) GetMsgs() []sdk.Msg { return nil }
    78  
    79  func (tx testTx) GetMsgsV2() ([]protov2.Message, error) { return nil, nil }
    80  
    81  func (tx testTx) ValidateBasic() error { return nil }
    82  
    83  func (tx testTx) String() string {
    84  	return fmt.Sprintf("tx a: %s, p: %d, n: %d", tx.address, tx.priority, tx.nonce)
    85  }
    86  
    87  type sigErrTx struct {
    88  	getSigs func() ([]txsigning.SignatureV2, error)
    89  }
    90  
    91  func (sigErrTx) Size() int64 { return 0 }
    92  
    93  func (sigErrTx) GetMsgs() []sdk.Msg { return nil }
    94  
    95  func (sigErrTx) GetMsgsV2() ([]protov2.Message, error) { return nil, nil }
    96  
    97  func (sigErrTx) ValidateBasic() error { return nil }
    98  
    99  func (sigErrTx) GetSigners() ([][]byte, error) { return nil, nil }
   100  
   101  func (sigErrTx) GetPubKeys() ([]cryptotypes.PubKey, error) { return nil, nil }
   102  
   103  func (t sigErrTx) GetSignaturesV2() ([]txsigning.SignatureV2, error) { return t.getSigs() }
   104  
   105  type txSpec struct {
   106  	i int
   107  	p int
   108  	n int
   109  	a sdk.AccAddress
   110  }
   111  
   112  func (tx txSpec) String() string {
   113  	return fmt.Sprintf("[tx i: %d, a: %s, p: %d, n: %d]", tx.i, tx.a, tx.p, tx.n)
   114  }
   115  
   116  func fetchTxs(iterator mempool.Iterator, maxBytes int64) []sdk.Tx {
   117  	const txSize = 1
   118  	var (
   119  		txs      []sdk.Tx
   120  		numBytes int64
   121  	)
   122  	for iterator != nil {
   123  		if numBytes += txSize; numBytes > maxBytes {
   124  			break
   125  		}
   126  		txs = append(txs, iterator.Tx())
   127  		i := iterator.Next()
   128  		iterator = i
   129  	}
   130  	return txs
   131  }
   132  
   133  func (s *MempoolTestSuite) TestDefaultMempool() {
   134  	t := s.T()
   135  	ctx := sdk.NewContext(nil, cmtproto.Header{}, false, log.NewNopLogger())
   136  	accounts := simtypes.RandomAccounts(rand.New(rand.NewSource(0)), 10)
   137  	txCount := 1000
   138  	var txs []testTx
   139  
   140  	for i := 0; i < txCount; i++ {
   141  		acc := accounts[i%len(accounts)]
   142  		tx := testTx{
   143  			nonce:    0,
   144  			address:  acc.Address,
   145  			priority: rand.Int63(),
   146  		}
   147  		txs = append(txs, tx)
   148  	}
   149  
   150  	// empty mempool behavior
   151  	require.Equal(t, 0, s.mempool.CountTx())
   152  	itr := s.mempool.Select(ctx, nil)
   153  	require.Nil(t, itr)
   154  
   155  	// same sender-nonce just overwrites a tx
   156  	for _, tx := range txs {
   157  		ctx = ctx.WithPriority(tx.priority)
   158  		err := s.mempool.Insert(ctx, tx)
   159  		require.NoError(t, err)
   160  	}
   161  	require.Equal(t, len(accounts), s.mempool.CountTx())
   162  
   163  	// distinct sender-nonce should not overwrite a tx
   164  	s.resetMempool()
   165  	for i, tx := range txs {
   166  		tx.nonce = uint64(i)
   167  		err := s.mempool.Insert(ctx, tx)
   168  		require.NoError(t, err)
   169  	}
   170  	require.Equal(t, txCount, s.mempool.CountTx())
   171  
   172  	itr = s.mempool.Select(ctx, nil)
   173  	sel := fetchTxs(itr, 13)
   174  	require.Equal(t, 13, len(sel))
   175  
   176  	// a tx which does not implement SigVerifiableTx should not be inserted
   177  	tx := &sigErrTx{getSigs: func() ([]txsigning.SignatureV2, error) {
   178  		return nil, fmt.Errorf("error")
   179  	}}
   180  	require.Error(t, s.mempool.Insert(ctx, tx))
   181  	require.Error(t, s.mempool.Remove(tx))
   182  	tx.getSigs = func() ([]txsigning.SignatureV2, error) {
   183  		return nil, nil
   184  	}
   185  	require.Error(t, s.mempool.Insert(ctx, tx))
   186  	require.Error(t, s.mempool.Remove(tx))
   187  
   188  	// removing a tx not in the mempool should error
   189  	s.resetMempool()
   190  	require.NoError(t, s.mempool.Insert(ctx, txs[0]))
   191  	require.ErrorIs(t, s.mempool.Remove(txs[1]), mempool.ErrTxNotFound)
   192  
   193  	// inserting a tx with a different priority should overwrite the old tx
   194  	newPriorityTx := testTx{
   195  		address:  txs[0].address,
   196  		priority: txs[0].priority + 1,
   197  		nonce:    txs[0].nonce,
   198  	}
   199  	require.NoError(t, s.mempool.Insert(ctx, newPriorityTx))
   200  	require.Equal(t, 1, s.mempool.CountTx())
   201  }
   202  
   203  type MempoolTestSuite struct {
   204  	suite.Suite
   205  	numTxs      int
   206  	numAccounts int
   207  	iterations  int
   208  	mempool     mempool.Mempool
   209  }
   210  
   211  func (s *MempoolTestSuite) resetMempool() {
   212  	s.iterations = 0
   213  	s.mempool = mempool.NewSenderNonceMempool(mempool.SenderNonceMaxTxOpt(5000))
   214  }
   215  
   216  func (s *MempoolTestSuite) SetupTest() {
   217  	s.numTxs = 1000
   218  	s.numAccounts = 100
   219  	s.resetMempool()
   220  }
   221  
   222  func TestMempoolTestSuite(t *testing.T) {
   223  	suite.Run(t, new(MempoolTestSuite))
   224  }
   225  
   226  func (s *MempoolTestSuite) TestSampleTxs() {
   227  	ctxt := sdk.NewContext(nil, cmtproto.Header{}, false, log.NewNopLogger())
   228  	t := s.T()
   229  	s.resetMempool()
   230  	mp := s.mempool
   231  	delegatorTx, err := unmarshalTx(msgWithdrawDelegatorReward)
   232  
   233  	require.NoError(t, err)
   234  	require.NoError(t, mp.Insert(ctxt, delegatorTx))
   235  	require.Equal(t, 1, mp.CountTx())
   236  
   237  	proposalTx, err := unmarshalTx(msgMultiSigMsgSubmitProposal)
   238  	require.NoError(t, err)
   239  	require.NoError(t, mp.Insert(ctxt, proposalTx))
   240  	require.Equal(t, 2, mp.CountTx())
   241  }
   242  
   243  func unmarshalTx(txBytes []byte) (sdk.Tx, error) {
   244  	cfg := moduletestutil.MakeTestEncodingConfig(distribution.AppModuleBasic{}, gov.AppModuleBasic{})
   245  	return cfg.TxConfig.TxJSONDecoder()(txBytes)
   246  }
   247  
   248  var (
   249  	msgWithdrawDelegatorReward   = []byte("{\"body\":{\"messages\":[{\"@type\":\"\\/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward\",\"delegator_address\":\"cosmos16w6g0whmw703t8h2m9qmq2fd9dwaw6fjszzjsw\",\"validator_address\":\"cosmosvaloper1lzhlnpahvznwfv4jmay2tgaha5kmz5qxerarrl\"},{\"@type\":\"\\/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward\",\"delegator_address\":\"cosmos16w6g0whmw703t8h2m9qmq2fd9dwaw6fjszzjsw\",\"validator_address\":\"cosmosvaloper1sjllsnramtg3ewxqwwrwjxfgc4n4ef9u2lcnj0\"},{\"@type\":\"\\/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward\",\"delegator_address\":\"cosmos16w6g0whmw703t8h2m9qmq2fd9dwaw6fjszzjsw\",\"validator_address\":\"cosmosvaloper196ax4vc0lwpxndu9dyhvca7jhxp70rmcvrj90c\"},{\"@type\":\"\\/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward\",\"delegator_address\":\"cosmos16w6g0whmw703t8h2m9qmq2fd9dwaw6fjszzjsw\",\"validator_address\":\"cosmosvaloper1k2d9ed9vgfuk2m58a2d80q9u6qljkh4vfaqjfq\"},{\"@type\":\"\\/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward\",\"delegator_address\":\"cosmos16w6g0whmw703t8h2m9qmq2fd9dwaw6fjszzjsw\",\"validator_address\":\"cosmosvaloper1vygmh344ldv9qefss9ek7ggsnxparljlmj56q5\"},{\"@type\":\"\\/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward\",\"delegator_address\":\"cosmos16w6g0whmw703t8h2m9qmq2fd9dwaw6fjszzjsw\",\"validator_address\":\"cosmosvaloper1ej2es5fjztqjcd4pwa0zyvaevtjd2y5wxxp9gd\"}],\"memo\":\"\",\"timeout_height\":\"0\",\"extension_options\":[],\"non_critical_extension_options\":[]},\"auth_info\":{\"signer_infos\":[{\"public_key\":{\"@type\":\"\\/cosmos.crypto.secp256k1.PubKey\",\"key\":\"AmbXAy10a0SerEefTYQzqyGQdX5kiTEWJZ1PZKX1oswX\"},\"mode_info\":{\"single\":{\"mode\":\"SIGN_MODE_LEGACY_AMINO_JSON\"}},\"sequence\":\"119\"}],\"fee\":{\"amount\":[{\"denom\":\"uatom\",\"amount\":\"15968\"}],\"gas_limit\":\"638717\",\"payer\":\"\",\"granter\":\"\"}},\"signatures\":[\"ji+inUo4xGlN9piRQLdLCeJWa7irwnqzrMVPcmzJyG5y6NPc+ZuNaIc3uvk5NLDJytRB8AHX0GqNETR\\/Q8fz4Q==\"]}")
   250  	msgMultiSigMsgSubmitProposal = []byte("{\"body\":{\"messages\":[{\"@type\":\"\\/cosmos.gov.v1beta1.MsgSubmitProposal\",\"content\":{\"@type\":\"\\/cosmos.distribution.v1beta1.CommunityPoolSpendProposal\",\"title\":\"ATOM \\ud83e\\udd1d Osmosis:  Allocate Community Pool to ATOM Liquidity Incentives\",\"description\":\"ATOMs should be the base money of Cosmos, just like ETH is the base money of the entire Ethereum DeFi ecosystem. ATOM is currently well positioned to play this role among Cosmos assets because it has the highest market cap, most liquidity, largest brand, and many integrations with fiat onramps. ATOM is the gateway to Cosmos.\\n\\nIn the Cosmos Hub Port City vision, ATOMs are pitched as equity in the Cosmos Hub.  However, this alone is insufficient to establish ATOM as the base currency of the Cosmos ecosystem as a whole. Instead, the ATOM community must work to actively promote the use of ATOMs throughout the Cosmos ecosystem, rather than passively relying on the Hub's reputation to create ATOM's value.\\n\\nIn order to cement the role of ATOMs in Cosmos DeFi, the Cosmos Hub should leverage its community pool to help align incentives with other protocols within the Cosmos ecosystem. We propose beginning this initiative by using the community pool ATOMs to incentivize deep ATOM base pair liquidity pools on the Osmosis Network.\\n\\nOsmosis is the first IBC-enabled DeFi application. Within its 3 weeks of existence, it has already 100x\\u2019d the number of IBC transactions ever created, demonstrating the power of IBC and the ability of the Cosmos SDK to bootstrap DeFi protocols with $100M+ TVL in a short period of time. Since its announcement Osmosis has helped bring renewed attention and interest to Cosmos from the crypto community at large and kickstarted the era of Cosmos DeFi.\\n\\nOsmosis has already helped in establishing ATOM as the Schelling Point of the Cosmos ecosystem.  The genesis distribution of OSMO was primarily based on an airdrop to ATOM holders specifically, acknowledging the importance of ATOM to all future projects within the Cosmos. Furthermore, the Osmosis LP rewards currently incentivize ATOMs to be one of the main base pairs of the platform.\\n\\nOsmosis has the ability to incentivize AMM liquidity, a feature not available on any other IBC-enabled DEX. Osmosis already uses its own native OSMO liquidity rewards to incentivize ATOMs to be one of the main base pairs, leading to ~2.2 million ATOMs already providing liquidity on the platform.\\n\\nIn addition to these native OSMO LP Rewards, the platform also includes a feature called \\u201cexternal incentives\\u201d that allows anyone to permissionlessly add additional incentives in any token to the LPs of any AMM pools they wish. You can read more about this mechanism here: https:\\/\\/medium.com\\/osmosis\\/osmosis-liquidity-mining-101-2fa58d0e9d4d#f413 . Pools containing Cosmos assets such as AKT and XPRT are already planned to receive incentives from their respective community pools and\\/or foundations.\\n\\nWe propose the Cosmos Hub dedicate 100,000 ATOMs from its Community Pool to be allocated towards liquidity incentives on Osmosis over the next 3 months. This community fund proposal will transfer 100,000 ATOMs to a multisig group who will then allocate the ATOMs to bonded liquidity gauges on Osmosis on a biweekly basis, according to direction given by Cosmos Hub governance.  For simplicity, we propose setting the liquidity incentives to initially point to Osmosis Pool #1, the ATOM\\/OSMO pool, which is the pool with by far the highest TVL and Volume. Cosmos Hub governance can then use Text Proposals to further direct the multisig members to reallocate incentives to new pools.\\n\\nThe multisig will consist of a 2\\/3 key holder set consisting of the following individuals whom have all agreed to participate in this process shall this proposal pass:\\n\\n- Zaki Manian\\n- Federico Kunze\\n- Marko Baricevic\\n\\nThis is one small step for the Hub, but one giant leap for ATOM-aligned.\\n\",\"recipient\":\"cosmos157n0d38vwn5dvh64rc39q3lyqez0a689g45rkc\",\"amount\":[{\"denom\":\"uatom\",\"amount\":\"100000000000\"}]},\"initial_deposit\":[{\"denom\":\"uatom\",\"amount\":\"64000000\"}],\"proposer\":\"cosmos1ey69r37gfxvxg62sh4r0ktpuc46pzjrmz29g45\"}],\"memo\":\"\",\"timeout_height\":\"0\",\"extension_options\":[],\"non_critical_extension_options\":[]},\"auth_info\":{\"signer_infos\":[{\"public_key\":{\"@type\":\"\\/cosmos.crypto.multisig.LegacyAminoPubKey\",\"threshold\":2,\"public_keys\":[{\"@type\":\"\\/cosmos.crypto.secp256k1.PubKey\",\"key\":\"AldOvgv8dU9ZZzuhGydQD5FYreLhfhoBgrDKi8ZSTbCQ\"},{\"@type\":\"\\/cosmos.crypto.secp256k1.PubKey\",\"key\":\"AxUMR\\/GKoycWplR+2otzaQZ9zhHRQWJFt3h1bPg1ltha\"},{\"@type\":\"\\/cosmos.crypto.secp256k1.PubKey\",\"key\":\"AlI9yVj2Aejow6bYl2nTRylfU+9LjQLEl3keq0sERx9+\"},{\"@type\":\"\\/cosmos.crypto.secp256k1.PubKey\",\"key\":\"A0UvHPcvCCaIoFY9Ygh0Pxq9SZTAWtduOyinit\\/8uo+Q\"},{\"@type\":\"\\/cosmos.crypto.secp256k1.PubKey\",\"key\":\"As7R9fDUnwsUVLDr1cxspp+cY9UfXfUf7i9\\/w+N0EzKA\"}]},\"mode_info\":{\"multi\":{\"bitarray\":{\"extra_bits_stored\":5,\"elems\":\"SA==\"},\"mode_infos\":[{\"single\":{\"mode\":\"SIGN_MODE_LEGACY_AMINO_JSON\"}},{\"single\":{\"mode\":\"SIGN_MODE_LEGACY_AMINO_JSON\"}}]}},\"sequence\":\"102\"}],\"fee\":{\"amount\":[],\"gas_limit\":\"10000000\",\"payer\":\"\",\"granter\":\"\"}},\"signatures\":[\"CkB\\/KKWTFntEWbg1A0vu7DCHffJ4x4db\\/EI8dIVzRFFW7iuZBzvq+jYBtrcTlVpEVfmCY3ggIMnWfbMbb1egIlYbCkAmDf6Eaj1NbyXY8JZZtYAX3Qj81ZuKZUBeLW1ZvH1XqAg9sl\\/sqpLMnsJzKfmqEXvhoMwu1YxcSzrY6CJfuYL6\"]}")
   251  )