diff --git a/go.mod b/go.mod index 9674881..605a76c 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/gorilla/mux v1.8.1 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/huandu/skiplist v1.2.0 - github.com/skip-mev/chaintestutil v0.0.0-20231218180533-7f3da3ddb3f4 + github.com/skip-mev/chaintestutil v0.0.0-20231221145345-f208ee3b1383 github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.18.2 @@ -35,7 +35,7 @@ require ( golang.org/x/tools v0.16.1 golang.org/x/vuln v1.0.1 google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 - google.golang.org/grpc v1.59.0 + google.golang.org/grpc v1.60.1 google.golang.org/protobuf v1.31.0 mvdan.cc/gofumpt v0.5.0 ) @@ -309,7 +309,7 @@ require ( go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.10.0 // indirect go.uber.org/zap v1.24.0 // indirect - golang.org/x/crypto v0.16.0 // indirect + golang.org/x/crypto v0.17.0 // indirect golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect golang.org/x/exp/typeparams v0.0.0-20230307190834-24139beb5833 // indirect golang.org/x/mod v0.14.0 // indirect @@ -322,7 +322,7 @@ require ( golang.org/x/time v0.5.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.153.0 // indirect - google.golang.org/appengine v1.6.7 // indirect + google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index b42ecbf..2b4eb23 100644 --- a/go.sum +++ b/go.sum @@ -1219,8 +1219,8 @@ github.com/sivchari/nosnakecase v1.7.0 h1:7QkpWIRMe8x25gckkFd2A5Pi6Ymo0qgr4JrhGt github.com/sivchari/nosnakecase v1.7.0/go.mod h1:CwDzrzPea40/GB6uynrNLiorAlgFRvRbFSgJx2Gs+QY= github.com/sivchari/tenv v1.7.1 h1:PSpuD4bu6fSmtWMxSGWcvqUUgIn7k3yOJhOIzVWn8Ak= github.com/sivchari/tenv v1.7.1/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg= -github.com/skip-mev/chaintestutil v0.0.0-20231218180533-7f3da3ddb3f4 h1:uX3mI+MRH4wPclt4MS2BAGKXxxOoKfxy384zbXb6MQc= -github.com/skip-mev/chaintestutil v0.0.0-20231218180533-7f3da3ddb3f4/go.mod h1:o3naFS52DumeJLR6h+0YoMV09YvxOALaou9WZuSJOIg= +github.com/skip-mev/chaintestutil v0.0.0-20231221145345-f208ee3b1383 h1:tjmoJDbTLTolmL/pjvNbICb/I9as5hQwxL1FqRVUwY4= +github.com/skip-mev/chaintestutil v0.0.0-20231221145345-f208ee3b1383/go.mod h1:FvYgT9wJSLvtBkwWp4mHo+A5/r9OkvHXJJh9u8RhGWk= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -1401,8 +1401,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1694,6 +1694,7 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= @@ -1855,8 +1856,9 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -2010,8 +2012,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= +google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= diff --git a/tests/integration/network/auction_test.go b/tests/integration/network/auction_test.go new file mode 100644 index 0000000..40c05b9 --- /dev/null +++ b/tests/integration/network/auction_test.go @@ -0,0 +1,251 @@ +package integration_test + +import ( + "context" + + "cosmossdk.io/math" + cmttypes "github.com/cometbft/cometbft/types" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/skip-mev/chaintestutil/account" + "github.com/skip-mev/chaintestutil/network" + "github.com/stretchr/testify/require" + + auctiontypes "github.com/skip-mev/block-sdk/x/auction/types" +) + +func (s *NetworkTestSuite) TestAuctionWithValidBids() { + cc, closeFn, err := s.NetworkSuite.GetGRPC() + require.NoError(s.T(), err) + defer closeFn() + + cmtClient, err := s.NetworkSuite.GetCometClient() + require.NoError(s.T(), err) + + params, err := s.QueryAuctionParams() + require.NoError(s.T(), err) + + fee := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000)) + + bankClient := banktypes.NewQueryClient(cc) + resp, err := bankClient.AllBalances(context.Background(), &banktypes.QueryAllBalancesRequest{ + Address: params.EscrowAddressString, + Pagination: nil, + ResolveDenom: false, + }) + require.NoError(s.T(), err) + beginEscrowBalances := resp.Balances + beginEscrowBalance := beginEscrowBalances.AmountOf(params.Params.ReserveFee.Denom) + + // Create and fund the bidders + bidder1 := account.NewAccount() + bidder2 := account.NewAccount() + receiver := account.NewAccount() + + // Fund bidder1 + bz, err := s.NetworkSuite.CreateTxBytes(context.Background(), + network.TxGenInfo{ + Account: *s.Accounts[0], + GasLimit: 10000000, + TimeoutHeight: 100000000, + Fee: fee, + }, + banktypes.NewMsgSend( + s.Accounts[0].Address(), + bidder1.Address(), + sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 10000000000))), + ) + require.NoError(s.T(), err) + res, err := s.NetworkSuite.BroadcastTxCommit( + context.Background(), + bz, + ) + require.NoError(s.T(), err) + require.Equal(s.T(), uint32(0), res.CheckTx.Code) + require.Equal(s.T(), uint32(0), res.TxResult.Code) + + // Fund bidder2 + bz, err = s.NetworkSuite.CreateTxBytes(context.Background(), + network.TxGenInfo{ + Account: *s.Accounts[0], + GasLimit: 10000000, + TimeoutHeight: 100000000, + Fee: fee, + }, + banktypes.NewMsgSend( + s.Accounts[0].Address(), + bidder2.Address(), + sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 10000000000))), + ) + require.NoError(s.T(), err) + res, err = s.NetworkSuite.BroadcastTxCommit( + context.Background(), + bz, + ) + require.NoError(s.T(), err) + require.Equal(s.T(), uint32(0), res.CheckTx.Code) + require.Equal(s.T(), uint32(0), res.TxResult.Code) + + s.Run("two valid bids--balance/fee verification", func() { + // Store the receiver's initial balance + beginReceiverBalances, err := s.NetworkSuite.Balances(*receiver) + require.NoError(s.T(), err) + beginReceiverBalance := beginReceiverBalances.AmountOf(params.Params.ReserveFee.Denom) + + bid1Seq, _, err := getAccount(context.Background(), authtypes.NewQueryClient(cc), *bidder1) + s.Require().NoError(err) + bid2Seq, _, err := getAccount(context.Background(), authtypes.NewQueryClient(cc), *bidder2) + s.Require().NoError(err) + + // Get current height + resp, err := cmtClient.Status(context.Background()) + s.Require().NoError(err) + bidHeight := uint64(resp.SyncInfo.LatestBlockHeight + 1) + + // Bidder1's send tx they want included + send1Tx, err := s.NetworkSuite.CreateTxBytes( + context.Background(), + network.TxGenInfo{ + Account: *bidder1, + GasLimit: 1000000, + TimeoutHeight: bidHeight, + Fee: fee, + Sequence: bid1Seq + 1, + OverrideSequence: true, + }, + banktypes.NewMsgSend(bidder1.Address(), receiver.Address(), sdk.NewCoins(sdk.NewCoin(params.Params.ReserveFee.Denom, math.NewInt(1)))), + ) + require.NoError(s.T(), err) + + // Bidder1's Bid Tx + bid1Tx, err := s.NetworkSuite.CreateTxBytes( + context.Background(), + network.TxGenInfo{ + Account: *bidder1, + GasLimit: 1000009, + TimeoutHeight: bidHeight, + Fee: fee, + Sequence: bid1Seq, + OverrideSequence: true, + }, + auctiontypes.NewMsgAuctionBid( + bidder1.Address(), + params.Params.ReserveFee, + [][]byte{send1Tx}, + ), + ) + require.NoError(s.T(), err) + + // Bidder2's send tx they want included + send2Tx, err := s.NetworkSuite.CreateTxBytes( + context.Background(), + network.TxGenInfo{ + Account: *bidder2, + GasLimit: 1000000, + TimeoutHeight: bidHeight, + Fee: fee, + Sequence: bid2Seq + 1, + OverrideSequence: true, + }, + banktypes.NewMsgSend(bidder2.Address(), receiver.Address(), sdk.NewCoins(sdk.NewCoin(params.Params.ReserveFee.Denom, math.NewInt(2)))), + ) + require.NoError(s.T(), err) + + // Bidder2's Bid Tx + bid2Tx, err := s.NetworkSuite.CreateTxBytes( + context.Background(), + network.TxGenInfo{ + Account: *bidder2, + GasLimit: 1000000, + TimeoutHeight: bidHeight, + Fee: fee, + Sequence: bid2Seq, + OverrideSequence: true, + }, + auctiontypes.NewMsgAuctionBid( + bidder2.Address(), + params.Params.ReserveFee.Add(params.Params.MinBidIncrement), + [][]byte{send2Tx}, + ), + ) + require.NoError(s.T(), err) + + // Broadcast the bids + for _, tx := range [][]byte{bid1Tx, bid2Tx} { + result, err := s.NetworkSuite.BroadcastTx(context.Background(), tx, network.BroadcastModeSync) + require.NoError(s.T(), err) + require.Equal(s.T(), uint32(0), result.Code) + } + require.NoError(s.T(), waitForTxCommit(context.Background(), cmtClient, cmttypes.Tx(bid2Tx).Hash())) + + // Validate that the receiver got the funds + endReceiverBalances, err := s.NetworkSuite.Balances(*receiver) + require.NoError(s.T(), err) + endReceiverBalance := endReceiverBalances.AmountOf(params.Params.ReserveFee.Denom) + require.Equal(s.T(), beginReceiverBalance.Add(math.NewInt(2)), endReceiverBalance) + + // Validate that the escrow got the funds + // endEscrowBalances, err := s.NetworkSuite.Balances(*s.AuctionEscrow) + balResp, err := bankClient.AllBalances(context.Background(), &banktypes.QueryAllBalancesRequest{ + Address: params.EscrowAddressString, + Pagination: nil, + ResolveDenom: false, + }) + require.NoError(s.T(), err) + endEscrowBalances := balResp.Balances + endEscrowBalance := endEscrowBalances.AmountOf(params.Params.ReserveFee.Denom) + require.Equal(s.T(), beginEscrowBalance.Add(math.NewInt(2)), endEscrowBalance) + }) + s.Run("bid w/ too many txs", func() { + bid1Seq, _, err := getAccount(context.Background(), authtypes.NewQueryClient(cc), *bidder1) + s.Require().NoError(err) + + // Get current height + resp, err := cmtClient.Status(context.Background()) + s.Require().NoError(err) + bidHeight := uint64(resp.SyncInfo.LatestBlockHeight + 1) + + bundle := make([][]byte, 0, s.AuctionState.Params.MaxBundleSize+1) + for i := 0; i <= int(s.AuctionState.Params.MaxBundleSize); i++ { + // Bidder1's send tx they want included + sendTx, err := s.NetworkSuite.CreateTxBytes( + context.Background(), + network.TxGenInfo{ + Account: *bidder1, + GasLimit: 1000000, + TimeoutHeight: bidHeight, + Fee: fee, + Sequence: bid1Seq + 1, + OverrideSequence: true, + }, + banktypes.NewMsgSend(bidder1.Address(), receiver.Address(), sdk.NewCoins(sdk.NewCoin(params.Params.ReserveFee.Denom, math.NewInt(1)))), + ) + require.NoError(s.T(), err) + bundle = append(bundle, sendTx) + } + + // Bidder1's Bid Tx + bid1Tx, err := s.NetworkSuite.CreateTxBytes( + context.Background(), + network.TxGenInfo{ + Account: *bidder1, + GasLimit: 1000009, + TimeoutHeight: bidHeight, + Fee: fee, + Sequence: bid1Seq, + OverrideSequence: true, + }, + auctiontypes.NewMsgAuctionBid( + bidder1.Address(), + params.Params.ReserveFee, + bundle, + ), + ) + require.NoError(s.T(), err) + + result, err := s.NetworkSuite.BroadcastTx(context.Background(), bid1Tx, network.BroadcastModeSync) + require.NoError(s.T(), err) + require.Equal(s.T(), uint32(1), result.Code) + }) +}