diff --git a/app/abci.go b/app/abci.go index c8e878e776..fd4a45c78e 100644 --- a/app/abci.go +++ b/app/abci.go @@ -87,7 +87,7 @@ func (app *App) PreprocessTxs(txs abci.RequestPreprocessTxs) abci.ResponsePrepro } parentHash := sha256.Sum256(rawTx) - wrappedTx, err := coretypes.WrapChildTx(parentHash[:], rawProcessedTx) + wrappedTx, err := coretypes.WrapMalleatedTx(parentHash[:], rawProcessedTx) if err != nil { app.Logger().Error("failure to wrap child transaction with parent hash", "Error:", err) } diff --git a/app/child_tx_decoder.go b/app/child_tx_decoder.go index 7e02899855..4fc59cdd72 100644 --- a/app/child_tx_decoder.go +++ b/app/child_tx_decoder.go @@ -7,7 +7,7 @@ import ( func ChildTxDecoder(dec sdk.TxDecoder) sdk.TxDecoder { return func(txBytes []byte) (sdk.Tx, error) { - if _, childTx, has := coretypes.DecodeChildTx(txBytes); has { + if _, childTx, has := coretypes.UnwrapMalleatedTx(txBytes); has { return dec(childTx) } return dec(txBytes) diff --git a/go.mod b/go.mod index 08c3167cf0..1f5e73ec61 100644 --- a/go.mod +++ b/go.mod @@ -127,6 +127,6 @@ replace ( github.com/99designs/keyring => github.com/cosmos/keyring v1.1.7-0.20210622111912-ef00f8ac3d76 github.com/cosmos/cosmos-sdk => github.com/celestiaorg/cosmos-sdk v0.44.1-celestia github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 - github.com/tendermint/tendermint v0.34.13 => github.com/celestiaorg/celestia-core v0.34.14-celestia.0.20211121093520-199a1e4232ac + github.com/tendermint/tendermint v0.34.13 => github.com/celestiaorg/celestia-core v0.34.14-celestia.0.20220110174237-266919cced26 google.golang.org/grpc => google.golang.org/grpc v1.33.2 ) diff --git a/go.sum b/go.sum index c2c9a077dd..f8abc7c320 100644 --- a/go.sum +++ b/go.sum @@ -135,8 +135,8 @@ github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= -github.com/celestiaorg/celestia-core v0.34.14-celestia.0.20211121093520-199a1e4232ac h1:4JZt3mJxhM/i5djJVFBZZzgjYv0b1/wtYeTIX9yxey8= -github.com/celestiaorg/celestia-core v0.34.14-celestia.0.20211121093520-199a1e4232ac/go.mod h1:3n9kP3esPVYeAXMW/QSLALhMtraZInoTD5rcjteFpVQ= +github.com/celestiaorg/celestia-core v0.34.14-celestia.0.20220110174237-266919cced26 h1:rjRRkLQhqs/sVnYiDBRo3ndPaAKKKH0YuG+kl9lfD40= +github.com/celestiaorg/celestia-core v0.34.14-celestia.0.20220110174237-266919cced26/go.mod h1:3n9kP3esPVYeAXMW/QSLALhMtraZInoTD5rcjteFpVQ= github.com/celestiaorg/cosmos-sdk v0.44.1-celestia h1:WbNV1I4L7oudA38lZ+7ILnWElfDIbdZdNp3jHBvIXgU= github.com/celestiaorg/cosmos-sdk v0.44.1-celestia/go.mod h1:YVeOYCHyYj6Ig58sB9wxpu2hxzdI+apUtQ+hrp308kg= github.com/celestiaorg/go-leopard v0.1.0 h1:28z2EkvKJIez5J9CEaiiUEC+OxalRLtTGJJ1oScfE1g= diff --git a/testutil/network/network.go b/testutil/network/network.go new file mode 100644 index 0000000000..5f66662a4e --- /dev/null +++ b/testutil/network/network.go @@ -0,0 +1,137 @@ +package network + +import ( + "fmt" + "testing" + "time" + + "github.com/celestiaorg/celestia-app/app" + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/cosmos/cosmos-sdk/simapp" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + "github.com/cosmos/cosmos-sdk/testutil/network" + 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/stretchr/testify/require" + "github.com/tendermint/spm/cosmoscmd" + tmrand "github.com/tendermint/tendermint/libs/rand" + tmdb "github.com/tendermint/tm-db" +) + +func New(t *testing.T, config network.Config, genAccNames ...string) *network.Network { + kr := generateKeyring(t) + + // add genesis accounts + genAuthAccs := make([]authtypes.GenesisAccount, len(genAccNames)) + genBalances := make([]banktypes.Balance, len(genAccNames)) + mnemonics := make([]string, len(genAccNames)) + for i, name := range genAccNames { + a, b, mnm := newGenAccout(kr, name, 1000000000000) + genAuthAccs[i] = a + genBalances[i] = b + mnemonics[i] = mnm + } + + config, err := addGenAccounts(config, genAuthAccs, genBalances) + if err != nil { + panic(err) + } + + net := network.New(t, config) + + // add the keys to the keyring that is used by the integration test + for i, name := range genAccNames { + _, err := net.Validators[0].ClientCtx.Keyring.NewAccount(name, mnemonics[i], "", "", hd.Secp256k1) + require.NoError(t, err) + } + + return net +} + +// DefaultConfig will initialize config for the network with custom application, +// genesis and single validator. All other parameters are inherited from cosmos-sdk/testutil/network.DefaultConfig +func DefaultConfig() network.Config { + encoding := cosmoscmd.MakeEncodingConfig(app.ModuleBasics) + return network.Config{ + Codec: encoding.Marshaler, + TxConfig: encoding.TxConfig, + LegacyAmino: encoding.Amino, + InterfaceRegistry: encoding.InterfaceRegistry, + AccountRetriever: authtypes.AccountRetriever{}, + AppConstructor: func(val network.Validator) servertypes.Application { + return app.New( + val.Ctx.Logger, tmdb.NewMemDB(), nil, true, map[int64]bool{}, val.Ctx.Config.RootDir, 0, + encoding, + simapp.EmptyAppOptions{}, + baseapp.SetPruning(storetypes.NewPruningOptionsFromString(val.AppConfig.Pruning)), + baseapp.SetMinGasPrices(val.AppConfig.MinGasPrices), + ) + }, + GenesisState: app.ModuleBasics.DefaultGenesis(encoding.Marshaler), + TimeoutCommit: 2 * time.Second, + ChainID: "chain-" + tmrand.NewRand().Str(6), + NumValidators: 1, + BondDenom: sdk.DefaultBondDenom, + MinGasPrices: fmt.Sprintf("0.000006%s", sdk.DefaultBondDenom), + AccountTokens: sdk.TokensFromConsensusPower(1000, sdk.DefaultPowerReduction), + StakingTokens: sdk.TokensFromConsensusPower(500, sdk.DefaultPowerReduction), + BondedTokens: sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction), + PruningStrategy: storetypes.PruningOptionNothing, + CleanupDir: true, + SigningAlgo: string(hd.Secp256k1Type), + KeyringOptions: []keyring.Option{}, + } +} + +func addGenAccounts(cfg network.Config, genAccounts []authtypes.GenesisAccount, genBalances []banktypes.Balance) (network.Config, error) { + // set the accounts in the genesis state + var authGenState authtypes.GenesisState + cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[authtypes.ModuleName], &authGenState) + + accounts, err := authtypes.PackAccounts(genAccounts) + if err != nil { + return cfg, err + } + + authGenState.Accounts = append(authGenState.Accounts, accounts...) + cfg.GenesisState[authtypes.ModuleName] = cfg.Codec.MustMarshalJSON(&authGenState) + + // set the balances in the genesis state + var bankGenState banktypes.GenesisState + cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[banktypes.ModuleName], &bankGenState) + + bankGenState.Balances = append(bankGenState.Balances, genBalances...) + cfg.GenesisState[banktypes.ModuleName] = cfg.Codec.MustMarshalJSON(&bankGenState) + + return cfg, nil +} + +func newGenAccout(kr keyring.Keyring, name string, amount int64) (authtypes.GenesisAccount, banktypes.Balance, string) { + info, mnm, err := kr.NewMnemonic(name, keyring.English, "", "", hd.Secp256k1) + if err != nil { + panic(err) + } + + // create coin + balances := sdk.NewCoins( + sdk.NewCoin(fmt.Sprintf("%stoken", name), sdk.NewInt(amount)), + sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(amount)), + ) + + bal := banktypes.Balance{ + Address: info.GetAddress().String(), + Coins: balances.Sort(), + } + + return authtypes.NewBaseAccount(info.GetAddress(), info.GetPubKey(), 0, 0), bal, mnm +} + +func generateKeyring(t *testing.T) keyring.Keyring { + t.Helper() + kb := keyring.NewInMemory() + return kb +} diff --git a/x/payment/client/cli/wirepayformessage.go b/x/payment/client/cli/wirepayformessage.go index c9e668f6d3..179da13c87 100644 --- a/x/payment/client/cli/wirepayformessage.go +++ b/x/payment/client/cli/wirepayformessage.go @@ -12,6 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" ) func CmdWirePayForMessage() *cobra.Command { @@ -25,6 +26,13 @@ func CmdWirePayForMessage() *cobra.Command { return err } + // query for account number + fromAddress := clientCtx.GetFromAddress() + account, err := clientCtx.AccountRetriever.GetAccount(clientCtx, fromAddress) + if err != nil { + return err + } + // get the account name accName := clientCtx.GetFromName() if accName == "" { @@ -43,7 +51,7 @@ func CmdWirePayForMessage() *cobra.Command { return fmt.Errorf("failure to decode hex message: %w", err) } - // create the MsgPayForMessage + // create the MsgPayForMessage pfmMsg, err := types.NewWirePayForMessage(namespace, message, consts.MaxSquareSize) if err != nil { return err @@ -51,8 +59,36 @@ func CmdWirePayForMessage() *cobra.Command { signer := types.NewKeyringSigner(clientCtx.Keyring, accName, clientCtx.ChainID) + signer.SetAccountNumber(account.GetAccountNumber()) + signer.SetSequence(account.GetSequence()) + + // get and parse the gas limit for this tx + rawGasLimit, err := cmd.Flags().GetString(flags.FlagGas) + if err != nil { + return err + } + gasSetting, err := flags.ParseGasSetting(rawGasLimit) + if err != nil { + return err + } + + // get and parse the fees for this tx + fees, err := cmd.Flags().GetString(flags.FlagFees) + if err != nil { + return err + } + parsedFees, err := sdk.ParseCoinsNormalized(fees) + if err != nil { + return err + } + + // get the gas price and such and add it to the tx builder that is used to create the signed share commitments + builder := signer.NewTxBuilder() + builder.SetGasLimit(gasSetting.Gas) + builder.SetFeeAmount(parsedFees) + // sign the MsgPayForMessage's ShareCommitments - err = pfmMsg.SignShareCommitments(signer, signer.NewTxBuilder()) + err = pfmMsg.SignShareCommitments(signer, builder) if err != nil { return err } diff --git a/x/payment/client/testutil/integration_test.go b/x/payment/client/testutil/integration_test.go new file mode 100644 index 0000000000..984f8ac13a --- /dev/null +++ b/x/payment/client/testutil/integration_test.go @@ -0,0 +1,114 @@ +package testutil + +import ( + "fmt" + "testing" + + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/gogo/protobuf/proto" + "github.com/stretchr/testify/suite" + + "github.com/celestiaorg/celestia-app/testutil/network" + paycli "github.com/celestiaorg/celestia-app/x/payment/client/cli" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + cosmosnet "github.com/cosmos/cosmos-sdk/testutil/network" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// username is used to create a funded genesis account under this name +const username = "test" + +type IntegrationTestSuite struct { + suite.Suite + + cfg cosmosnet.Config + network *cosmosnet.Network + kr keyring.Keyring +} + +func NewIntegrationTestSuite(cfg cosmosnet.Config) *IntegrationTestSuite { + return &IntegrationTestSuite{cfg: cfg} +} + +func (s *IntegrationTestSuite) SetupSuite() { + s.T().Log("setting up integration test suite") + + if testing.Short() { + s.T().Skip("skipping test in unit-tests mode.") + } + + net := network.New(s.T(), s.cfg, username) + + s.network = net + s.kr = net.Validators[0].ClientCtx.Keyring + _, err := s.network.WaitForHeight(1) + s.Require().NoError(err) +} + +func (s *IntegrationTestSuite) TearDownSuite() { + s.T().Log("tearing down integration test suite") + s.network.Cleanup() +} + +func (s *IntegrationTestSuite) TestSubmitWirePayForMessage() { + require := s.Require() + val := s.network.Validators[0] + + // some hex namespace + hexNS := "0102030405060708" + // some hex message + hexMsg := "0204033704032c0b162109000908094d425837422c2116" + + testCases := []struct { + name string + args []string + expectErr bool + expectedCode uint32 + respType proto.Message + }{ + { + "valid transaction", + []string{ + hexNS, + hexMsg, + fmt.Sprintf("--from=%s", username), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, "2stake"), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + }, + false, 0, &sdk.TxResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := paycli.CmdWirePayForMessage() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + if tc.expectErr { + require.Error(err) + } else { + require.NoError(err, "test: %s\noutput: %s", tc.name, out.String()) + err = clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType) + require.NoError(err, out.String(), "test: %s, output\n:", tc.name, out.String()) + + txResp := tc.respType.(*sdk.TxResponse) + require.Equal(tc.expectedCode, txResp.Code, + "test: %s, output\n:", tc.name, out.String()) + + events := txResp.Logs[0].GetEvents() + for i := 0; i < len(events); i++ { + s.Equal("/payment.MsgPayForMessage", events[i].GetAttributes()[0].Value) + } + } + }) + } +} + +func TestIntegrationTestSuite(t *testing.T) { + suite.Run(t, NewIntegrationTestSuite(network.DefaultConfig())) +} diff --git a/x/payment/types/builder_test.go b/x/payment/types/builder_test.go index aef5b24a32..097fb69f91 100644 --- a/x/payment/types/builder_test.go +++ b/x/payment/types/builder_test.go @@ -36,7 +36,7 @@ func TestBuildPayForMessage(t *testing.T) { rawTx, err := makeEncodingConfig().TxConfig.TxEncoder()(signedTx) require.NoError(t, err) - _, _, isChild := coretypes.DecodeChildTx(rawTx) + _, _, isChild := coretypes.UnwrapMalleatedTx(rawTx) require.False(t, isChild) sigs, err := signedTx.GetSignaturesV2()