diff --git a/.github/workflows/md-link-checker.yml b/.github/workflows/md-link-checker.yml index 218dd6b25180..a9ed26810b23 100644 --- a/.github/workflows/md-link-checker.yml +++ b/.github/workflows/md-link-checker.yml @@ -20,7 +20,7 @@ jobs: if: ${{ failure() }} steps: - name: Notify Slack on failure - uses: rtCamp/action-slack-notify@v2.3.1 + uses: rtCamp/action-slack-notify@v2.3.2 env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_CHANNEL: sdk-sims diff --git a/.github/workflows/pr-reminder.yml b/.github/workflows/pr-reminder.yml index de174f5d77b5..ea03bac8d5d4 100644 --- a/.github/workflows/pr-reminder.yml +++ b/.github/workflows/pr-reminder.yml @@ -38,7 +38,7 @@ jobs: - name: Send Slack Reminder if: steps.pr-list.outputs.result != '' - uses: rtCamp/action-slack-notify@v2.3.1 + uses: rtCamp/action-slack-notify@v2.3.2 env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_CHANNEL: pr-github diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 13ca5a1db4d7..098d70ba8d72 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -37,7 +37,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Notify Slack on success - uses: rtCamp/action-slack-notify@v2.3.1 + uses: rtCamp/action-slack-notify@v2.3.2 env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_CHANNEL: cosmos-tech diff --git a/.github/workflows/sims-047.yml b/.github/workflows/sims-047.yml index 90b03b492146..3da50f38defa 100644 --- a/.github/workflows/sims-047.yml +++ b/.github/workflows/sims-047.yml @@ -115,7 +115,7 @@ jobs: - name: Notify Slack on success if: ${{ steps.last_status.outputs.last_status == 'failure' }} - uses: rtCamp/action-slack-notify@v2.3.1 + uses: rtCamp/action-slack-notify@v2.3.2 env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_CHANNEL: sdk-sims @@ -134,7 +134,7 @@ jobs: if: ${{ failure() }} steps: - name: Notify Slack on failure - uses: rtCamp/action-slack-notify@v2.3.1 + uses: rtCamp/action-slack-notify@v2.3.2 env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_CHANNEL: sdk-sims diff --git a/.github/workflows/sims-050.yml b/.github/workflows/sims-050.yml index eabc8faee224..6896a7d41b13 100644 --- a/.github/workflows/sims-050.yml +++ b/.github/workflows/sims-050.yml @@ -115,7 +115,7 @@ jobs: - name: Notify Slack on success if: ${{ steps.last_status.outputs.last_status == 'failure' }} - uses: rtCamp/action-slack-notify@v2.3.1 + uses: rtCamp/action-slack-notify@v2.3.2 env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_CHANNEL: sdk-sims @@ -134,7 +134,7 @@ jobs: if: ${{ failure() }} steps: - name: Notify Slack on failure - uses: rtCamp/action-slack-notify@v2.3.1 + uses: rtCamp/action-slack-notify@v2.3.2 env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_CHANNEL: sdk-sims diff --git a/.github/workflows/sims-052.yml b/.github/workflows/sims-052.yml index dacb30a887d1..2d2ff553ee2a 100644 --- a/.github/workflows/sims-052.yml +++ b/.github/workflows/sims-052.yml @@ -111,7 +111,7 @@ jobs: - name: Notify Slack on success if: ${{ steps.last_status.outputs.last_status == 'failure' }} - uses: rtCamp/action-slack-notify@v2.3.1 + uses: rtCamp/action-slack-notify@v2.3.2 env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_CHANNEL: sdk-sims @@ -135,7 +135,7 @@ jobs: if: ${{ failure() }} steps: - name: Notify Slack on failure - uses: rtCamp/action-slack-notify@v2.3.1 + uses: rtCamp/action-slack-notify@v2.3.2 env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_CHANNEL: sdk-sims diff --git a/.github/workflows/sims-nightly.yml b/.github/workflows/sims-nightly.yml index f41d240c88fb..9879c20b2744 100644 --- a/.github/workflows/sims-nightly.yml +++ b/.github/workflows/sims-nightly.yml @@ -44,7 +44,7 @@ jobs: - name: Notify Slack on success if: ${{ steps.last_status.outputs.last_status == 'failure' }} - uses: rtCamp/action-slack-notify@v2.3.1 + uses: rtCamp/action-slack-notify@v2.3.2 env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_CHANNEL: sdk-sims @@ -62,7 +62,7 @@ jobs: if: ${{ failure() }} steps: - name: Notify Slack on failure - uses: rtCamp/action-slack-notify@v2.3.1 + uses: rtCamp/action-slack-notify@v2.3.2 env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_CHANNEL: sdk-sims diff --git a/.github/workflows/sims.yml b/.github/workflows/sims.yml index ed166028b428..0fcba8e5cf7d 100644 --- a/.github/workflows/sims.yml +++ b/.github/workflows/sims.yml @@ -102,7 +102,7 @@ jobs: - name: Notify Slack on success if: ${{ steps.last_status.outputs.last_status == 'failure' }} - uses: rtCamp/action-slack-notify@v2.3.1 + uses: rtCamp/action-slack-notify@v2.3.2 env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_CHANNEL: sdk-sims @@ -126,7 +126,7 @@ jobs: if: ${{ failure() }} steps: - name: Notify Slack on failure - uses: rtCamp/action-slack-notify@v2.3.1 + uses: rtCamp/action-slack-notify@v2.3.2 env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_CHANNEL: sdk-sims diff --git a/.github/workflows/software-compat-v052.yml b/.github/workflows/software-compat-v052.yml index e4f86589ca71..999f3a97a94c 100644 --- a/.github/workflows/software-compat-v052.yml +++ b/.github/workflows/software-compat-v052.yml @@ -46,7 +46,7 @@ jobs: - name: Notify Slack on success if: ${{ steps.last_status.outputs.last_status == 'failure' }} - uses: rtCamp/action-slack-notify@v2.3.1 + uses: rtCamp/action-slack-notify@v2.3.2 env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_CHANNEL: sdk-sims @@ -64,7 +64,7 @@ jobs: if: ${{ failure() }} steps: - name: Notify Slack on failure - uses: rtCamp/action-slack-notify@v2.3.1 + uses: rtCamp/action-slack-notify@v2.3.2 env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_CHANNEL: sdk-sims diff --git a/.golangci.yml b/.golangci.yml index 9fa8a3398ac3..29c3e352b6ab 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -119,3 +119,5 @@ linters-settings: - regexpMust - appendAssign - ifElseChain + unused: + local-variables-are-used: false \ No newline at end of file diff --git a/api/cosmos/accounts/defaults/lockup/v1/tx.pulsar.go b/api/cosmos/accounts/defaults/lockup/v1/tx.pulsar.go index 3283320c925b..6c690258c20f 100644 --- a/api/cosmos/accounts/defaults/lockup/v1/tx.pulsar.go +++ b/api/cosmos/accounts/defaults/lockup/v1/tx.pulsar.go @@ -5851,8 +5851,7 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// MsgInitLockupAccount defines a message that enables creating a lockup -// account. +// MsgInitLockupAccount defines a message that enables creating a lockup account. type MsgInitLockupAccount struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -5860,9 +5859,9 @@ type MsgInitLockupAccount struct { // owner of the vesting account Owner string `protobuf:"bytes,1,opt,name=owner,proto3" json:"owner,omitempty"` - // end of lockup + // end_time is end of lockup EndTime *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=end_time,json=endTime,proto3" json:"end_time,omitempty"` - // start of lockup + // start_time is start of lockup StartTime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"` } diff --git a/api/cosmos/accounts/defaults/multisig/v1/multisig.pulsar.go b/api/cosmos/accounts/defaults/multisig/v1/multisig.pulsar.go index f864bb69f9a9..3f5067238735 100644 --- a/api/cosmos/accounts/defaults/multisig/v1/multisig.pulsar.go +++ b/api/cosmos/accounts/defaults/multisig/v1/multisig.pulsar.go @@ -8872,8 +8872,10 @@ type MsgInit struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // members are the members of the multisig account. Members []*Member `protobuf:"bytes,1,rep,name=members,proto3" json:"members,omitempty"` - Config *Config `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"` + // config is the configuration of the multisig account. + Config *Config `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"` } func (x *MsgInit) Reset() { @@ -9275,8 +9277,10 @@ type Config struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // threshold is the minimum weight required for a proposal to pass. Threshold int64 `protobuf:"varint,1,opt,name=threshold,proto3" json:"threshold,omitempty"` - Quorum int64 `protobuf:"varint,2,opt,name=quorum,proto3" json:"quorum,omitempty"` + // quorum is the minimum number of members that need to vote for a proposal to pass. + Quorum int64 `protobuf:"varint,2,opt,name=quorum,proto3" json:"quorum,omitempty"` // voting_period is the duration in seconds for the voting period. VotingPeriod int64 `protobuf:"varint,3,opt,name=voting_period,json=votingPeriod,proto3" json:"voting_period,omitempty"` // revote defines if members can change their vote. @@ -9346,12 +9350,16 @@ type Proposal struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` - Summary string `protobuf:"bytes,2,opt,name=summary,proto3" json:"summary,omitempty"` + // title is the title of the proposal. + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + // summary is the summary of the proposal. + Summary string `protobuf:"bytes,2,opt,name=summary,proto3" json:"summary,omitempty"` + // messages are the messages that will be executed Messages []*anypb.Any `protobuf:"bytes,3,rep,name=messages,proto3" json:"messages,omitempty"` // voting_period_end will be set by the account when the proposal is created. - VotingPeriodEnd int64 `protobuf:"varint,4,opt,name=voting_period_end,json=votingPeriodEnd,proto3" json:"voting_period_end,omitempty"` - Status ProposalStatus `protobuf:"varint,5,opt,name=status,proto3,enum=cosmos.accounts.defaults.multisig.v1.ProposalStatus" json:"status,omitempty"` + VotingPeriodEnd int64 `protobuf:"varint,4,opt,name=voting_period_end,json=votingPeriodEnd,proto3" json:"voting_period_end,omitempty"` + // status is the current status of the proposal. + Status ProposalStatus `protobuf:"varint,5,opt,name=status,proto3,enum=cosmos.accounts.defaults.multisig.v1.ProposalStatus" json:"status,omitempty"` } func (x *Proposal) Reset() { @@ -9506,8 +9514,10 @@ type QueryConfigResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // members are the current members of the account. Members []*Member `protobuf:"bytes,1,rep,name=members,proto3" json:"members,omitempty"` - Config *Config `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"` + // config is the current config of the account. + Config *Config `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"` } func (x *QueryConfigResponse) Reset() { diff --git a/client/cmd.go b/client/cmd.go index 7ea1f49e0942..29a0352f7dbc 100644 --- a/client/cmd.go +++ b/client/cmd.go @@ -345,7 +345,7 @@ func GetClientQueryContext(cmd *cobra.Command) (Context, error) { // - client.Context field pre-populated & flag not set: uses pre-populated value // - client.Context field pre-populated & flag set: uses set flag value func GetClientTxContext(cmd *cobra.Command) (Context, error) { - ctx := GetClientContextFromCmd(cmd) + ctx := GetClientContextFromCmd(cmd).WithOutput(cmd.OutOrStdout()) return readTxCommandFlags(ctx, cmd.Flags()) } diff --git a/client/cmd_test.go b/client/cmd_test.go index 31c7bf390b01..ae57b2f4bac6 100644 --- a/client/cmd_test.go +++ b/client/cmd_test.go @@ -1,6 +1,7 @@ package client_test import ( + "bytes" "context" "fmt" "testing" @@ -137,3 +138,28 @@ func TestSetCmdClientContextHandler(t *testing.T) { }) } } + +func TestContext_usesCobraCommandOutput(t *testing.T) { + var initCtx client.Context + + cmd := &cobra.Command{ + PreRunE: func(cmd *cobra.Command, args []string) error { + return client.SetCmdClientContextHandler(initCtx, cmd) + }, + RunE: func(cmd *cobra.Command, _ []string) error { + cctx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + return cctx.PrintString("hello") + }, + } + + var outBuf bytes.Buffer + cmd.SetOutput(&outBuf) + + require.NoError(t, cmd.Execute()) + + require.Equal(t, "hello", outBuf.String()) +} diff --git a/client/v2/go.mod b/client/v2/go.mod index a9d75f6d8a38..6a895d059fb8 100644 --- a/client/v2/go.mod +++ b/client/v2/go.mod @@ -8,7 +8,7 @@ require ( cosmossdk.io/depinject v1.0.0 cosmossdk.io/x/bank v0.0.0-20240226161501-23359a0b6d91 cosmossdk.io/x/gov v0.0.0-20231113122742-912390d5fc4a - cosmossdk.io/x/tx v0.13.3 + cosmossdk.io/x/tx v1.0.0-alpha.1 github.com/cosmos/cosmos-proto v1.0.0-beta.5 github.com/cosmos/cosmos-sdk v0.53.0 github.com/spf13/cobra v1.8.1 diff --git a/go.mod b/go.mod index f6286b7dc3e4..7c3cc9d9bf3d 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( cosmossdk.io/store v1.1.1-0.20240418092142-896cdf1971bc cosmossdk.io/x/bank v0.0.0-20240226161501-23359a0b6d91 cosmossdk.io/x/staking v0.0.0-00010101000000-000000000000 - cosmossdk.io/x/tx v0.13.3 + cosmossdk.io/x/tx v1.0.0-alpha.1 github.com/99designs/keyring v1.2.2 github.com/bgentry/speakeasy v0.2.0 github.com/cometbft/cometbft v1.0.0-rc1.0.20240908111210-ab0be101882f diff --git a/log/CHANGELOG.md b/log/CHANGELOG.md index c9f2475683e9..72b4e6d1adf7 100644 --- a/log/CHANGELOG.md +++ b/log/CHANGELOG.md @@ -22,6 +22,10 @@ Each entry must include the Github issue reference in the following format: ## [Unreleased] +### Improvements + +* [#22233](https://github.com/cosmos/cosmos-sdk/pull/22233) Use sonic json library for faster json handling + ## [v1.4.1](https://github.com/cosmos/cosmos-sdk/releases/tag/log/v1.4.1) - 2024-08-16 * [#21326](https://github.com/cosmos/cosmos-sdk/pull/21326) Avoid context key collision. diff --git a/log/go.mod b/log/go.mod index 8ad68695218b..292e5d973e6f 100644 --- a/log/go.mod +++ b/log/go.mod @@ -3,14 +3,19 @@ module cosmossdk.io/log go 1.20 require ( + github.com/bytedance/sonic v1.12.3 github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.33.0 - gotest.tools/v3 v3.5.1 ) require ( - github.com/google/go-cmp v0.6.0 // indirect + github.com/bytedance/sonic/loader v0.2.0 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/klauspost/cpuid/v2 v2.0.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect golang.org/x/sys v0.22.0 // indirect ) diff --git a/log/go.sum b/log/go.sum index 12553f8dc11e..b6a141763c97 100644 --- a/log/go.sum +++ b/log/go.sum @@ -1,7 +1,20 @@ +github.com/bytedance/sonic v1.12.3 h1:W2MGa7RCU1QTeYRTPE3+88mVC0yXmsRQRChiyVocVjU= +github.com/bytedance/sonic v1.12.3/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= +github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -10,13 +23,30 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= -gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= diff --git a/log/level_test.go b/log/level_test.go index e893ca424274..9b7e2a5ac103 100644 --- a/log/level_test.go +++ b/log/level_test.go @@ -3,46 +3,88 @@ package log_test import ( "testing" - "gotest.tools/v3/assert" - "cosmossdk.io/log" ) func TestParseLogLevel(t *testing.T) { _, err := log.ParseLogLevel("") - assert.Error(t, err, "empty log level") + if err == nil { + t.Errorf("expected error for empty log level, got nil") + } level := "consensus:foo,mempool:debug,*:error" _, err = log.ParseLogLevel(level) - assert.Error(t, err, "invalid log level foo in log level list [consensus:foo mempool:debug *:error]") + if err == nil { + t.Errorf("expected error for invalid log level foo in log level list [consensus:foo mempool:debug *:error], got nil") + } level = "consensus:debug,mempool:debug,*:error" filter, err := log.ParseLogLevel(level) - assert.NilError(t, err) - assert.Assert(t, filter != nil) - - assert.Assert(t, !filter("consensus", "debug")) - assert.Assert(t, !filter("consensus", "info")) - assert.Assert(t, !filter("consensus", "error")) - assert.Assert(t, !filter("mempool", "debug")) - assert.Assert(t, !filter("mempool", "info")) - assert.Assert(t, !filter("mempool", "error")) - assert.Assert(t, !filter("state", "error")) - assert.Assert(t, !filter("server", "panic")) - - assert.Assert(t, filter("server", "debug")) - assert.Assert(t, filter("state", "debug")) - assert.Assert(t, filter("state", "info")) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if filter == nil { + t.Fatalf("expected non-nil filter, got nil") + } + + if filter("consensus", "debug") { + t.Errorf("expected filter to return false for consensus:debug") + } + if filter("consensus", "info") { + t.Errorf("expected filter to return false for consensus:info") + } + if filter("consensus", "error") { + t.Errorf("expected filter to return false for consensus:error") + } + if filter("mempool", "debug") { + t.Errorf("expected filter to return false for mempool:debug") + } + if filter("mempool", "info") { + t.Errorf("expected filter to return false for mempool:info") + } + if filter("mempool", "error") { + t.Errorf("expected filter to return false for mempool:error") + } + if filter("state", "error") { + t.Errorf("expected filter to return false for state:error") + } + if filter("server", "panic") { + t.Errorf("expected filter to return false for server:panic") + } + + if !filter("server", "debug") { + t.Errorf("expected filter to return true for server:debug") + } + if !filter("state", "debug") { + t.Errorf("expected filter to return true for state:debug") + } + if !filter("state", "info") { + t.Errorf("expected filter to return true for state:info") + } level = "error" filter, err = log.ParseLogLevel(level) - assert.NilError(t, err) - assert.Assert(t, filter != nil) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if filter == nil { + t.Fatalf("expected non-nil filter, got nil") + } - assert.Assert(t, !filter("state", "error")) - assert.Assert(t, !filter("consensus", "error")) + if filter("state", "error") { + t.Errorf("expected filter to return false for state:error") + } + if filter("consensus", "error") { + t.Errorf("expected filter to return false for consensus:error") + } - assert.Assert(t, filter("consensus", "debug")) - assert.Assert(t, filter("consensus", "info")) - assert.Assert(t, filter("state", "debug")) + if !filter("consensus", "debug") { + t.Errorf("expected filter to return true for consensus:debug") + } + if !filter("consensus", "info") { + t.Errorf("expected filter to return true for consensus:info") + } + if !filter("state", "debug") { + t.Errorf("expected filter to return true for state:debug") + } } diff --git a/log/logger.go b/log/logger.go index 8a27538e80ff..ef9928029edb 100644 --- a/log/logger.go +++ b/log/logger.go @@ -6,6 +6,7 @@ import ( "fmt" "io" + "github.com/bytedance/sonic" "github.com/pkg/errors" "github.com/rs/zerolog" "github.com/rs/zerolog/pkgerrors" @@ -15,13 +16,13 @@ func init() { zerolog.InterfaceMarshalFunc = func(i any) ([]byte, error) { switch v := i.(type) { case json.Marshaler: - return json.Marshal(i) + return sonic.Marshal(i) case encoding.TextMarshaler: - return json.Marshal(i) + return sonic.Marshal(i) case fmt.Stringer: - return json.Marshal(v.String()) + return sonic.Marshal(v.String()) default: - return json.Marshal(i) + return sonic.Marshal(i) } } } @@ -112,6 +113,7 @@ func NewLogger(dst io.Writer, options ...Option) Logger { } logger := zerolog.New(output) + if logCfg.StackTrace { zerolog.ErrorStackMarshaler = func(err error) interface{} { return pkgerrors.MarshalStack(errors.WithStack(err)) diff --git a/log/logger_test.go b/log/logger_test.go index 534183e524e9..752026a25bd8 100644 --- a/log/logger_test.go +++ b/log/logger_test.go @@ -7,27 +7,10 @@ import ( "testing" "github.com/rs/zerolog" - "gotest.tools/v3/assert" "cosmossdk.io/log" ) -func TestLoggerOptionStackTrace(t *testing.T) { - buf := new(bytes.Buffer) - logger := log.NewLogger(buf, log.TraceOption(true), log.ColorOption(false)) - logger.Error("this log should be displayed", "error", inner()) - if strings.Count(buf.String(), "logger_test.go") != 1 { - t.Fatalf("stack trace not found, got: %s", buf.String()) - } - buf.Reset() - - logger = log.NewLogger(buf, log.TraceOption(false), log.ColorOption(false)) - logger.Error("this log should be displayed", "error", inner()) - if strings.Count(buf.String(), "logger_test.go") > 0 { - t.Fatalf("stack trace found, got: %s", buf.String()) - } -} - func inner() error { return errors.New("seems we have an error here") } @@ -46,11 +29,33 @@ func TestLoggerOptionHooks(t *testing.T) { ) logger := log.NewLogger(buf, log.HooksOption(mockHook1, mockHook2), log.ColorOption(false)) logger.Info("hello world") - assert.Assert(t, strings.Contains(buf.String(), "mock_message1=true")) - assert.Assert(t, strings.Contains(buf.String(), "mock_message2=true")) + if !strings.Contains(buf.String(), "mock_message1=true") { + t.Fatalf("expected mock_message1=true, got: %s", buf.String()) + } + if !strings.Contains(buf.String(), "mock_message2=true") { + t.Fatalf("expected mock_message2=true, got: %s", buf.String()) + } buf.Reset() logger = log.NewLogger(buf, log.HooksOption(), log.ColorOption(false)) logger.Info("hello world") - assert.Assert(t, strings.Contains(buf.String(), "hello world")) + if !strings.Contains(buf.String(), "hello world") { + t.Fatalf("expected hello world, got: %s", buf.String()) + } +} + +func TestLoggerOptionStackTrace(t *testing.T) { + buf := new(bytes.Buffer) + logger := log.NewLogger(buf, log.TraceOption(true), log.ColorOption(false)) + logger.Error("this log should be displayed", "error", inner()) + if strings.Count(buf.String(), "logger_test.go") != 1 { + t.Fatalf("stack trace not found, got: %s", buf.String()) + } + buf.Reset() + + logger = log.NewLogger(buf, log.TraceOption(false), log.ColorOption(false)) + logger.Error("this log should be displayed", "error", inner()) + if strings.Count(buf.String(), "logger_test.go") > 0 { + t.Fatalf("stack trace found, got: %s", buf.String()) + } } diff --git a/log/writer.go b/log/writer.go index 9c6befef71fe..d6f0dc2381cb 100644 --- a/log/writer.go +++ b/log/writer.go @@ -1,9 +1,10 @@ package log import ( - "encoding/json" "fmt" "io" + + "github.com/bytedance/sonic" ) // NewFilterWriter returns a writer that filters out all key/value pairs that do not match the filter. @@ -28,7 +29,7 @@ func (fw *filterWriter) Write(p []byte) (n int, err error) { Module string `json:"module"` } - if err := json.Unmarshal(p, &event); err != nil { + if err := sonic.Unmarshal(p, &event); err != nil { return 0, fmt.Errorf("failed to unmarshal event: %w", err) } diff --git a/log/writer_test.go b/log/writer_test.go index 1c43030f8d7e..d69d6ccdd60c 100644 --- a/log/writer_test.go +++ b/log/writer_test.go @@ -5,8 +5,6 @@ import ( "strings" "testing" - "gotest.tools/v3/assert" - "cosmossdk.io/log" ) @@ -15,13 +13,19 @@ func TestFilteredWriter(t *testing.T) { level := "consensus:debug,mempool:debug,*:error" filter, err := log.ParseLogLevel(level) - assert.NilError(t, err) + if err != nil { + t.Fatalf("failed to parse log level: %v", err) + } logger := log.NewLogger(buf, log.FilterOption(filter)) logger.Debug("this log line should be displayed", log.ModuleKey, "consensus") - assert.Check(t, strings.Contains(buf.String(), "this log line should be displayed")) + if !strings.Contains(buf.String(), "this log line should be displayed") { + t.Errorf("expected log line to be displayed, but it was not") + } buf.Reset() logger.Debug("this log line should be filtered", log.ModuleKey, "server") - assert.Check(t, buf.Len() == 0) + if buf.Len() != 0 { + t.Errorf("expected log line to be filtered, but it was not") + } } diff --git a/runtime/v2/go.mod b/runtime/v2/go.mod index 27ed971add6a..df78675400c7 100644 --- a/runtime/v2/go.mod +++ b/runtime/v2/go.mod @@ -20,7 +20,7 @@ require ( cosmossdk.io/server/v2/appmanager v0.0.0-00010101000000-000000000000 cosmossdk.io/server/v2/stf v0.0.0-00010101000000-000000000000 cosmossdk.io/store/v2 v2.0.0-00010101000000-000000000000 - cosmossdk.io/x/tx v0.13.3 + cosmossdk.io/x/tx v1.0.0-alpha.1 github.com/cosmos/gogoproto v1.7.0 github.com/stretchr/testify v1.9.0 google.golang.org/grpc v1.67.1 diff --git a/server/v2/api/telemetry/config.go b/server/v2/api/telemetry/config.go index 2619665d1844..bb26d942d7c7 100644 --- a/server/v2/api/telemetry/config.go +++ b/server/v2/api/telemetry/config.go @@ -3,7 +3,7 @@ package telemetry func DefaultConfig() *Config { return &Config{ Enable: true, - Address: "localhost:1318", + Address: "localhost:1327", ServiceName: "", EnableHostname: false, EnableHostnameLabel: false, diff --git a/server/v2/appmanager/appmanager.go b/server/v2/appmanager/appmanager.go index af54936ebf03..9380efb0bf21 100644 --- a/server/v2/appmanager/appmanager.go +++ b/server/v2/appmanager/appmanager.go @@ -41,6 +41,10 @@ type AppManager[T transaction.Tx] interface { // Simulate runs validation and execution flow of a Tx. Simulate(ctx context.Context, tx T) (server.TxResult, corestore.WriterMap, error) + // SimulateWithState runs validation and execution flow of a Tx, + // using the provided state instead of loading the latest state from the underlying database. + SimulateWithState(ctx context.Context, state corestore.ReaderMap, tx T) (server.TxResult, corestore.WriterMap, error) + // Query queries the application at the provided version. // CONTRACT: Version must always be provided, if 0, get latest Query(ctx context.Context, version uint64, request transaction.Msg) (transaction.Msg, error) @@ -193,6 +197,13 @@ func (a appManager[T]) Simulate(ctx context.Context, tx T) (server.TxResult, cor return result, cs, nil } +// SimulateWithState runs validation and execution flow of a Tx, +// using the provided state instead of loading the latest state from the underlying database. +func (a appManager[T]) SimulateWithState(ctx context.Context, state corestore.ReaderMap, tx T) (server.TxResult, corestore.WriterMap, error) { + result, cs := a.stf.Simulate(ctx, state, a.config.SimulationGasLimit, tx) // TODO: check if this is done in the antehandler + return result, cs, nil +} + // Query queries the application at the provided version. // CONTRACT: Version must always be provided, if 0, get latest func (a appManager[T]) Query(ctx context.Context, version uint64, request transaction.Msg) (transaction.Msg, error) { diff --git a/server/v2/cometbft/go.mod b/server/v2/cometbft/go.mod index b4e2905a546d..77f1a90f5b2d 100644 --- a/server/v2/cometbft/go.mod +++ b/server/v2/cometbft/go.mod @@ -50,7 +50,7 @@ require ( cosmossdk.io/store v1.1.1-0.20240418092142-896cdf1971bc // indirect cosmossdk.io/x/bank v0.0.0-20240226161501-23359a0b6d91 // indirect cosmossdk.io/x/staking v0.0.0-00010101000000-000000000000 // indirect - cosmossdk.io/x/tx v0.13.3 // indirect + cosmossdk.io/x/tx v1.0.0-alpha.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect diff --git a/server/v2/commands.go b/server/v2/commands.go index d5c202ade9f7..c64fbc1f0de4 100644 --- a/server/v2/commands.go +++ b/server/v2/commands.go @@ -120,9 +120,15 @@ func createStartCommand[T transaction.Tx]( go func() { sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) - sig := <-sigCh - cancelFn() - cmd.Printf("caught %s signal\n", sig.String()) + select { + case sig := <-sigCh: + cancelFn() + cmd.Printf("caught %s signal\n", sig.String()) + case <-ctx.Done(): + // If the root context is canceled (which is likely to happen in tests involving cobra commands), + // don't block waiting for the OS signal before stopping the server. + cancelFn() + } if err := server.Stop(ctx); err != nil { cmd.PrintErrln("failed to stop servers:", err) diff --git a/simapp/export.go b/simapp/export.go index 28d15f507a9b..9600132dfedf 100644 --- a/simapp/export.go +++ b/simapp/export.go @@ -216,7 +216,6 @@ func (app *SimApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs [] // update bond intra-tx counters. store := ctx.KVStore(app.GetKey(stakingtypes.StoreKey)) iter := storetypes.KVStoreReversePrefixIterator(store, stakingtypes.ValidatorsKey) - counter := int16(0) for ; iter.Valid(); iter.Next() { addr := sdk.ValAddress(stakingtypes.AddressFromValidatorsKey(iter.Key())) @@ -238,7 +237,6 @@ func (app *SimApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs [] if err = app.StakingKeeper.SetValidator(ctx, validator); err != nil { panic(err) } - counter++ } if err := iter.Close(); err != nil { diff --git a/simapp/go.mod b/simapp/go.mod index 0988fe2f7f78..b18938c3719d 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -14,7 +14,9 @@ require ( cosmossdk.io/store v1.1.1 cosmossdk.io/tools/confix v0.0.0-20230613133644-0a778132a60f cosmossdk.io/x/accounts v0.0.0-20240913065641-0064ccbce64e + cosmossdk.io/x/accounts/defaults/base v0.0.0-00010101000000-000000000000 cosmossdk.io/x/accounts/defaults/lockup v0.0.0-20240417181816-5e7aae0db1f5 + cosmossdk.io/x/accounts/defaults/multisig v0.0.0-00010101000000-000000000000 cosmossdk.io/x/authz v0.0.0-00010101000000-000000000000 cosmossdk.io/x/bank v0.0.0-20240226161501-23359a0b6d91 cosmossdk.io/x/circuit v0.0.0-20230613133644-0a778132a60f @@ -30,7 +32,7 @@ require ( cosmossdk.io/x/protocolpool v0.0.0-20230925135524-a1bc045b3190 cosmossdk.io/x/slashing v0.0.0-00010101000000-000000000000 cosmossdk.io/x/staking v0.0.0-20240226161501-23359a0b6d91 - cosmossdk.io/x/tx v0.13.5 + cosmossdk.io/x/tx v1.0.0-alpha.1 cosmossdk.io/x/upgrade v0.0.0-20230613133644-0a778132a60f github.com/cometbft/cometbft v1.0.0-rc1.0.20240908111210-ab0be101882f github.com/cometbft/cometbft/api v1.0.0-rc.1 @@ -43,13 +45,8 @@ require ( github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 go.uber.org/mock v0.5.0 - google.golang.org/protobuf v1.35.1 -) - -require ( - cosmossdk.io/x/accounts/defaults/base v0.0.0-00010101000000-000000000000 - cosmossdk.io/x/accounts/defaults/multisig v0.0.0-00010101000000-000000000000 google.golang.org/grpc v1.67.1 + google.golang.org/protobuf v1.35.1 ) require ( diff --git a/simapp/simd/cmd/root_di.go b/simapp/simd/cmd/root_di.go index 7182fe4c9bf9..ea6e70f37a99 100644 --- a/simapp/simd/cmd/root_di.go +++ b/simapp/simd/cmd/root_di.go @@ -16,6 +16,9 @@ import ( "cosmossdk.io/depinject" "cosmossdk.io/log" "cosmossdk.io/simapp" + basedepinject "cosmossdk.io/x/accounts/defaults/base/depinject" + lockupdepinject "cosmossdk.io/x/accounts/defaults/lockup/depinject" + multisigdepinject "cosmossdk.io/x/accounts/defaults/multisig/depinject" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/config" @@ -42,6 +45,12 @@ func NewRootCmd() *cobra.Command { depinject.Supply(log.NewNopLogger()), depinject.Provide( ProvideClientContext, + multisigdepinject.ProvideAccount, + basedepinject.ProvideAccount, + lockupdepinject.ProvideAllLockupAccounts, + + // provide base account options + basedepinject.ProvideSecp256K1PubKey, ), ), &autoCliOpts, diff --git a/simapp/v2/go.mod b/simapp/v2/go.mod index 5059906225c3..b493b093a765 100644 --- a/simapp/v2/go.mod +++ b/simapp/v2/go.mod @@ -65,7 +65,7 @@ require ( cosmossdk.io/server/v2/appmanager v0.0.0-20240802110823-cffeedff643d // indirect cosmossdk.io/server/v2/stf v0.0.0-20240708142107-25e99c54bac1 // indirect cosmossdk.io/store v1.1.1 // indirect - cosmossdk.io/x/tx v0.13.5 // indirect + cosmossdk.io/x/tx v1.0.0-alpha.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect diff --git a/simapp/v2/simdv2/cmd/commands.go b/simapp/v2/simdv2/cmd/commands.go index 4d669f91749b..cf940ac67e96 100644 --- a/simapp/v2/simdv2/cmd/commands.go +++ b/simapp/v2/simdv2/cmd/commands.go @@ -17,7 +17,6 @@ import ( "cosmossdk.io/server/v2/api/grpc" "cosmossdk.io/server/v2/api/rest" "cosmossdk.io/server/v2/api/telemetry" - "cosmossdk.io/server/v2/cometbft" serverstore "cosmossdk.io/server/v2/store" "cosmossdk.io/simapp/v2" confixcmd "cosmossdk.io/tools/confix/cmd" @@ -37,14 +36,14 @@ import ( ) func newApp[T transaction.Tx](logger log.Logger, viper *viper.Viper) serverv2.AppI[T] { - viper.Set(serverv2.FlagHome, simapp.DefaultNodeHome) + viper.SetDefault(serverv2.FlagHome, simapp.DefaultNodeHome) return serverv2.AppI[T](simapp.NewSimApp[T](logger, viper)) } func initRootCmd[T transaction.Tx]( rootCmd *cobra.Command, - txConfig client.TxConfig, moduleManager *runtimev2.MM[T], + consensusComponent serverv2.ServerComponent[T], ) { cfg := sdk.GetConfig() cfg.Seal() @@ -70,11 +69,7 @@ func initRootCmd[T transaction.Tx]( rootCmd, newApp, initServerConfig(), - cometbft.New( - &genericTxDecoder[T]{txConfig}, - initCometOptions[T](), - initCometConfig(), - ), + consensusComponent, grpc.New[T](), serverstore.New[T](), telemetry.New[T](), @@ -165,7 +160,7 @@ func appExport[T transaction.Tx]( // overwrite the FlagInvCheckPeriod viper.Set(server.FlagInvCheckPeriod, 1) - viper.Set(serverv2.FlagHome, simapp.DefaultNodeHome) + viper.SetDefault(serverv2.FlagHome, simapp.DefaultNodeHome) var simApp *simapp.SimApp[T] if height != -1 { diff --git a/simapp/v2/simdv2/cmd/root_di.go b/simapp/v2/simdv2/cmd/root_di.go index 6b13b7201342..da1bcf77061a 100644 --- a/simapp/v2/simdv2/cmd/root_di.go +++ b/simapp/v2/simdv2/cmd/root_di.go @@ -13,7 +13,12 @@ import ( "cosmossdk.io/depinject" "cosmossdk.io/log" "cosmossdk.io/runtime/v2" + serverv2 "cosmossdk.io/server/v2" + "cosmossdk.io/server/v2/cometbft" "cosmossdk.io/simapp/v2" + basedepinject "cosmossdk.io/x/accounts/defaults/base/depinject" + lockupdepinject "cosmossdk.io/x/accounts/defaults/lockup/depinject" + multisigdepinject "cosmossdk.io/x/accounts/defaults/multisig/depinject" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/config" @@ -25,8 +30,25 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/types" ) -// NewRootCmd creates a new root command for simd. It is called once in the main function. -func NewRootCmd[T transaction.Tx]() *cobra.Command { +// NewCometBFTRootCmd creates a new root command for simd, +// using the CometBFT server component for consensus. +// It is called once in the main function. +func NewCometBFTRootCmd[T transaction.Tx]() *cobra.Command { + return NewRootCmdWithConsensusComponent(func(cc client.Context) serverv2.ServerComponent[T] { + return cometbft.New[T]( + &genericTxDecoder[T]{cc.TxConfig}, + initCometOptions[T](), + initCometConfig(), + ) + }) +} + +// NewRootCmdWithConsensusComponent returns a new root command, +// using the provided callback to instantiate the server component for the consensus layer. +// Callers who want to use CometBFT should call [NewCometBFTRootCmd] directly. +func NewRootCmdWithConsensusComponent[T transaction.Tx]( + makeConsensusComponent func(cc client.Context) serverv2.ServerComponent[T], +) *cobra.Command { var ( autoCliOpts autocli.AppOptions moduleManager *runtime.MM[T] @@ -36,7 +58,15 @@ func NewRootCmd[T transaction.Tx]() *cobra.Command { if err := depinject.Inject( depinject.Configs( simapp.AppConfig(), - depinject.Provide(ProvideClientContext), + depinject.Provide( + ProvideClientContext, + // inject desired account types: + multisigdepinject.ProvideAccount, + basedepinject.ProvideAccount, + lockupdepinject.ProvideAllLockupAccounts, + + // provide base account options + basedepinject.ProvideSecp256K1PubKey), depinject.Supply(log.NewNopLogger()), ), &autoCliOpts, @@ -71,12 +101,12 @@ func NewRootCmd[T transaction.Tx]() *cobra.Command { }, } - initRootCmd(rootCmd, clientCtx.TxConfig, moduleManager) + consensusComponent := makeConsensusComponent(clientCtx) + initRootCmd(rootCmd, moduleManager, consensusComponent) nodeCmds := nodeservice.NewNodeCommands() autoCliOpts.ModuleOptions = make(map[string]*autocliv1.ModuleOptions) autoCliOpts.ModuleOptions[nodeCmds.Name()] = nodeCmds.AutoCLIOptions() - if err := autoCliOpts.EnhanceRootCommand(rootCmd); err != nil { panic(err) } diff --git a/simapp/v2/simdv2/cmd/root_test.go b/simapp/v2/simdv2/cmd/root_test.go index 7c51b1b21170..87678bc4b909 100644 --- a/simapp/v2/simdv2/cmd/root_test.go +++ b/simapp/v2/simdv2/cmd/root_test.go @@ -16,7 +16,7 @@ import ( ) func TestInitCmd(t *testing.T) { - rootCmd := cmd.NewRootCmd[transaction.Tx]() + rootCmd := cmd.NewCometBFTRootCmd[transaction.Tx]() rootCmd.SetArgs([]string{ "init", // Test the init cmd "simapp-test", // Moniker @@ -29,7 +29,7 @@ func TestInitCmd(t *testing.T) { func TestHomeFlagRegistration(t *testing.T) { homeDir := "/tmp/foo" - rootCmd := cmd.NewRootCmd[transaction.Tx]() + rootCmd := cmd.NewCometBFTRootCmd[transaction.Tx]() rootCmd.SetArgs([]string{ "query", fmt.Sprintf("--%s", flags.FlagHome), diff --git a/simapp/v2/simdv2/cmd/testnet_test.go b/simapp/v2/simdv2/cmd/testnet_test.go index 145a32608e60..3c7769d912e8 100644 --- a/simapp/v2/simdv2/cmd/testnet_test.go +++ b/simapp/v2/simdv2/cmd/testnet_test.go @@ -16,7 +16,7 @@ import ( ) func TestInitTestFilesCmd(t *testing.T) { - rootCmd := cmd.NewRootCmd[transaction.Tx]() + rootCmd := cmd.NewCometBFTRootCmd[transaction.Tx]() rootCmd.SetArgs([]string{ "testnet", // Test the testnet init-files command "init-files", diff --git a/simapp/v2/simdv2/main.go b/simapp/v2/simdv2/main.go index eb7d9a1b005b..84248ceed0a6 100644 --- a/simapp/v2/simdv2/main.go +++ b/simapp/v2/simdv2/main.go @@ -12,7 +12,7 @@ import ( ) func main() { - rootCmd := cmd.NewRootCmd[transaction.Tx]() + rootCmd := cmd.NewCometBFTRootCmd[transaction.Tx]() if err := serverv2.Execute(rootCmd, clientv2helpers.EnvPrefix, simapp.DefaultNodeHome); err != nil { fmt.Fprintln(rootCmd.OutOrStderr(), err) os.Exit(1) diff --git a/store/cachekv/store_test.go b/store/cachekv/store_test.go index 2885e7125476..de03b04ba3fa 100644 --- a/store/cachekv/store_test.go +++ b/store/cachekv/store_test.go @@ -552,7 +552,6 @@ func assertIterateDomainCheck(t *testing.T, st types.KVStore, mem corestore.KVSt require.NoError(t, err) krc := newKeyRangeCounter(r) - i := 0 for ; krc.valid(); krc.next() { require.True(t, itr.Valid()) @@ -569,7 +568,6 @@ func assertIterateDomainCheck(t *testing.T, st types.KVStore, mem corestore.KVSt itr.Next() itr2.Next() - i++ } require.False(t, itr.Valid()) diff --git a/tests/e2e/tx/service_test.go b/tests/e2e/tx/service_test.go deleted file mode 100644 index f0e4e527664c..000000000000 --- a/tests/e2e/tx/service_test.go +++ /dev/null @@ -1,1145 +0,0 @@ -package tx_test - -import ( - "context" - "encoding/base64" - "fmt" - "os" - "strings" - "testing" - - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - - "cosmossdk.io/math" - "cosmossdk.io/simapp" - banktypes "cosmossdk.io/x/bank/types" - - "github.com/cosmos/cosmos-sdk/client" - clienttx "github.com/cosmos/cosmos-sdk/client/tx" - "github.com/cosmos/cosmos-sdk/crypto/hd" - "github.com/cosmos/cosmos-sdk/crypto/keyring" - kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - "github.com/cosmos/cosmos-sdk/testutil" - "github.com/cosmos/cosmos-sdk/testutil/cli" - "github.com/cosmos/cosmos-sdk/testutil/network" - "github.com/cosmos/cosmos-sdk/testutil/testdata" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/query" - "github.com/cosmos/cosmos-sdk/types/tx" - "github.com/cosmos/cosmos-sdk/types/tx/signing" - authclient "github.com/cosmos/cosmos-sdk/x/auth/client" - authtest "github.com/cosmos/cosmos-sdk/x/auth/client/testutil" - "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" -) - -var bankMsgSendEventAction = fmt.Sprintf("message.action='%s'", sdk.MsgTypeURL(&banktypes.MsgSend{})) - -type E2ETestSuite struct { - suite.Suite - - cfg network.Config - network network.NetworkI - - txHeight int64 - queryClient tx.ServiceClient - goodTxHash string -} - -func (s *E2ETestSuite) SetupSuite() { - s.T().Log("setting up e2e test suite") - - cfg := network.DefaultConfig(simapp.NewTestNetworkFixture) - cfg.NumValidators = 1 - s.cfg = cfg - - var err error - s.network, err = network.New(s.T(), s.T().TempDir(), s.cfg) - s.Require().NoError(err) - - val := s.network.GetValidators()[0] - s.Require().NoError(s.network.WaitForNextBlock()) - - s.queryClient = tx.NewServiceClient(val.GetClientCtx()) - - msgSend := &banktypes.MsgSend{ - FromAddress: val.GetAddress().String(), - ToAddress: val.GetAddress().String(), - Amount: sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))), - } - - // Create a new MsgSend tx from val to itself. - out, err := cli.SubmitTestTx( - val.GetClientCtx(), - msgSend, - val.GetAddress(), - cli.TestTxConfig{ - Memo: "foobar", - }, - ) - - s.Require().NoError(err) - - var txRes sdk.TxResponse - s.Require().NoError(val.GetClientCtx().Codec.UnmarshalJSON(out.Bytes(), &txRes)) - s.Require().Equal(uint32(0), txRes.Code, txRes) - s.goodTxHash = txRes.TxHash - - msgSend1 := &banktypes.MsgSend{ - FromAddress: val.GetAddress().String(), - ToAddress: val.GetAddress().String(), - Amount: sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(1))), - } - - out1, err := cli.SubmitTestTx( - val.GetClientCtx(), - msgSend1, - val.GetAddress(), - cli.TestTxConfig{ - Offline: true, - AccNum: 0, - Seq: 2, - Memo: "foobar", - }, - ) - - s.Require().NoError(err) - var tr sdk.TxResponse - s.Require().NoError(val.GetClientCtx().Codec.UnmarshalJSON(out1.Bytes(), &tr)) - s.Require().Equal(uint32(0), tr.Code) - - resp, err := cli.GetTxResponse(s.network, val.GetClientCtx(), tr.TxHash) - s.Require().NoError(err) - s.txHeight = resp.Height -} - -func (s *E2ETestSuite) TearDownSuite() { - s.T().Log("tearing down e2e test suite") - s.network.Cleanup() -} - -func (s *E2ETestSuite) TestQueryBySig() { - // broadcast tx - txb := s.mkTxBuilder() - txbz, err := s.cfg.TxConfig.TxEncoder()(txb.GetTx()) - s.Require().NoError(err) - resp, err := s.queryClient.BroadcastTx(context.Background(), &tx.BroadcastTxRequest{TxBytes: txbz, Mode: tx.BroadcastMode_BROADCAST_MODE_SYNC}) - s.Require().NoError(err) - s.Require().NotEmpty(resp.TxResponse.TxHash) - - s.Require().NoError(s.network.WaitForNextBlock()) - - // get the signature out of the builder - sigs, err := txb.GetTx().GetSignaturesV2() - s.Require().NoError(err) - s.Require().Len(sigs, 1) - sig, ok := sigs[0].Data.(*signing.SingleSignatureData) - s.Require().True(ok) - - // encode, format, query - b64Sig := base64.StdEncoding.EncodeToString(sig.Signature) - sigFormatted := fmt.Sprintf("%s.%s='%s'", sdk.EventTypeTx, sdk.AttributeKeySignature, b64Sig) - res, err := s.queryClient.GetTxsEvent(context.Background(), &tx.GetTxsEventRequest{ - Query: sigFormatted, - OrderBy: 0, - Page: 0, - Limit: 10, - }) - s.Require().NoError(err) - s.Require().Len(res.Txs, 1) - s.Require().Len(res.Txs[0].Signatures, 1) - s.Require().Equal(res.Txs[0].Signatures[0], sig.Signature) -} - -func (s *E2ETestSuite) TestSimulateTx_GRPC() { - val := s.network.GetValidators()[0] - txBuilder := s.mkTxBuilder() - // Convert the txBuilder to a tx.Tx. - protoTx, err := txBuilder.GetTx().(interface{ AsTx() (*tx.Tx, error) }).AsTx() - s.Require().NoError(err) - // Encode the txBuilder to txBytes. - txBytes, err := val.GetClientCtx().TxConfig.TxEncoder()(txBuilder.GetTx()) - s.Require().NoError(err) - - testCases := []struct { - name string - req *tx.SimulateRequest - expErr bool - expErrMsg string - }{ - {"nil request", nil, true, "request cannot be nil"}, - {"empty request", &tx.SimulateRequest{}, true, "empty txBytes is not allowed"}, - {"valid request with proto tx (deprecated)", &tx.SimulateRequest{Tx: protoTx}, false, ""}, - {"valid request with tx_bytes", &tx.SimulateRequest{TxBytes: txBytes}, false, ""}, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - // Broadcast the tx via gRPC via the validator's clientCtx (which goes - // through Tendermint). - res, err := s.queryClient.Simulate(context.Background(), tc.req) - if tc.expErr { - s.Require().Error(err) - s.Require().Contains(err.Error(), tc.expErrMsg) - } else { - s.Require().NoError(err) - // Check the result and gas used are correct. - // - // The 12 events are: - // - Sending Fee to the pool: coin_spent, coin_received and transfer - // - tx.* events: tx.fee, tx.acc_seq, tx.signature - // - Sending Amount to recipient: coin_spent, coin_received and transfer - // - Msg events: message.module=bank, message.action=/cosmos.bank.v1beta1.MsgSend and message.sender= (in one message) - s.Require().Equal(10, len(res.GetResult().GetEvents())) - s.Require().True(res.GetGasInfo().GetGasUsed() > 0) // Gas used sometimes change, just check it's not empty. - } - }) - } -} - -func (s *E2ETestSuite) TestSimulateTx_GRPCGateway() { - val := s.network.GetValidators()[0] - txBuilder := s.mkTxBuilder() - // Convert the txBuilder to a tx.Tx. - protoTx, err := txBuilder.GetTx().(interface{ AsTx() (*tx.Tx, error) }).AsTx() - s.Require().NoError(err) - // Encode the txBuilder to txBytes. - txBytes, err := val.GetClientCtx().TxConfig.TxEncoder()(txBuilder.GetTx()) - s.Require().NoError(err) - - testCases := []struct { - name string - req *tx.SimulateRequest - expErr bool - expErrMsg string - }{ - {"empty request", &tx.SimulateRequest{}, true, "empty txBytes is not allowed"}, - {"valid request with proto tx (deprecated)", &tx.SimulateRequest{Tx: protoTx}, false, ""}, - {"valid request with tx_bytes", &tx.SimulateRequest{TxBytes: txBytes}, false, ""}, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - req, err := val.GetClientCtx().Codec.MarshalJSON(tc.req) - s.Require().NoError(err) - res, err := testutil.PostRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/simulate", val.GetAPIAddress()), "application/json", req) - s.Require().NoError(err) - if tc.expErr { - s.Require().Contains(string(res), tc.expErrMsg) - } else { - var result tx.SimulateResponse - err = val.GetClientCtx().Codec.UnmarshalJSON(res, &result) - s.Require().NoError(err) - // Check the result and gas used are correct. - s.Require().Len(result.GetResult().MsgResponses, 1) - s.Require().Equal(10, len(result.GetResult().GetEvents())) // See TestSimulateTx_GRPC for the 10 events. - s.Require().True(result.GetGasInfo().GetGasUsed() > 0) // Gas used sometimes change, just check it's not empty. - } - }) - } -} - -func (s *E2ETestSuite) TestGetTxEvents_GRPC() { - testCases := []struct { - name string - req *tx.GetTxsEventRequest - expErr bool - expErrMsg string - expLen int - }{ - { - "nil request", - nil, - true, - "request cannot be nil", - 0, - }, - { - "empty request", - &tx.GetTxsEventRequest{}, - true, - "query cannot be empty", - 0, - }, - { - "request with dummy event", - &tx.GetTxsEventRequest{Query: "foobar"}, - true, - "failed to search for txs", - 0, - }, - { - "request with order-by", - &tx.GetTxsEventRequest{ - Query: bankMsgSendEventAction, - OrderBy: tx.OrderBy_ORDER_BY_ASC, - }, - false, - "", - 3, - }, - { - "without pagination", - &tx.GetTxsEventRequest{ - Query: bankMsgSendEventAction, - }, - false, - "", - 3, - }, - { - "with pagination", - &tx.GetTxsEventRequest{ - Query: bankMsgSendEventAction, - Page: 1, - Limit: 2, - }, - false, - "", - 2, - }, - { - "with multi events", - &tx.GetTxsEventRequest{ - Query: fmt.Sprintf("%s AND message.module='bank'", bankMsgSendEventAction), - }, - false, - "", - 3, - }, - } - for _, tc := range testCases { - s.Run(tc.name, func() { - // Query the tx via gRPC. - grpcRes, err := s.queryClient.GetTxsEvent(context.Background(), tc.req) - if tc.expErr { - s.Require().Error(err) - s.Require().Contains(err.Error(), tc.expErrMsg) - } else { - s.Require().NoError(err) - s.Require().GreaterOrEqual(len(grpcRes.Txs), 1) - s.Require().Equal("foobar", grpcRes.Txs[0].Body.Memo) - s.Require().Equal(tc.expLen, len(grpcRes.Txs)) - - // Make sure fields are populated. - // ref: https://github.com/cosmos/cosmos-sdk/issues/8680 - // ref: https://github.com/cosmos/cosmos-sdk/issues/8681 - s.Require().NotEmpty(grpcRes.TxResponses[0].Timestamp) - s.Require().Empty(grpcRes.TxResponses[0].RawLog) // logs are empty if the transactions are successful - } - }) - } -} - -func (s *E2ETestSuite) TestGetTxEvents_GRPCGateway() { - val := s.network.GetValidators()[0] - testCases := []struct { - name string - url string - expErr bool - expErrMsg string - expLen int - }{ - { - "empty params", - fmt.Sprintf("%s/cosmos/tx/v1beta1/txs", val.GetAPIAddress()), - true, - "query cannot be empty", 0, - }, - { - "without pagination", - fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?query=%s", val.GetAPIAddress(), bankMsgSendEventAction), - false, - "", 3, - }, - { - "with pagination", - fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?query=%s&page=%d&limit=%d", val.GetAPIAddress(), bankMsgSendEventAction, 1, 2), - false, - "", 2, - }, - { - "valid request: order by asc", - fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?query=%s&query=%s&order_by=ORDER_BY_ASC", val.GetAPIAddress(), bankMsgSendEventAction, "message.module='bank'"), - false, - "", 3, - }, - { - "valid request: order by desc", - fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?query=%s&query=%s&order_by=ORDER_BY_DESC", val.GetAPIAddress(), bankMsgSendEventAction, "message.module='bank'"), - false, - "", 3, - }, - { - "invalid request: invalid order by", - fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?query=%s&query=%s&order_by=invalid_order", val.GetAPIAddress(), bankMsgSendEventAction, "message.module='bank'"), - true, - "is not a valid tx.OrderBy", 0, - }, - { - "expect pass with multiple-events", - fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?query=%s&query=%s", val.GetAPIAddress(), bankMsgSendEventAction, "message.module='bank'"), - false, - "", 3, - }, - { - "expect pass with escape event", - fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?query=%s", val.GetAPIAddress(), "message.action%3D'/cosmos.bank.v1beta1.MsgSend'"), - false, - "", 3, - }, - } - for _, tc := range testCases { - s.Run(tc.name, func() { - res, err := testutil.GetRequest(tc.url) - s.Require().NoError(err) - if tc.expErr { - s.Require().Contains(string(res), tc.expErrMsg) - } else { - var result tx.GetTxsEventResponse - err = val.GetClientCtx().Codec.UnmarshalJSON(res, &result) - s.Require().NoError(err, "failed to unmarshal JSON: %s", res) - s.Require().GreaterOrEqual(len(result.Txs), 1) - s.Require().Equal("foobar", result.Txs[0].Body.Memo) - s.Require().NotZero(result.TxResponses[0].Height) - s.Require().Equal(tc.expLen, len(result.Txs)) - } - }) - } -} - -func (s *E2ETestSuite) TestGetTx_GRPC() { - testCases := []struct { - name string - req *tx.GetTxRequest - expErr bool - expErrMsg string - }{ - {"nil request", nil, true, "request cannot be nil"}, - {"empty request", &tx.GetTxRequest{}, true, "tx hash cannot be empty"}, - {"request with dummy hash", &tx.GetTxRequest{Hash: "deadbeef"}, true, "code = NotFound desc = tx not found: deadbeef"}, - {"good request", &tx.GetTxRequest{Hash: s.goodTxHash}, false, ""}, - } - for _, tc := range testCases { - s.Run(tc.name, func() { - // Query the tx via gRPC. - grpcRes, err := s.queryClient.GetTx(context.Background(), tc.req) - if tc.expErr { - s.Require().Error(err) - s.Require().Contains(err.Error(), tc.expErrMsg) - } else { - s.Require().NoError(err) - s.Require().Equal("foobar", grpcRes.Tx.Body.Memo) - } - }) - } -} - -func (s *E2ETestSuite) TestGetTx_GRPCGateway() { - val := s.network.GetValidators()[0] - testCases := []struct { - name string - url string - expErr bool - expErrMsg string - }{ - { - "empty params", - fmt.Sprintf("%s/cosmos/tx/v1beta1/txs/", val.GetAPIAddress()), - true, "tx hash cannot be empty", - }, - { - "dummy hash", - fmt.Sprintf("%s/cosmos/tx/v1beta1/txs/%s", val.GetAPIAddress(), "deadbeef"), - true, "code = NotFound desc = tx not found: deadbeef", - }, - { - "good hash", - fmt.Sprintf("%s/cosmos/tx/v1beta1/txs/%s", val.GetAPIAddress(), s.goodTxHash), - false, "", - }, - } - for _, tc := range testCases { - s.Run(tc.name, func() { - res, err := testutil.GetRequest(tc.url) - s.Require().NoError(err) - if tc.expErr { - s.Require().Contains(string(res), tc.expErrMsg) - } else { - var result tx.GetTxResponse - err = val.GetClientCtx().Codec.UnmarshalJSON(res, &result) - s.Require().NoError(err) - s.Require().Equal("foobar", result.Tx.Body.Memo) - s.Require().NotZero(result.TxResponse.Height) - - // Make sure fields are populated. - // ref: https://github.com/cosmos/cosmos-sdk/issues/8680 - // ref: https://github.com/cosmos/cosmos-sdk/issues/8681 - s.Require().NotEmpty(result.TxResponse.Timestamp) - s.Require().Empty(result.TxResponse.RawLog) // logs are empty on successful transactions - } - }) - } -} - -func (s *E2ETestSuite) TestBroadcastTx_GRPC() { - val := s.network.GetValidators()[0] - txBuilder := s.mkTxBuilder() - txBytes, err := val.GetClientCtx().TxConfig.TxEncoder()(txBuilder.GetTx()) - s.Require().NoError(err) - - testCases := []struct { - name string - req *tx.BroadcastTxRequest - expErr bool - expErrMsg string - }{ - {"nil request", nil, true, "request cannot be nil"}, - {"empty request", &tx.BroadcastTxRequest{}, true, "invalid empty tx"}, - {"no mode", &tx.BroadcastTxRequest{TxBytes: txBytes}, true, "supported types: sync, async"}, - {"valid request", &tx.BroadcastTxRequest{ - Mode: tx.BroadcastMode_BROADCAST_MODE_SYNC, - TxBytes: txBytes, - }, false, ""}, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - // Broadcast the tx via gRPC via the validator's clientCtx (which goes - // through Tendermint). - grpcRes, err := s.queryClient.BroadcastTx(context.Background(), tc.req) - if tc.expErr { - s.Require().Error(err) - s.Require().Contains(err.Error(), tc.expErrMsg) - } else { - s.Require().NoError(err) - s.Require().Equal(uint32(0), grpcRes.TxResponse.Code) - } - }) - } -} - -func (s *E2ETestSuite) TestBroadcastTx_GRPCGateway() { - val := s.network.GetValidators()[0] - txBuilder := s.mkTxBuilder() - txBytes, err := val.GetClientCtx().TxConfig.TxEncoder()(txBuilder.GetTx()) - s.Require().NoError(err) - - testCases := []struct { - name string - req *tx.BroadcastTxRequest - expErr bool - expErrMsg string - }{ - {"empty request", &tx.BroadcastTxRequest{}, true, "invalid empty tx"}, - {"no mode", &tx.BroadcastTxRequest{TxBytes: txBytes}, true, "supported types: sync, async"}, - {"valid request", &tx.BroadcastTxRequest{ - Mode: tx.BroadcastMode_BROADCAST_MODE_SYNC, - TxBytes: txBytes, - }, false, ""}, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - req, err := val.GetClientCtx().Codec.MarshalJSON(tc.req) - s.Require().NoError(err) - res, err := testutil.PostRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/txs", val.GetAPIAddress()), "application/json", req) - s.Require().NoError(err) - if tc.expErr { - s.Require().Contains(string(res), tc.expErrMsg) - } else { - var result tx.BroadcastTxResponse - err = val.GetClientCtx().Codec.UnmarshalJSON(res, &result) - s.Require().NoError(err) - s.Require().Equal(uint32(0), result.TxResponse.Code, "rawlog", result.TxResponse.RawLog) - } - }) - } -} - -func (s *E2ETestSuite) TestSimMultiSigTx() { - val1 := s.network.GetValidators()[0] - clientCtx := val1.GetClientCtx() - - kr := clientCtx.Keyring - - account1, _, err := kr.NewMnemonic("newAccount1", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) - s.Require().NoError(err) - - account2, _, err := kr.NewMnemonic("newAccount2", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) - s.Require().NoError(err) - - pub1, err := account1.GetPubKey() - s.Require().NoError(err) - - pub2, err := account2.GetPubKey() - s.Require().NoError(err) - - multi := kmultisig.NewLegacyAminoPubKey(2, []cryptotypes.PubKey{pub1, pub2}) - _, err = kr.SaveMultisig("multi", multi) - s.Require().NoError(err) - - s.Require().NoError(s.network.WaitForNextBlock()) - - multisigRecord, err := clientCtx.Keyring.Key("multi") - s.Require().NoError(err) - - height, err := s.network.LatestHeight() - s.Require().NoError(err) - _, err = s.network.WaitForHeight(height + 1) - s.Require().NoError(err) - - addr, err := multisigRecord.GetAddress() - s.Require().NoError(err) - - // Send coins from validator to multisig. - coin := sdk.NewInt64Coin(s.cfg.BondDenom, 15) - msgSend := &banktypes.MsgSend{ - FromAddress: val1.GetAddress().String(), - ToAddress: addr.String(), - Amount: sdk.NewCoins(coin), - } - - _, err = cli.SubmitTestTx( - clientCtx, - msgSend, - val1.GetAddress(), - cli.TestTxConfig{}, - ) - - s.Require().NoError(err) - - height, err = s.network.LatestHeight() - s.Require().NoError(err) - _, err = s.network.WaitForHeight(height + 1) - s.Require().NoError(err) - - msgSend1 := &banktypes.MsgSend{ - FromAddress: addr.String(), - ToAddress: val1.GetAddress().String(), - Amount: sdk.NewCoins( - sdk.NewInt64Coin(s.cfg.BondDenom, 5), - ), - } - // Generate multisig transaction. - multiGeneratedTx, err := cli.SubmitTestTx( - clientCtx, - msgSend1, - val1.GetAddress(), - cli.TestTxConfig{ - GenOnly: true, - Memo: "foobar", - }, - ) - - s.Require().NoError(err) - - // Save tx to file - multiGeneratedTxFile := testutil.WriteToNewTempFile(s.T(), multiGeneratedTx.String()) - - // Sign with account1 - addr1, err := account1.GetAddress() - s.Require().NoError(err) - clientCtx.HomeDir = strings.Replace(clientCtx.HomeDir, "simd", "simcli", 1) - account1Signature, err := authtest.TxSignExec(clientCtx, addr1, multiGeneratedTxFile.Name(), "--multisig", addr.String()) - s.Require().NoError(err) - sign1File := testutil.WriteToNewTempFile(s.T(), account1Signature.String()) - - // Sign with account2 - addr2, err := account2.GetAddress() - s.Require().NoError(err) - account2Signature, err := authtest.TxSignExec(clientCtx, addr2, multiGeneratedTxFile.Name(), "--multisig", addr.String()) - s.Require().NoError(err) - sign2File := testutil.WriteToNewTempFile(s.T(), account2Signature.String()) - - // multisign tx - clientCtx.Offline = false - multiSigWith2Signatures, err := authtest.TxMultiSignExec(clientCtx, multisigRecord.Name, multiGeneratedTxFile.Name(), sign1File.Name(), sign2File.Name()) - s.Require().NoError(err) - - // convert from protoJSON to protoBinary for sim - sdkTx, err := clientCtx.TxConfig.TxJSONDecoder()(multiSigWith2Signatures.Bytes()) - s.Require().NoError(err) - txBytes, err := clientCtx.TxConfig.TxEncoder()(sdkTx) - s.Require().NoError(err) - - // simulate tx - sim := &tx.SimulateRequest{TxBytes: txBytes} - res, err := s.queryClient.Simulate(context.Background(), sim) - s.Require().NoError(err) - - // make sure gas was used - s.Require().Greater(res.GasInfo.GasUsed, uint64(0)) -} - -func (s *E2ETestSuite) TestGetBlockWithTxs_GRPC() { - testCases := []struct { - name string - req *tx.GetBlockWithTxsRequest - expErr bool - expErrMsg string - expTxsLen int - }{ - {"nil request", nil, true, "request cannot be nil", 0}, - {"empty request", &tx.GetBlockWithTxsRequest{}, true, "height must not be less than 1 or greater than the current height", 0}, - {"bad height", &tx.GetBlockWithTxsRequest{Height: 99999999}, true, "height must not be less than 1 or greater than the current height", 0}, - {"bad pagination", &tx.GetBlockWithTxsRequest{Height: s.txHeight, Pagination: &query.PageRequest{Offset: 1000, Limit: 100}}, true, "out of range", 0}, - {"good request", &tx.GetBlockWithTxsRequest{Height: s.txHeight}, false, "", 1}, - {"with pagination request", &tx.GetBlockWithTxsRequest{Height: s.txHeight, Pagination: &query.PageRequest{Offset: 0, Limit: 1}}, false, "", 1}, - {"page all request", &tx.GetBlockWithTxsRequest{Height: s.txHeight, Pagination: &query.PageRequest{Offset: 0, Limit: 100}}, false, "", 1}, - {"block with 0 tx", &tx.GetBlockWithTxsRequest{Height: s.txHeight - 1, Pagination: &query.PageRequest{Offset: 0, Limit: 100}}, false, "", 0}, - } - for _, tc := range testCases { - s.Run(tc.name, func() { - // Query the tx via gRPC. - grpcRes, err := s.queryClient.GetBlockWithTxs(context.Background(), tc.req) - if tc.expErr { - s.Require().Error(err) - s.Require().Contains(err.Error(), tc.expErrMsg) - } else { - s.Require().NoError(err) - if tc.expTxsLen > 0 { - s.Require().Equal("foobar", grpcRes.Txs[0].Body.Memo) - } - s.Require().Equal(grpcRes.Block.Header.Height, tc.req.Height) - if tc.req.Pagination != nil { - s.Require().LessOrEqual(len(grpcRes.Txs), int(tc.req.Pagination.Limit)) - } - } - }) - } -} - -func (s *E2ETestSuite) TestGetBlockWithTxs_GRPCGateway() { - val := s.network.GetValidators()[0] - testCases := []struct { - name string - url string - expErr bool - expErrMsg string - }{ - { - "empty params", - fmt.Sprintf("%s/cosmos/tx/v1beta1/txs/block/0", val.GetAPIAddress()), - true, "height must not be less than 1 or greater than the current height", - }, - { - "bad height", - fmt.Sprintf("%s/cosmos/tx/v1beta1/txs/block/%d", val.GetAPIAddress(), 9999999), - true, "height must not be less than 1 or greater than the current height", - }, - { - "good request", - fmt.Sprintf("%s/cosmos/tx/v1beta1/txs/block/%d", val.GetAPIAddress(), s.txHeight), - false, "", - }, - } - for _, tc := range testCases { - s.Run(tc.name, func() { - res, err := testutil.GetRequest(tc.url) - s.Require().NoError(err) - if tc.expErr { - s.Require().Contains(string(res), tc.expErrMsg) - } else { - var result tx.GetBlockWithTxsResponse - err = val.GetClientCtx().Codec.UnmarshalJSON(res, &result) - s.Require().NoError(err) - s.Require().Equal("foobar", result.Txs[0].Body.Memo) - s.Require().Equal(result.Block.Header.Height, s.txHeight) - } - }) - } -} - -func (s *E2ETestSuite) TestTxEncode_GRPC() { - val := s.network.GetValidators()[0] - txBuilder := s.mkTxBuilder() - protoTx, err := txBuilder.GetTx().(interface{ AsTx() (*tx.Tx, error) }).AsTx() - s.Require().NoError(err) - - testCases := []struct { - name string - req *tx.TxEncodeRequest - expErr bool - expErrMsg string - }{ - {"nil request", nil, true, "request cannot be nil"}, - {"empty request", &tx.TxEncodeRequest{}, true, "invalid empty tx"}, - {"valid tx request", &tx.TxEncodeRequest{Tx: protoTx}, false, ""}, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - res, err := s.queryClient.TxEncode(context.Background(), tc.req) - if tc.expErr { - s.Require().Error(err) - s.Require().Contains(err.Error(), tc.expErrMsg) - s.Require().Empty(res) - } else { - s.Require().NoError(err) - s.Require().NotEmpty(res.GetTxBytes()) - - tx, err := val.GetClientCtx().TxConfig.TxDecoder()(res.TxBytes) - s.Require().NoError(err) - s.Require().Equal(protoTx.GetMsgs(), tx.GetMsgs()) - } - }) - } -} - -func (s *E2ETestSuite) TestTxEncode_GRPCGateway() { - val := s.network.GetValidators()[0] - txBuilder := s.mkTxBuilder() - protoTx, err := txBuilder.GetTx().(interface{ AsTx() (*tx.Tx, error) }).AsTx() - s.Require().NoError(err) - - testCases := []struct { - name string - req *tx.TxEncodeRequest - expErr bool - expErrMsg string - }{ - {"empty request", &tx.TxEncodeRequest{}, true, "invalid empty tx"}, - {"valid tx request", &tx.TxEncodeRequest{Tx: protoTx}, false, ""}, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - req, err := val.GetClientCtx().Codec.MarshalJSON(tc.req) - s.Require().NoError(err) - - res, err := testutil.PostRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/encode", val.GetAPIAddress()), "application/json", req) - s.Require().NoError(err) - if tc.expErr { - s.Require().Contains(string(res), tc.expErrMsg) - } else { - var result tx.TxEncodeResponse - err := val.GetClientCtx().Codec.UnmarshalJSON(res, &result) - s.Require().NoError(err) - - tx, err := val.GetClientCtx().TxConfig.TxDecoder()(result.TxBytes) - s.Require().NoError(err) - s.Require().Equal(protoTx.GetMsgs(), tx.GetMsgs()) - } - }) - } -} - -func (s *E2ETestSuite) TestTxDecode_GRPC() { - val := s.network.GetValidators()[0] - txBuilder := s.mkTxBuilder() - - goodTx := txBuilder.GetTx() - encodedTx, err := val.GetClientCtx().TxConfig.TxEncoder()(goodTx) - s.Require().NoError(err) - - invalidTxBytes := append(encodedTx, byte(0o00)) - - testCases := []struct { - name string - req *tx.TxDecodeRequest - expErr bool - expErrMsg string - }{ - {"nil request", nil, true, "request cannot be nil"}, - {"empty request", &tx.TxDecodeRequest{}, true, "invalid empty tx bytes"}, - {"invalid tx bytes", &tx.TxDecodeRequest{TxBytes: invalidTxBytes}, true, "tx parse error"}, - {"valid request with tx bytes", &tx.TxDecodeRequest{TxBytes: encodedTx}, false, ""}, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - res, err := s.queryClient.TxDecode(context.Background(), tc.req) - if tc.expErr { - s.Require().Error(err) - s.Require().Contains(err.Error(), tc.expErrMsg) - s.Require().Empty(res) - } else { - s.Require().NoError(err) - s.Require().NotEmpty(res.GetTx()) - - txb := wrapTx(s.T(), s.cfg.TxConfig, res.Tx) - gotTx := txb.GetTx() - gotEncoded, err := val.GetClientCtx().TxConfig.TxEncoder()(gotTx) - s.Require().NoError(err) - s.Require().Equal(encodedTx, gotEncoded) - } - }) - } -} - -func wrapTx(t *testing.T, conf client.TxConfig, dTx *tx.Tx) client.TxBuilder { - t.Helper() - bodyBytes, err := dTx.Body.Marshal() - require.NoError(t, err) - authInfoBytes, err := dTx.AuthInfo.Marshal() - require.NoError(t, err) - rawTxBytes, err := (&tx.TxRaw{ - BodyBytes: bodyBytes, - AuthInfoBytes: authInfoBytes, - Signatures: dTx.Signatures, - }).Marshal() - require.NoError(t, err) - dec, err := conf.TxDecoder()(rawTxBytes) - require.NoError(t, err) - bld, err := conf.WrapTxBuilder(dec) - require.NoError(t, err) - return bld -} - -func (s *E2ETestSuite) TestTxDecode_GRPCGateway() { - val := s.network.GetValidators()[0] - txBuilder := s.mkTxBuilder() - - encodedTxBytes, err := val.GetClientCtx().TxConfig.TxEncoder()(txBuilder.GetTx()) - s.Require().NoError(err) - - invalidTxBytes := append(encodedTxBytes, byte(0o00)) - - testCases := []struct { - name string - req *tx.TxDecodeRequest - expErr bool - expErrMsg string - }{ - {"empty request", &tx.TxDecodeRequest{}, true, "invalid empty tx bytes"}, - {"invalid tx bytes", &tx.TxDecodeRequest{TxBytes: invalidTxBytes}, true, "tx parse error"}, - {"valid request with tx_bytes", &tx.TxDecodeRequest{TxBytes: encodedTxBytes}, false, ""}, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - req, err := val.GetClientCtx().Codec.MarshalJSON(tc.req) - s.Require().NoError(err) - - res, err := testutil.PostRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/decode", val.GetAPIAddress()), "application/json", req) - s.Require().NoError(err) - if tc.expErr { - s.Require().Contains(string(res), tc.expErrMsg) - } else { - var result tx.TxDecodeResponse - err := val.GetClientCtx().Codec.UnmarshalJSON(res, &result) - s.Require().NoError(err) - - txb := wrapTx(s.T(), s.cfg.TxConfig, result.Tx) - tx, err := val.GetClientCtx().TxConfig.TxEncoder()(txb.GetTx()) - s.Require().NoError(err) - s.T().Log(len(tx), len(encodedTxBytes)) - s.Require().Equal(encodedTxBytes, tx) - } - }) - } -} - -func (s *E2ETestSuite) readTestAminoTxJSON() ([]byte, *legacytx.StdTx) { - val := s.network.GetValidators()[0] - txJSONBytes, err := os.ReadFile("testdata/tx_amino1.json") - s.Require().NoError(err) - var stdTx legacytx.StdTx - err = val.GetClientCtx().LegacyAmino.UnmarshalJSON(txJSONBytes, &stdTx) - s.Require().NoError(err) - return txJSONBytes, &stdTx -} - -func (s *E2ETestSuite) TestTxEncodeAmino_GRPC() { - val := s.network.GetValidators()[0] - txJSONBytes, stdTx := s.readTestAminoTxJSON() - - testCases := []struct { - name string - req *tx.TxEncodeAminoRequest - expErr bool - expErrMsg string - }{ - {"nil request", nil, true, "request cannot be nil"}, - {"empty request", &tx.TxEncodeAminoRequest{}, true, "invalid empty tx json"}, - {"invalid request", &tx.TxEncodeAminoRequest{AminoJson: "invalid tx json"}, true, "invalid request"}, - {"valid request with amino-json", &tx.TxEncodeAminoRequest{AminoJson: string(txJSONBytes)}, false, ""}, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - res, err := s.queryClient.TxEncodeAmino(context.Background(), tc.req) - if tc.expErr { - s.Require().Error(err) - s.Require().Contains(err.Error(), tc.expErrMsg) - s.Require().Empty(res) - } else { - s.Require().NoError(err) - s.Require().NotEmpty(res.GetAminoBinary()) - - var decodedTx legacytx.StdTx - err = val.GetClientCtx().LegacyAmino.Unmarshal(res.AminoBinary, &decodedTx) - s.Require().NoError(err) - s.Require().Equal(decodedTx.GetMsgs(), stdTx.GetMsgs()) - } - }) - } -} - -func (s *E2ETestSuite) TestTxEncodeAmino_GRPCGateway() { - val := s.network.GetValidators()[0] - txJSONBytes, stdTx := s.readTestAminoTxJSON() - - testCases := []struct { - name string - req *tx.TxEncodeAminoRequest - expErr bool - expErrMsg string - }{ - {"empty request", &tx.TxEncodeAminoRequest{}, true, "invalid empty tx json"}, - {"invalid request", &tx.TxEncodeAminoRequest{AminoJson: "invalid tx json"}, true, "invalid request"}, - {"valid request with amino-json", &tx.TxEncodeAminoRequest{AminoJson: string(txJSONBytes)}, false, ""}, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - req, err := val.GetClientCtx().Codec.MarshalJSON(tc.req) - s.Require().NoError(err) - - res, err := testutil.PostRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/encode/amino", val.GetAPIAddress()), "application/json", req) - s.Require().NoError(err) - if tc.expErr { - s.Require().Contains(string(res), tc.expErrMsg) - } else { - var result tx.TxEncodeAminoResponse - err := val.GetClientCtx().Codec.UnmarshalJSON(res, &result) - s.Require().NoError(err) - - var decodedTx legacytx.StdTx - err = val.GetClientCtx().LegacyAmino.Unmarshal(result.AminoBinary, &decodedTx) - s.Require().NoError(err) - s.Require().Equal(decodedTx.GetMsgs(), stdTx.GetMsgs()) - } - }) - } -} - -func (s *E2ETestSuite) readTestAminoTxBinary() ([]byte, *legacytx.StdTx) { - val := s.network.GetValidators()[0] - txJSONBytes, err := os.ReadFile("testdata/tx_amino1.bin") - s.Require().NoError(err) - var stdTx legacytx.StdTx - err = val.GetClientCtx().LegacyAmino.Unmarshal(txJSONBytes, &stdTx) - s.Require().NoError(err) - return txJSONBytes, &stdTx -} - -func (s *E2ETestSuite) TestTxDecodeAmino_GRPC() { - encodedTx, stdTx := s.readTestAminoTxBinary() - - invalidTxBytes := append(encodedTx, byte(0o00)) - - testCases := []struct { - name string - req *tx.TxDecodeAminoRequest - expErr bool - expErrMsg string - }{ - {"nil request", nil, true, "request cannot be nil"}, - {"empty request", &tx.TxDecodeAminoRequest{}, true, "invalid empty tx bytes"}, - {"invalid tx bytes", &tx.TxDecodeAminoRequest{AminoBinary: invalidTxBytes}, true, "invalid request"}, - {"valid request with tx bytes", &tx.TxDecodeAminoRequest{AminoBinary: encodedTx}, false, ""}, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - res, err := s.queryClient.TxDecodeAmino(context.Background(), tc.req) - if tc.expErr { - s.Require().Error(err) - s.Require().Contains(err.Error(), tc.expErrMsg) - s.Require().Empty(res) - } else { - s.Require().NoError(err) - s.Require().NotEmpty(res.GetAminoJson()) - - var decodedTx legacytx.StdTx - err = s.network.GetValidators()[0].GetClientCtx().LegacyAmino.UnmarshalJSON([]byte(res.GetAminoJson()), &decodedTx) - s.Require().NoError(err) - s.Require().Equal(stdTx.GetMsgs(), decodedTx.GetMsgs()) - } - }) - } -} - -func (s *E2ETestSuite) TestTxDecodeAmino_GRPCGateway() { - val := s.network.GetValidators()[0] - encodedTx, stdTx := s.readTestAminoTxBinary() - - invalidTxBytes := append(encodedTx, byte(0o00)) - - testCases := []struct { - name string - req *tx.TxDecodeAminoRequest - expErr bool - expErrMsg string - }{ - {"empty request", &tx.TxDecodeAminoRequest{}, true, "invalid empty tx bytes"}, - {"invalid tx bytes", &tx.TxDecodeAminoRequest{AminoBinary: invalidTxBytes}, true, "invalid request"}, - {"valid request with tx bytes", &tx.TxDecodeAminoRequest{AminoBinary: encodedTx}, false, ""}, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - req, err := val.GetClientCtx().Codec.MarshalJSON(tc.req) - s.Require().NoError(err) - - res, err := testutil.PostRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/decode/amino", val.GetAPIAddress()), "application/json", req) - s.Require().NoError(err) - if tc.expErr { - s.Require().Contains(string(res), tc.expErrMsg) - } else { - var result tx.TxDecodeAminoResponse - err := val.GetClientCtx().Codec.UnmarshalJSON(res, &result) - s.Require().NoError(err) - - var decodedTx legacytx.StdTx - err = val.GetClientCtx().LegacyAmino.UnmarshalJSON([]byte(result.AminoJson), &decodedTx) - s.Require().NoError(err) - s.Require().Equal(stdTx.GetMsgs(), decodedTx.GetMsgs()) - } - }) - } -} - -func TestE2ETestSuite(t *testing.T) { - suite.Run(t, new(E2ETestSuite)) -} - -func (s *E2ETestSuite) mkTxBuilder() client.TxBuilder { - val := s.network.GetValidators()[0] - s.Require().NoError(s.network.WaitForNextBlock()) - - // prepare txBuilder with msg - txBuilder := val.GetClientCtx().TxConfig.NewTxBuilder() - feeAmount := sdk.Coins{sdk.NewInt64Coin(s.cfg.BondDenom, 10)} - gasLimit := testdata.NewTestGasLimit() - s.Require().NoError( - txBuilder.SetMsgs(&banktypes.MsgSend{ - FromAddress: val.GetAddress().String(), - ToAddress: val.GetAddress().String(), - Amount: sdk.Coins{sdk.NewInt64Coin(s.cfg.BondDenom, 10)}, - }), - ) - txBuilder.SetFeeAmount(feeAmount) - txBuilder.SetGasLimit(gasLimit) - txBuilder.SetMemo("foobar") - txBuilder.SetFeePayer(val.GetAddress()) - signers, err := txBuilder.GetTx().GetSigners() - s.Require().NoError(err) - s.Require().Equal([][]byte{val.GetAddress()}, signers) - - // setup txFactory - txFactory := clienttx.Factory{}. - WithChainID(val.GetClientCtx().ChainID). - WithKeybase(val.GetClientCtx().Keyring). - WithTxConfig(val.GetClientCtx().TxConfig). - WithSignMode(signing.SignMode_SIGN_MODE_DIRECT) - - // Sign Tx. - err = authclient.SignTx(txFactory, val.GetClientCtx(), val.GetMoniker(), txBuilder, false, true) - s.Require().NoError(err) - - return txBuilder -} diff --git a/tests/e2e/tx/testdata/tx_amino1.json b/tests/e2e/tx/testdata/tx_amino1.json deleted file mode 100644 index 1d19393e1a54..000000000000 --- a/tests/e2e/tx/testdata/tx_amino1.json +++ /dev/null @@ -1 +0,0 @@ -{"type":"cosmos-sdk/StdTx","value":{"msg":[{"type":"cosmos-sdk/MsgSend","value":{"from_address":"cosmos1hzw8v2kk4csg8xr3fhy8ykyymykknm2tdgvf7k","to_address":"cosmos1hzw8v2kk4csg8xr3fhy8ykyymykknm2tdgvf7k","amount":[{"denom":"stake","amount":"10"}]}}],"fee":{"amount":[{"denom":"stake","amount":"10"}],"gas":"200000"},"signatures":[],"memo":"foobar","timeout_height":"0"}} \ No newline at end of file diff --git a/tests/go.mod b/tests/go.mod index 3e0bf0bb809a..ef20c80f6ef1 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -15,7 +15,7 @@ require ( cosmossdk.io/x/feegrant v0.0.0-20230613133644-0a778132a60f cosmossdk.io/x/nft v0.0.0-20230613133644-0a778132a60f // indirect cosmossdk.io/x/protocolpool v0.0.0-20230925135524-a1bc045b3190 - cosmossdk.io/x/tx v0.13.5 + cosmossdk.io/x/tx v1.0.0-alpha.1 cosmossdk.io/x/upgrade v0.0.0-20230613133644-0a778132a60f github.com/cometbft/cometbft v1.0.0-rc1.0.20240908111210-ab0be101882f github.com/cosmos/cosmos-proto v1.0.0-beta.5 diff --git a/tests/e2e/baseapp/block_gas_test.go b/tests/integration/baseapp/block_gas_test.go similarity index 98% rename from tests/e2e/baseapp/block_gas_test.go rename to tests/integration/baseapp/block_gas_test.go index 8de527ec5bd5..f883b68db9f4 100644 --- a/tests/e2e/baseapp/block_gas_test.go +++ b/tests/integration/baseapp/block_gas_test.go @@ -1,6 +1,3 @@ -//go:build e2e -// +build e2e - package baseapp_test import ( @@ -26,7 +23,7 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/runtime" - baseapputil "github.com/cosmos/cosmos-sdk/tests/e2e/baseapp" + baseapputil "github.com/cosmos/cosmos-sdk/tests/integration/baseapp" "github.com/cosmos/cosmos-sdk/testutil" "github.com/cosmos/cosmos-sdk/testutil/configurator" simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" diff --git a/tests/e2e/baseapp/utils.go b/tests/integration/baseapp/utils.go similarity index 100% rename from tests/e2e/baseapp/utils.go rename to tests/integration/baseapp/utils.go diff --git a/tests/systemtests/account_test.go b/tests/systemtests/account_test.go index 5f3ee7e340ad..db4fed5c7126 100644 --- a/tests/systemtests/account_test.go +++ b/tests/systemtests/account_test.go @@ -1,6 +1,7 @@ package systemtests import ( + "fmt" "strings" "testing" @@ -51,3 +52,104 @@ func TestAccountCreation(t *testing.T) { rsp5 := cli.CustomQuery("q", "auth", "account", account1Addr) assert.Equal(t, "1", gjson.Get(rsp5, "account.value.sequence").String(), rsp5) } + +func TestAccountsMigration(t *testing.T) { + sut.ResetChain(t) + cli := NewCLIWrapper(t, sut, verbose) + + legacyAddress := cli.GetKeyAddr(defaultSrcAddr) + // Create a receiver account + receiverName := "receiver-account" + receiverAddress := cli.AddKey(receiverName) + require.NotEmpty(t, receiverAddress) + sut.ModifyGenesisCLI(t, + []string{"genesis", "add-genesis-account", receiverAddress, "1000000stake"}, + ) + + sut.StartChain(t) + + // Get pubkey + pubKeyValue := cli.GetPubKeyByCustomField(legacyAddress, "address") + require.NotEmpty(t, pubKeyValue, "Public key for legacy-account not found") + + // 1. Verify the account + rsp := cli.CustomQuery("q", "auth", "account", legacyAddress) + require.NotEmpty(t, rsp) + accountInfo := gjson.Parse(rsp) + addressFromResponse := accountInfo.Get("account.value.address").String() + require.Equal(t, legacyAddress, addressFromResponse, "The address in the response should match the legacy address") + + // 2. Migrate this account from x/auth to x/accounts + + // Verify the account not exist in account + rsp = cli.WithRunErrorsIgnored().CustomQuery("q", "accounts", "query", legacyAddress, "cosmos.accounts.defaults.base.v1.QuerySequence", "{}") + require.Contains(t, rsp, "not found: key") + + accountInitMsg := fmt.Sprintf(`{ + "@type": "/cosmos.accounts.defaults.base.v1.MsgInit", + "pub_key": { + "@type": "/cosmos.crypto.secp256k1.PubKey", + "key": "%s" + }, + "init_sequence": "0" + }`, pubKeyValue) + + rsp = cli.RunAndWait("tx", "auth", "migrate-account", + "--account-type=base", + fmt.Sprintf("--account-init-msg=%s", accountInitMsg), + fmt.Sprintf("--from=%s", legacyAddress), + "--fees=1stake") + RequireTxSuccess(t, rsp) + + // 3. Now the account should be existed, query the account Sequence + rsp = cli.CustomQuery("q", "accounts", "query", legacyAddress, "cosmos.accounts.defaults.base.v1.QuerySequence", "{}") + sequence := gjson.Get(rsp, "response.sequence").Exists() + require.True(t, sequence, "Sequence field should exist") + + // 4. Execute a transaction using the bank module + + // Check initial balances + legacyBalance := cli.QueryBalance(legacyAddress, "stake") + receiverBalance := cli.QueryBalance(receiverAddress, "stake") + require.Equal(t, int64(399999999), legacyBalance) // 20000000 - 1 (fee for migration) + require.Equal(t, int64(1000000), receiverBalance) + + transferAmount := "1000000" + rsp = cli.RunAndWait("tx", "bank", "send", + legacyAddress, + receiverAddress, + transferAmount+"stake", + fmt.Sprintf("--from=%s", legacyAddress), + "--fees=1stake") + RequireTxSuccess(t, rsp) + + // Verify the balances after the transaction + newLegacyBalance := cli.QueryBalance(legacyAddress, "stake") + newReceiverBalance := cli.QueryBalance(receiverAddress, "stake") + + expectedLegacyBalance := legacyBalance - 1000000 - 1 // Initial balance - transferred amount - fee + expectedReceiverBalance := receiverBalance + 1000000 // Initial balance + transferred amount + + require.Equal(t, expectedLegacyBalance, newLegacyBalance, "Legacy account balance is incorrect after transfer") + require.Equal(t, expectedReceiverBalance, newReceiverBalance, "Receiver account balance is incorrect after transfer") + + // 5. Test swapKey functionality + newKeyName := "new-key" + newKeyAddress := cli.AddKey(newKeyName) + require.NotEmpty(t, newKeyAddress) + + newPubKey := cli.GetPubKeyByCustomField(newKeyAddress, "address") + require.NotEmpty(t, newPubKey, "Public key for new-key not found") + + swapKeyMsg := fmt.Sprintf(`{ + "new_pub_key": { + "@type": "/cosmos.crypto.secp256k1.PubKey", + "key": "%s" + } + }`, newPubKey) + + rsp = cli.RunAndWait("tx", "accounts", "execute", legacyAddress, "cosmos.accounts.defaults.base.v1.MsgSwapPubKey", swapKeyMsg, + fmt.Sprintf("--from=%s", legacyAddress), + "--fees=1stake") + RequireTxSuccess(t, rsp) +} diff --git a/tests/systemtests/circuit_test.go b/tests/systemtests/circuit_test.go new file mode 100644 index 000000000000..e6b660e22eca --- /dev/null +++ b/tests/systemtests/circuit_test.go @@ -0,0 +1,243 @@ +//go:build system_test + +package systemtests + +import ( + "encoding/json" + "fmt" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/require" + "github.com/tidwall/gjson" +) + +var someMsgs = []string{"/cosmos.bank.v1beta1.MsgSend", "/cosmos.bank.v1beta1.MsgMultiSend"} + +func TestCircuitCommands(t *testing.T) { + // scenario: test circuit commands + // given a running chain + + sut.ResetChain(t) + require.GreaterOrEqual(t, sut.NodesCount(), 2) + + cli := NewCLIWrapper(t, sut, verbose) + + // get validator addresses + superAdmin := cli.GetKeyAddr("node0") + require.NotEmpty(t, superAdmin) + + superAdmin2 := cli.GetKeyAddr("node1") + require.NotEmpty(t, superAdmin2) + + // short voting period + // update expedited voting period to avoid validation error + sut.ModifyGenesisJSON( + t, + SetGovVotingPeriod(t, time.Second*8), + SetGovExpeditedVotingPeriod(t, time.Second*7), + ) + + sut.StartChain(t) + + allMsgsAcc := cli.AddKey("allMsgsAcc") + require.NotEmpty(t, allMsgsAcc) + + someMsgsAcc := cli.AddKey("someMsgsAcc") + require.NotEmpty(t, someMsgsAcc) + + // fund tokens to new created addresses + var amount int64 = 100000 + denom := "stake" + rsp := cli.FundAddress(allMsgsAcc, fmt.Sprintf("%d%s", amount, denom)) + RequireTxSuccess(t, rsp) + require.Equal(t, amount, cli.QueryBalance(allMsgsAcc, denom)) + + rsp = cli.FundAddress(someMsgsAcc, fmt.Sprintf("%d%s", amount, denom)) + RequireTxSuccess(t, rsp) + require.Equal(t, amount, cli.QueryBalance(someMsgsAcc, denom)) + + // query gov module account address + rsp = cli.CustomQuery("q", "auth", "module-account", "gov") + govModAddr := gjson.Get(rsp, "account.value.address") + + // create a proposal to add super admin + validProposal := fmt.Sprintf(` + { + "messages": [ + { + "@type": "/cosmos.circuit.v1.MsgAuthorizeCircuitBreaker", + "granter": "%s", + "grantee": "%s", + "permissions": {"level": 3, "limit_type_urls": []} + } + ], + "title": "Params update proposal", + "deposit": "10000000stake", + "summary": "A short summary of my proposal" + }`, govModAddr, superAdmin) + proposalFile := StoreTempFile(t, []byte(validProposal)) + + rsp = cli.RunAndWait("tx", "gov", "submit-proposal", proposalFile.Name(), "--from="+superAdmin) + RequireTxSuccess(t, rsp) + + // vote to proposal from two validators + rsp = cli.RunAndWait("tx", "gov", "vote", "1", "yes", "--from="+superAdmin) + RequireTxSuccess(t, rsp) + rsp = cli.RunAndWait("tx", "gov", "vote", "1", "yes", "--from="+superAdmin2) + RequireTxSuccess(t, rsp) + + // wait for proposal to pass + time.Sleep(time.Second * 8) + + rsp = cli.CustomQuery("q", "circuit", "accounts") + + level := gjson.Get(rsp, fmt.Sprintf("accounts.#(address==%s).permissions.level", superAdmin)).String() + require.Equal(t, "LEVEL_SUPER_ADMIN", level) + + authorizeTestCases := []struct { + name string + address string + level int + limtTypeURLs []string + expPermission string + }{ + { + "set new super admin", + superAdmin2, + 3, + []string{}, + "LEVEL_SUPER_ADMIN", + }, + { + "set all msgs level to address", + allMsgsAcc, + 2, + []string{}, + "LEVEL_ALL_MSGS", + }, + { + "set some msgs level to address", + someMsgsAcc, + 1, + someMsgs, + "LEVEL_SOME_MSGS", + }, + } + + for _, tc := range authorizeTestCases { + t.Run(tc.name, func(t *testing.T) { + permissionJSON := fmt.Sprintf(`{"level":%d,"limit_type_urls":[]}`, tc.level) + if len(tc.limtTypeURLs) != 0 { + permissionJSON = fmt.Sprintf(`{"level":%d,"limit_type_urls":["%s"]}`, tc.level, strings.Join(tc.limtTypeURLs[:], `","`)) + } + rsp = cli.RunAndWait("tx", "circuit", "authorize", tc.address, permissionJSON, "--from="+superAdmin) + RequireTxSuccess(t, rsp) + + // query account permissions + rsp = cli.CustomQuery("q", "circuit", "account", tc.address) + require.Equal(t, tc.expPermission, gjson.Get(rsp, "permission.level").String()) + if len(tc.limtTypeURLs) != 0 { + listStr := gjson.Get(rsp, "permission.limit_type_urls").String() + + // convert string to array + var msgsList []string + require.NoError(t, json.Unmarshal([]byte(listStr), &msgsList)) + + require.EqualValues(t, tc.limtTypeURLs, msgsList) + } + }) + } + + // test disable tx command + testCircuitTxCommand(t, cli, "disable", superAdmin, superAdmin2, allMsgsAcc, someMsgsAcc) + + // test reset tx command + testCircuitTxCommand(t, cli, "reset", superAdmin, superAdmin2, allMsgsAcc, someMsgsAcc) +} + +func testCircuitTxCommand(t *testing.T, cli *CLIWrapper, txType, superAdmin, superAdmin2, allMsgsAcc, someMsgsAcc string) { + t.Helper() + + disableTestCases := []struct { + name string + fromAddr string + disableMsgs []string + executeTxs [][]string + }{ + { + txType + " msgs with super admin", + superAdmin, + []string{"/cosmos.gov.v1.MsgVote"}, + [][]string{ + { + "tx", "gov", "vote", "3", "yes", "--from=" + superAdmin, + }, + }, + }, + { + txType + " msgs with all msgs level address", + allMsgsAcc, + []string{"/cosmos.gov.v1.MsgDeposit"}, + [][]string{ + { + "tx", "gov", "deposit", "3", "1000stake", "--from=" + allMsgsAcc, + }, + }, + }, + { + txType + " msgs with some msgs level address", + someMsgsAcc, + someMsgs, + [][]string{ + { + "tx", "bank", "send", superAdmin, someMsgsAcc, "10000stake", + }, + { + "tx", "bank", "multi-send", superAdmin, someMsgsAcc, superAdmin2, "10000stake", "--from=" + superAdmin, + }, + }, + }, + } + + for _, tc := range disableTestCases { + t.Run(tc.name, func(t *testing.T) { + cmd := []string{"tx", "circuit", txType, "--from=" + tc.fromAddr} + cmd = append(cmd, tc.disableMsgs...) + rsp := cli.RunAndWait(cmd...) + RequireTxSuccess(t, rsp) + + // execute given type transaction + rsp = cli.CustomQuery("q", "circuit", "disabled-list") + var list []string + if gjson.Get(rsp, "disabled_list").Exists() { + listJSON := gjson.Get(rsp, "disabled_list").Raw + + // convert string to array + require.NoError(t, json.Unmarshal([]byte(listJSON), &list)) + } + for _, msg := range tc.disableMsgs { + if txType == "disable" { + require.Contains(t, list, msg) + } else { + require.NotContains(t, list, msg) + } + } + + // test given msg transaction to confirm + for _, tx := range tc.executeTxs { + tx = append(tx, "--fees=2stake") + rsp = cli.RunCommandWithArgs(cli.withTXFlags(tx...)...) + if txType == "disable" { + RequireTxFailure(t, rsp) + require.Contains(t, gjson.Get(rsp, "raw_log").String(), "tx type not allowed") + } else { + RequireTxSuccess(t, rsp) + } + // wait for sometime to avoid sequence error + time.Sleep(time.Second * 2) + } + }) + } +} diff --git a/tests/systemtests/cli.go b/tests/systemtests/cli.go index a39cc0dd6d16..423b27dc57f5 100644 --- a/tests/systemtests/cli.go +++ b/tests/systemtests/cli.go @@ -331,6 +331,23 @@ func (c CLIWrapper) GetKeyAddrPrefix(name, prefix string) string { return addr } +// GetPubKeyByCustomField returns pubkey in base64 by custom field +func (c CLIWrapper) GetPubKeyByCustomField(addr, field string) string { + keysListOutput := c.Keys("keys", "list") + keysList := gjson.Parse(keysListOutput) + + var pubKeyValue string + keysList.ForEach(func(_, value gjson.Result) bool { + if value.Get(field).String() == addr { + pubKeyJSON := gjson.Parse(value.Get("pubkey").String()) + pubKeyValue = pubKeyJSON.Get("key").String() + return false + } + return true + }) + return pubKeyValue +} + const defaultSrcAddr = "node0" // FundAddress sends the token amount to the destination address diff --git a/tests/e2e/tx/testdata/tx_amino1.bin b/tests/systemtests/testdata/tx_amino1.bin similarity index 100% rename from tests/e2e/tx/testdata/tx_amino1.bin rename to tests/systemtests/testdata/tx_amino1.bin diff --git a/tests/systemtests/testdata/tx_amino1.json b/tests/systemtests/testdata/tx_amino1.json new file mode 100644 index 000000000000..d4fb8cc8d378 --- /dev/null +++ b/tests/systemtests/testdata/tx_amino1.json @@ -0,0 +1,32 @@ +{ + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgSend", + "value": { + "from_address": "cosmos1hzw8v2kk4csg8xr3fhy8ykyymykknm2tdgvf7k", + "to_address": "cosmos1hzw8v2kk4csg8xr3fhy8ykyymykknm2tdgvf7k", + "amount": [ + { + "denom": "stake", + "amount": "10" + } + ] + } + } + ], + "fee": { + "amount": [ + { + "denom": "stake", + "amount": "10" + } + ], + "gas": "200000" + }, + "signatures": [], + "memo": "foobar", + "timeout_height": "0" + } +} \ No newline at end of file diff --git a/tests/systemtests/tx_test.go b/tests/systemtests/tx_test.go new file mode 100644 index 000000000000..344aff775ebc --- /dev/null +++ b/tests/systemtests/tx_test.go @@ -0,0 +1,1086 @@ +//go:build system_test + +package systemtests + +import ( + "context" + "encoding/base64" + "encoding/json" + "os" + + "fmt" + + "testing" + + "github.com/cosmos/cosmos-sdk/testutil" + "github.com/cosmos/cosmos-sdk/types/tx" + "github.com/stretchr/testify/require" + "github.com/tidwall/gjson" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/legacy" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/std" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" + "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +var ( + bankMsgSendEventAction = "message.action='/cosmos.bank.v1beta1.MsgSend'" + denom = "stake" + transferAmount int64 = 1000 +) + +func TestQueryBySig(t *testing.T) { + sut.ResetChain(t) + + cli := NewCLIWrapper(t, sut, verbose) + // get validator address + valAddr := cli.GetKeyAddr("node0") + require.NotEmpty(t, valAddr) + + // add new key + receiverAddr := cli.AddKey("account1") + + sut.StartChain(t) + + qc := tx.NewServiceClient(sut.RPCClient(t)) + + // create unsign tx + bankSendCmdArgs := []string{"tx", "bank", "send", valAddr, receiverAddr, fmt.Sprintf("%d%s", transferAmount, denom), "--fees=10stake", fmt.Sprintf("--chain-id=%s", sut.chainID), "--sign-mode=direct", "--generate-only"} + unsignedTx := cli.RunCommandWithArgs(bankSendCmdArgs...) + txFile := StoreTempFile(t, []byte(unsignedTx)) + + signedTx := cli.RunCommandWithArgs("tx", "sign", txFile.Name(), fmt.Sprintf("--from=%s", valAddr), fmt.Sprintf("--chain-id=%s", sut.chainID), "--keyring-backend=test", "--home=./testnet/node0/simd") + sig := gjson.Get(signedTx, "signatures.0").String() + signedTxFile := StoreTempFile(t, []byte(signedTx)) + + res := cli.Run("tx", "broadcast", signedTxFile.Name()) + RequireTxSuccess(t, res) + + sigFormatted := fmt.Sprintf("%s.%s='%s'", sdk.EventTypeTx, sdk.AttributeKeySignature, sig) + resp, err := qc.GetTxsEvent(context.Background(), &tx.GetTxsEventRequest{ + Query: sigFormatted, + OrderBy: 0, + Page: 0, + Limit: 10, + }) + require.NoError(t, err) + require.Len(t, resp.Txs, 1) + require.Len(t, resp.Txs[0].Signatures, 1) +} + +func TestSimulateTx_GRPC(t *testing.T) { + sut.ResetChain(t) + + cli := NewCLIWrapper(t, sut, verbose) + // get validator address + valAddr := cli.GetKeyAddr("node0") + require.NotEmpty(t, valAddr) + + // add new key + receiverAddr := cli.AddKey("account1") + + sut.StartChain(t) + + qc := tx.NewServiceClient(sut.RPCClient(t)) + + // create unsign tx + bankSendCmdArgs := []string{"tx", "bank", "send", valAddr, receiverAddr, fmt.Sprintf("%d%s", transferAmount, denom), fmt.Sprintf("--chain-id=%s", sut.chainID), "--fees=10stake", "--sign-mode=direct", "--generate-only"} + res := cli.RunCommandWithArgs(bankSendCmdArgs...) + txFile := StoreTempFile(t, []byte(res)) + + res = cli.RunCommandWithArgs("tx", "sign", txFile.Name(), fmt.Sprintf("--from=%s", valAddr), fmt.Sprintf("--chain-id=%s", sut.chainID), "--keyring-backend=test", "--home=./testnet/node0/simd") + signedTxFile := StoreTempFile(t, []byte(res)) + + res = cli.RunCommandWithArgs("tx", "encode", signedTxFile.Name()) + txBz, err := base64.StdEncoding.DecodeString(res) + require.NoError(t, err) + + testCases := []struct { + name string + req *tx.SimulateRequest + expErr bool + expErrMsg string + }{ + {"nil request", nil, true, "request cannot be nil"}, + {"empty request", &tx.SimulateRequest{}, true, "empty txBytes is not allowed"}, + {"valid request with tx_bytes", &tx.SimulateRequest{TxBytes: txBz}, false, ""}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Broadcast the tx via gRPC via the validator's clientCtx (which goes + // through Tendermint). + res, err := qc.Simulate(context.Background(), tc.req) + if tc.expErr { + require.Error(t, err) + require.Contains(t, err.Error(), tc.expErrMsg) + } else { + require.NoError(t, err) + // Check the result and gas used are correct. + // + // The 12 events are: + // - Sending Fee to the pool: coin_spent, coin_received and transfer + // - tx.* events: tx.fee, tx.acc_seq, tx.signature + // - Sending Amount to recipient: coin_spent, coin_received and transfer + // - Msg events: message.module=bank, message.action=/cosmos.bank.v1beta1.MsgSend and message.sender= (in one message) + require.Equal(t, 10, len(res.GetResult().GetEvents())) + require.True(t, res.GetGasInfo().GetGasUsed() > 0) // Gas used sometimes change, just check it's not empty. + } + }) + } +} + +func TestSimulateTx_GRPCGateway(t *testing.T) { + sut.ResetChain(t) + + cli := NewCLIWrapper(t, sut, verbose) + // get validator address + valAddr := cli.GetKeyAddr("node0") + require.NotEmpty(t, valAddr) + + // add new key + receiverAddr := cli.AddKey("account1") + + sut.StartChain(t) + + // qc := tx.NewServiceClient(sut.RPCClient(t)) + baseURL := sut.APIAddress() + + // create unsign tx + bankSendCmdArgs := []string{"tx", "bank", "send", valAddr, receiverAddr, fmt.Sprintf("%d%s", transferAmount, denom), fmt.Sprintf("--chain-id=%s", sut.chainID), "--fees=10stake", "--sign-mode=direct", "--generate-only"} + res := cli.RunCommandWithArgs(bankSendCmdArgs...) + txFile := StoreTempFile(t, []byte(res)) + + res = cli.RunCommandWithArgs("tx", "sign", txFile.Name(), fmt.Sprintf("--from=%s", valAddr), fmt.Sprintf("--chain-id=%s", sut.chainID), "--keyring-backend=test", "--home=./testnet/node0/simd") + signedTxFile := StoreTempFile(t, []byte(res)) + + res = cli.RunCommandWithArgs("tx", "encode", signedTxFile.Name()) + txBz, err := base64.StdEncoding.DecodeString(res) + require.NoError(t, err) + + testCases := []struct { + name string + req *tx.SimulateRequest + expErr bool + expErrMsg string + }{ + {"empty request", &tx.SimulateRequest{}, true, "empty txBytes is not allowed"}, + {"valid request with tx_bytes", &tx.SimulateRequest{TxBytes: txBz}, false, ""}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + reqBz, err := json.Marshal(tc.req) + require.NoError(t, err) + + res, err := testutil.PostRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/simulate", baseURL), "application/json", reqBz) + require.NoError(t, err) + if tc.expErr { + require.Contains(t, string(res), tc.expErrMsg) + } else { + require.NoError(t, err) + msgResponses := gjson.Get(string(res), "result.msg_responses").Array() + require.Equal(t, len(msgResponses), 1) + + events := gjson.Get(string(res), "result.events").Array() + require.Equal(t, len(events), 10) + + gasUsed := gjson.Get(string(res), "gas_info.gas_used").Int() + require.True(t, gasUsed > 0) + } + }) + } +} + +func TestGetTxEvents_GRPC(t *testing.T) { + sut.ResetChain(t) + + cli := NewCLIWrapper(t, sut, verbose) + // get validator address + valAddr := cli.GetKeyAddr("node0") + require.NotEmpty(t, valAddr) + + // add new key + receiverAddr := cli.AddKey("account1") + + sut.StartChain(t) + + qc := tx.NewServiceClient(sut.RPCClient(t)) + rsp := cli.Run("tx", "bank", "send", valAddr, receiverAddr, fmt.Sprintf("%d%s", transferAmount, denom), "--note=foobar", "--fees=1stake") + txResult, found := cli.AwaitTxCommitted(rsp) + require.True(t, found) + RequireTxSuccess(t, txResult) + + rsp = cli.Run("tx", "bank", "send", valAddr, receiverAddr, fmt.Sprintf("%d%s", transferAmount, denom), "--fees=1stake") + txResult, found = cli.AwaitTxCommitted(rsp) + require.True(t, found) + RequireTxSuccess(t, txResult) + + testCases := []struct { + name string + req *tx.GetTxsEventRequest + expErr bool + expErrMsg string + expLen int + }{ + { + "nil request", + nil, + true, + "request cannot be nil", + 0, + }, + { + "empty request", + &tx.GetTxsEventRequest{}, + true, + "query cannot be empty", + 0, + }, + { + "request with dummy event", + &tx.GetTxsEventRequest{Query: "foobar"}, + true, + "failed to search for txs", + 0, + }, + { + "request with order-by", + &tx.GetTxsEventRequest{ + Query: bankMsgSendEventAction, + OrderBy: tx.OrderBy_ORDER_BY_ASC, + }, + false, + "", + 2, + }, + { + "without pagination", + &tx.GetTxsEventRequest{ + Query: bankMsgSendEventAction, + }, + false, + "", + 2, + }, + { + "with pagination", + &tx.GetTxsEventRequest{ + Query: bankMsgSendEventAction, + Page: 1, + Limit: 1, + }, + false, + "", + 1, + }, + { + "with multi events", + &tx.GetTxsEventRequest{ + Query: fmt.Sprintf("%s AND message.module='bank'", bankMsgSendEventAction), + }, + false, + "", + 2, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Query the tx via gRPC. + grpcRes, err := qc.GetTxsEvent(context.Background(), tc.req) + if tc.expErr { + require.Error(t, err) + require.Contains(t, err.Error(), tc.expErrMsg) + } else { + require.NoError(t, err) + require.GreaterOrEqual(t, len(grpcRes.Txs), 1) + require.Equal(t, "foobar", grpcRes.Txs[0].Body.Memo) + require.Equal(t, tc.expLen, len(grpcRes.Txs)) + + // Make sure fields are populated. + require.NotEmpty(t, grpcRes.TxResponses[0].Timestamp) + require.Empty(t, grpcRes.TxResponses[0].RawLog) // logs are empty if the transactions are successful + } + }) + } +} + +func TestGetTxEvents_GRPCGateway(t *testing.T) { + sut.ResetChain(t) + + cli := NewCLIWrapper(t, sut, verbose) + // get validator address + valAddr := cli.GetKeyAddr("node0") + require.NotEmpty(t, valAddr) + + // add new key + receiverAddr := cli.AddKey("account1") + + sut.StartChain(t) + + // qc := tx.NewServiceClient(sut.RPCClient(t)) + baseURL := sut.APIAddress() + rsp := cli.Run("tx", "bank", "send", valAddr, receiverAddr, fmt.Sprintf("%d%s", transferAmount, denom), "--note=foobar", "--fees=1stake") + txResult, found := cli.AwaitTxCommitted(rsp) + require.True(t, found) + RequireTxSuccess(t, txResult) + + rsp = cli.Run("tx", "bank", "send", valAddr, receiverAddr, fmt.Sprintf("%d%s", transferAmount, denom), "--fees=1stake") + txResult, found = cli.AwaitTxCommitted(rsp) + require.True(t, found) + RequireTxSuccess(t, txResult) + + testCases := []struct { + name string + url string + expErr bool + expErrMsg string + expLen int + }{ + { + "empty params", + fmt.Sprintf("%s/cosmos/tx/v1beta1/txs", baseURL), + true, + "query cannot be empty", 0, + }, + { + "without pagination", + fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?query=%s", baseURL, bankMsgSendEventAction), + false, + "", 2, + }, + { + "with pagination", + fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?query=%s&page=%d&limit=%d", baseURL, bankMsgSendEventAction, 1, 1), + false, + "", 1, + }, + { + "valid request: order by asc", + fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?query=%s&query=%s&order_by=ORDER_BY_ASC", baseURL, bankMsgSendEventAction, "message.module='bank'"), + false, + "", 2, + }, + { + "valid request: order by desc", + fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?query=%s&query=%s&order_by=ORDER_BY_DESC", baseURL, bankMsgSendEventAction, "message.module='bank'"), + false, + "", 2, + }, + { + "invalid request: invalid order by", + fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?query=%s&query=%s&order_by=invalid_order", baseURL, bankMsgSendEventAction, "message.module='bank'"), + true, + "is not a valid tx.OrderBy", 0, + }, + { + "expect pass with multiple-events", + fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?query=%s&query=%s", baseURL, bankMsgSendEventAction, "message.module='bank'"), + false, + "", 2, + }, + { + "expect pass with escape event", + fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?query=%s", baseURL, "message.action%3D'/cosmos.bank.v1beta1.MsgSend'"), + false, + "", 2, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + res, err := testutil.GetRequest(tc.url) + require.NoError(t, err) + if tc.expErr { + require.Contains(t, string(res), tc.expErrMsg) + } else { + require.NoError(t, err) + txs := gjson.Get(string(res), "txs").Array() + require.Equal(t, len(txs), tc.expLen) + } + }) + } +} + +func TestGetTx_GRPC(t *testing.T) { + sut.ResetChain(t) + + cli := NewCLIWrapper(t, sut, verbose) + // get validator address + valAddr := cli.GetKeyAddr("node0") + require.NotEmpty(t, valAddr) + + // add new key + receiverAddr := cli.AddKey("account1") + + sut.StartChain(t) + + qc := tx.NewServiceClient(sut.RPCClient(t)) + + rsp := cli.Run("tx", "bank", "send", valAddr, receiverAddr, fmt.Sprintf("%d%s", transferAmount, denom), "--fees=1stake", "--note=foobar") + txResult, found := cli.AwaitTxCommitted(rsp) + require.True(t, found) + RequireTxSuccess(t, txResult) + txHash := gjson.Get(txResult, "txhash").String() + + testCases := []struct { + name string + req *tx.GetTxRequest + expErr bool + expErrMsg string + }{ + {"nil request", nil, true, "request cannot be nil"}, + {"empty request", &tx.GetTxRequest{}, true, "tx hash cannot be empty"}, + {"request with dummy hash", &tx.GetTxRequest{Hash: "deadbeef"}, true, "code = NotFound desc = tx not found: deadbeef"}, + {"good request", &tx.GetTxRequest{Hash: txHash}, false, ""}, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Query the tx via gRPC. + grpcRes, err := qc.GetTx(context.Background(), tc.req) + if tc.expErr { + require.Error(t, err) + require.Contains(t, err.Error(), tc.expErrMsg) + } else { + require.NoError(t, err) + require.Equal(t, "foobar", grpcRes.Tx.Body.Memo) + } + }) + } +} + +func TestGetTx_GRPCGateway(t *testing.T) { + sut.ResetChain(t) + + cli := NewCLIWrapper(t, sut, verbose) + // get validator address + valAddr := cli.GetKeyAddr("node0") + require.NotEmpty(t, valAddr) + + // add new key + receiverAddr := cli.AddKey("account1") + + sut.StartChain(t) + + baseURL := sut.APIAddress() + + rsp := cli.Run("tx", "bank", "send", valAddr, receiverAddr, fmt.Sprintf("%d%s", transferAmount, denom), "--fees=1stake", "--note=foobar") + txResult, found := cli.AwaitTxCommitted(rsp) + require.True(t, found) + RequireTxSuccess(t, txResult) + txHash := gjson.Get(txResult, "txhash").String() + + testCases := []struct { + name string + url string + expErr bool + expErrMsg string + }{ + { + "empty params", + fmt.Sprintf("%s/cosmos/tx/v1beta1/txs/", baseURL), + true, "tx hash cannot be empty", + }, + { + "dummy hash", + fmt.Sprintf("%s/cosmos/tx/v1beta1/txs/%s", baseURL, "deadbeef"), + true, "tx not found", + }, + { + "good hash", + fmt.Sprintf("%s/cosmos/tx/v1beta1/txs/%s", baseURL, txHash), + false, "", + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + res, err := testutil.GetRequest(tc.url) + require.NoError(t, err) + if tc.expErr { + require.Contains(t, string(res), tc.expErrMsg) + } else { + timestamp := gjson.Get(string(res), "tx_response.timestamp").String() + require.NotEmpty(t, timestamp) + + height := gjson.Get(string(res), "tx_response.height").Int() + require.NotZero(t, height) + + rawLog := gjson.Get(string(res), "tx_response.raw_log").String() + require.Empty(t, rawLog) + } + }) + } +} + +func TestGetBlockWithTxs_GRPC(t *testing.T) { + sut.ResetChain(t) + + cli := NewCLIWrapper(t, sut, verbose) + // get validator address + valAddr := cli.GetKeyAddr("node0") + require.NotEmpty(t, valAddr) + + // add new key + receiverAddr := cli.AddKey("account1") + + sut.StartChain(t) + + qc := tx.NewServiceClient(sut.RPCClient(t)) + + rsp := cli.Run("tx", "bank", "send", valAddr, receiverAddr, fmt.Sprintf("%d%s", transferAmount, denom), "--fees=1stake", "--note=foobar") + txResult, found := cli.AwaitTxCommitted(rsp) + require.True(t, found) + RequireTxSuccess(t, txResult) + height := gjson.Get(txResult, "height").Int() + + testCases := []struct { + name string + req *tx.GetBlockWithTxsRequest + expErr bool + expErrMsg string + expTxsLen int + }{ + {"nil request", nil, true, "request cannot be nil", 0}, + {"empty request", &tx.GetBlockWithTxsRequest{}, true, "height must not be less than 1 or greater than the current height", 0}, + {"bad height", &tx.GetBlockWithTxsRequest{Height: 99999999}, true, "height must not be less than 1 or greater than the current height", 0}, + {"bad pagination", &tx.GetBlockWithTxsRequest{Height: height, Pagination: &query.PageRequest{Offset: 1000, Limit: 100}}, true, "out of range", 0}, + {"good request", &tx.GetBlockWithTxsRequest{Height: height}, false, "", 1}, + {"with pagination request", &tx.GetBlockWithTxsRequest{Height: height, Pagination: &query.PageRequest{Offset: 0, Limit: 1}}, false, "", 1}, + {"page all request", &tx.GetBlockWithTxsRequest{Height: height, Pagination: &query.PageRequest{Offset: 0, Limit: 100}}, false, "", 1}, + {"block with 0 tx", &tx.GetBlockWithTxsRequest{Height: height - 1, Pagination: &query.PageRequest{Offset: 0, Limit: 100}}, false, "", 0}, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Query the tx via gRPC. + grpcRes, err := qc.GetBlockWithTxs(context.Background(), tc.req) + if tc.expErr { + require.Error(t, err) + require.Contains(t, err.Error(), tc.expErrMsg) + } else { + require.NoError(t, err) + if tc.expTxsLen > 0 { + require.Equal(t, "foobar", grpcRes.Txs[0].Body.Memo) + } + require.Equal(t, grpcRes.Block.Header.Height, tc.req.Height) + if tc.req.Pagination != nil { + require.LessOrEqual(t, len(grpcRes.Txs), int(tc.req.Pagination.Limit)) + } + } + }) + } +} + +func TestGetBlockWithTxs_GRPCGateway(t *testing.T) { + sut.ResetChain(t) + + cli := NewCLIWrapper(t, sut, verbose) + // get validator address + valAddr := cli.GetKeyAddr("node0") + require.NotEmpty(t, valAddr) + + // add new key + receiverAddr := cli.AddKey("account1") + + sut.StartChain(t) + + baseUrl := sut.APIAddress() + + rsp := cli.Run("tx", "bank", "send", valAddr, receiverAddr, fmt.Sprintf("%d%s", transferAmount, denom), "--fees=1stake", "--note=foobar") + txResult, found := cli.AwaitTxCommitted(rsp) + require.True(t, found) + RequireTxSuccess(t, txResult) + height := gjson.Get(txResult, "height").Int() + + testCases := []struct { + name string + url string + expErr bool + expErrMsg string + }{ + { + "empty params", + fmt.Sprintf("%s/cosmos/tx/v1beta1/txs/block/0", baseUrl), + true, "height must not be less than 1 or greater than the current height", + }, + { + "bad height", + fmt.Sprintf("%s/cosmos/tx/v1beta1/txs/block/%d", baseUrl, 9999999), + true, "height must not be less than 1 or greater than the current height", + }, + { + "good request", + fmt.Sprintf("%s/cosmos/tx/v1beta1/txs/block/%d", baseUrl, height), + false, "", + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + res, err := testutil.GetRequest(tc.url) + require.NoError(t, err) + if tc.expErr { + require.Contains(t, string(res), tc.expErrMsg) + } else { + memo := gjson.Get(string(res), "txs.0.body.memo").String() + require.Equal(t, memo, "foobar") + + respHeight := gjson.Get(string(res), "block.header.height").Int() + require.Equal(t, respHeight, height) + } + }) + } +} + +func TestTxEncode_GRPC(t *testing.T) { + sut.ResetChain(t) + + cli := NewCLIWrapper(t, sut, verbose) + // get validator address + valAddr := cli.GetKeyAddr("node0") + require.NotEmpty(t, valAddr) + + sut.StartChain(t) + + qc := tx.NewServiceClient(sut.RPCClient(t)) + + protoTx := &tx.Tx{ + Body: &tx.TxBody{ + Messages: []*codectypes.Any{}, + }, + AuthInfo: &tx.AuthInfo{}, + Signatures: [][]byte{}, + } + + testCases := []struct { + name string + req *tx.TxEncodeRequest + expErr bool + expErrMsg string + }{ + {"nil request", nil, true, "request cannot be nil"}, + {"empty request", &tx.TxEncodeRequest{}, true, "invalid empty tx"}, + {"valid tx request", &tx.TxEncodeRequest{Tx: protoTx}, false, ""}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + res, err := qc.TxEncode(context.Background(), tc.req) + if tc.expErr { + require.Error(t, err) + require.Contains(t, err.Error(), tc.expErrMsg) + require.Empty(t, res) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestTxEncode_GRPCGateway(t *testing.T) { + sut.ResetChain(t) + + cli := NewCLIWrapper(t, sut, verbose) + // get validator address + valAddr := cli.GetKeyAddr("node0") + require.NotEmpty(t, valAddr) + + sut.StartChain(t) + + baseUrl := sut.APIAddress() + + protoTx := &tx.Tx{ + Body: &tx.TxBody{ + Messages: []*codectypes.Any{}, + }, + AuthInfo: &tx.AuthInfo{}, + Signatures: [][]byte{}, + } + + testCases := []struct { + name string + req *tx.TxEncodeRequest + expErr bool + expErrMsg string + }{ + {"empty request", &tx.TxEncodeRequest{}, true, "invalid empty tx"}, + {"valid tx request", &tx.TxEncodeRequest{Tx: protoTx}, false, ""}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + reqBz, err := json.Marshal(tc.req) + require.NoError(t, err) + + res, err := testutil.PostRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/encode", baseUrl), "application/json", reqBz) + require.NoError(t, err) + if tc.expErr { + require.Contains(t, string(res), tc.expErrMsg) + } + }) + } +} + +func TestTxDecode_GRPC(t *testing.T) { + sut.ResetChain(t) + + cli := NewCLIWrapper(t, sut, verbose) + // get validator address + valAddr := cli.GetKeyAddr("node0") + require.NotEmpty(t, valAddr) + + // add new key + receiverAddr := cli.AddKey("account1") + + sut.StartChain(t) + + qc := tx.NewServiceClient(sut.RPCClient(t)) + + // create unsign tx + bankSendCmdArgs := []string{"tx", "bank", "send", valAddr, receiverAddr, fmt.Sprintf("%d%s", transferAmount, denom), fmt.Sprintf("--chain-id=%s", sut.chainID), "--fees=10stake", "--sign-mode=direct", "--generate-only"} + res := cli.RunCommandWithArgs(bankSendCmdArgs...) + txFile := StoreTempFile(t, []byte(res)) + + res = cli.RunCommandWithArgs("tx", "sign", txFile.Name(), fmt.Sprintf("--from=%s", valAddr), fmt.Sprintf("--chain-id=%s", sut.chainID), "--keyring-backend=test", "--home=./testnet/node0/simd") + signedTxFile := StoreTempFile(t, []byte(res)) + + res = cli.RunCommandWithArgs("tx", "encode", signedTxFile.Name()) + txBz, err := base64.StdEncoding.DecodeString(res) + require.NoError(t, err) + invalidTxBytes := append(txBz, byte(0o00)) + + testCases := []struct { + name string + req *tx.TxDecodeRequest + expErr bool + expErrMsg string + }{ + {"nil request", nil, true, "request cannot be nil"}, + {"empty request", &tx.TxDecodeRequest{}, true, "invalid empty tx bytes"}, + {"invalid tx bytes", &tx.TxDecodeRequest{TxBytes: invalidTxBytes}, true, "tx parse error"}, + {"valid request with tx bytes", &tx.TxDecodeRequest{TxBytes: txBz}, false, ""}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + res, err := qc.TxDecode(context.Background(), tc.req) + if tc.expErr { + require.Error(t, err) + require.Contains(t, err.Error(), tc.expErrMsg) + require.Empty(t, res) + } else { + require.NoError(t, err) + require.NotEmpty(t, res.GetTx()) + } + }) + } +} + +func TestTxDecode_GRPCGateway(t *testing.T) { + sut.ResetChain(t) + + cli := NewCLIWrapper(t, sut, verbose) + // get validator address + valAddr := cli.GetKeyAddr("node0") + require.NotEmpty(t, valAddr) + + // add new key + receiverAddr := cli.AddKey("account1") + + sut.StartChain(t) + + basrUrl := sut.APIAddress() + + // create unsign tx + bankSendCmdArgs := []string{"tx", "bank", "send", valAddr, receiverAddr, fmt.Sprintf("%d%s", transferAmount, denom), fmt.Sprintf("--chain-id=%s", sut.chainID), "--fees=10stake", "--sign-mode=direct", "--generate-only"} + res := cli.RunCommandWithArgs(bankSendCmdArgs...) + txFile := StoreTempFile(t, []byte(res)) + + res = cli.RunCommandWithArgs("tx", "sign", txFile.Name(), fmt.Sprintf("--from=%s", valAddr), fmt.Sprintf("--chain-id=%s", sut.chainID), "--keyring-backend=test", "--home=./testnet/node0/simd") + signedTxFile := StoreTempFile(t, []byte(res)) + + res = cli.RunCommandWithArgs("tx", "encode", signedTxFile.Name()) + txBz, err := base64.StdEncoding.DecodeString(res) + require.NoError(t, err) + invalidTxBytes := append(txBz, byte(0o00)) + + testCases := []struct { + name string + req *tx.TxDecodeRequest + expErr bool + expErrMsg string + }{ + {"empty request", &tx.TxDecodeRequest{}, true, "invalid empty tx bytes"}, + {"invalid tx bytes", &tx.TxDecodeRequest{TxBytes: invalidTxBytes}, true, "tx parse error"}, + {"valid request with tx_bytes", &tx.TxDecodeRequest{TxBytes: txBz}, false, ""}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + reqBz, err := json.Marshal(tc.req) + require.NoError(t, err) + + res, err := testutil.PostRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/decode", basrUrl), "application/json", reqBz) + require.NoError(t, err) + if tc.expErr { + require.Contains(t, string(res), tc.expErrMsg) + } else { + signatures := gjson.Get(string(res), "tx.signatures").Array() + require.Equal(t, len(signatures), 1) + } + }) + } +} + +func TestTxEncodeAmino_GRPC(t *testing.T) { + sut.ResetChain(t) + sut.StartChain(t) + + legacyAmino := codec.NewLegacyAmino() + std.RegisterLegacyAminoCodec(legacyAmino) + legacytx.RegisterLegacyAminoCodec(legacyAmino) + legacy.RegisterAminoMsg(legacyAmino, &banktypes.MsgSend{}, "cosmos-sdk/MsgSend") + + qc := tx.NewServiceClient(sut.RPCClient(t)) + txJSONBytes, stdTx := readTestAminoTxJSON(t, legacyAmino) + + testCases := []struct { + name string + req *tx.TxEncodeAminoRequest + expErr bool + expErrMsg string + }{ + {"nil request", nil, true, "request cannot be nil"}, + {"empty request", &tx.TxEncodeAminoRequest{}, true, "invalid empty tx json"}, + {"invalid request", &tx.TxEncodeAminoRequest{AminoJson: "invalid tx json"}, true, "invalid request"}, + {"valid request with amino-json", &tx.TxEncodeAminoRequest{AminoJson: string(txJSONBytes)}, false, ""}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + res, err := qc.TxEncodeAmino(context.Background(), tc.req) + if tc.expErr { + require.Error(t, err) + require.Contains(t, err.Error(), tc.expErrMsg) + require.Empty(t, res) + } else { + require.NoError(t, err) + require.NotEmpty(t, res.GetAminoBinary()) + + var decodedTx legacytx.StdTx + err = legacyAmino.Unmarshal(res.AminoBinary, &decodedTx) + require.NoError(t, err) + require.Equal(t, decodedTx.GetMsgs(), stdTx.GetMsgs()) + } + }) + } +} + +func TestTxEncodeAmino_GRPCGateway(t *testing.T) { + sut.ResetChain(t) + sut.StartChain(t) + + legacyAmino := codec.NewLegacyAmino() + std.RegisterLegacyAminoCodec(legacyAmino) + legacytx.RegisterLegacyAminoCodec(legacyAmino) + legacy.RegisterAminoMsg(legacyAmino, &banktypes.MsgSend{}, "cosmos-sdk/MsgSend") + + baseUrl := sut.APIAddress() + txJSONBytes, stdTx := readTestAminoTxJSON(t, legacyAmino) + + testCases := []struct { + name string + req *tx.TxEncodeAminoRequest + expErr bool + expErrMsg string + }{ + {"empty request", &tx.TxEncodeAminoRequest{}, true, "invalid empty tx json"}, + {"invalid request", &tx.TxEncodeAminoRequest{AminoJson: "invalid tx json"}, true, "cannot parse disfix JSON wrapper"}, + {"valid request with amino-json", &tx.TxEncodeAminoRequest{AminoJson: string(txJSONBytes)}, false, ""}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + reqBz, err := json.Marshal(tc.req) + require.NoError(t, err) + + res, err := testutil.PostRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/encode/amino", baseUrl), "application/json", reqBz) + require.NoError(t, err) + if tc.expErr { + require.Contains(t, string(res), tc.expErrMsg) + } else { + var result tx.TxEncodeAminoResponse + err := json.Unmarshal(res, &result) + require.NoError(t, err) + + var decodedTx legacytx.StdTx + err = legacyAmino.Unmarshal(result.AminoBinary, &decodedTx) + require.NoError(t, err) + require.Equal(t, decodedTx.GetMsgs(), stdTx.GetMsgs()) + } + }) + } +} + +func TestTxDecodeAmino_GRPC(t *testing.T) { + sut.ResetChain(t) + sut.StartChain(t) + + legacyAmino := codec.NewLegacyAmino() + std.RegisterLegacyAminoCodec(legacyAmino) + legacytx.RegisterLegacyAminoCodec(legacyAmino) + legacy.RegisterAminoMsg(legacyAmino, &banktypes.MsgSend{}, "cosmos-sdk/MsgSend") + + qc := tx.NewServiceClient(sut.RPCClient(t)) + encodedTx, stdTx := readTestAminoTxBinary(t, legacyAmino) + + invalidTxBytes := append(encodedTx, byte(0o00)) + + testCases := []struct { + name string + req *tx.TxDecodeAminoRequest + expErr bool + expErrMsg string + }{ + {"nil request", nil, true, "request cannot be nil"}, + {"empty request", &tx.TxDecodeAminoRequest{}, true, "invalid empty tx bytes"}, + {"invalid tx bytes", &tx.TxDecodeAminoRequest{AminoBinary: invalidTxBytes}, true, "invalid request"}, + {"valid request with tx bytes", &tx.TxDecodeAminoRequest{AminoBinary: encodedTx}, false, ""}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + res, err := qc.TxDecodeAmino(context.Background(), tc.req) + if tc.expErr { + require.Error(t, err) + require.Contains(t, err.Error(), tc.expErrMsg) + require.Empty(t, res) + } else { + require.NoError(t, err) + require.NotEmpty(t, res.GetAminoJson()) + + var decodedTx legacytx.StdTx + err = legacyAmino.UnmarshalJSON([]byte(res.GetAminoJson()), &decodedTx) + require.NoError(t, err) + require.Equal(t, stdTx.GetMsgs(), decodedTx.GetMsgs()) + } + }) + } +} + +func TestTxDecodeAmino_GRPCGateway(t *testing.T) { + sut.ResetChain(t) + sut.StartChain(t) + + legacyAmino := codec.NewLegacyAmino() + std.RegisterLegacyAminoCodec(legacyAmino) + legacytx.RegisterLegacyAminoCodec(legacyAmino) + legacy.RegisterAminoMsg(legacyAmino, &banktypes.MsgSend{}, "cosmos-sdk/MsgSend") + + baseUrl := sut.APIAddress() + encodedTx, stdTx := readTestAminoTxBinary(t, legacyAmino) + + invalidTxBytes := append(encodedTx, byte(0o00)) + + testCases := []struct { + name string + req *tx.TxDecodeAminoRequest + expErr bool + expErrMsg string + }{ + {"empty request", &tx.TxDecodeAminoRequest{}, true, "invalid empty tx bytes"}, + {"invalid tx bytes", &tx.TxDecodeAminoRequest{AminoBinary: invalidTxBytes}, true, "unmarshal to legacytx.StdTx failed"}, + {"valid request with tx bytes", &tx.TxDecodeAminoRequest{AminoBinary: encodedTx}, false, ""}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + reqBz, err := json.Marshal(tc.req) + require.NoError(t, err) + + res, err := testutil.PostRequest(fmt.Sprintf("%s/cosmos/tx/v1beta1/decode/amino", baseUrl), "application/json", reqBz) + require.NoError(t, err) + if tc.expErr { + require.Contains(t, string(res), tc.expErrMsg) + } else { + var result tx.TxDecodeAminoResponse + err := json.Unmarshal(res, &result) + require.NoError(t, err) + + var decodedTx legacytx.StdTx + err = legacyAmino.UnmarshalJSON([]byte(result.AminoJson), &decodedTx) + require.NoError(t, err) + require.Equal(t, stdTx.GetMsgs(), decodedTx.GetMsgs()) + } + }) + } +} + +func TestSimMultiSigTx(t *testing.T) { + sut.ResetChain(t) + + cli := NewCLIWrapper(t, sut, verbose) + // get validator address + valAddr := cli.GetKeyAddr("node0") + require.NotEmpty(t, valAddr) + + // add new key + _ = cli.AddKey("account1") + _ = cli.AddKey("account2") + + sut.StartChain(t) + + multiSigName := "multisig" + cli.RunCommandWithArgs("keys", "add", multiSigName, "--multisig=account1,account2", "--multisig-threshold=2", "--keyring-backend=test", "--home=./testnet") + multiSigAddr := cli.GetKeyAddr(multiSigName) + + // Send from validator to multisig addr + rsp := cli.Run("tx", "bank", "send", valAddr, multiSigAddr, fmt.Sprintf("%d%s", transferAmount, denom), "--fees=1stake") + txResult, found := cli.AwaitTxCommitted(rsp) + require.True(t, found) + RequireTxSuccess(t, txResult) + + multiSigBalance := cli.QueryBalance(multiSigAddr, denom) + require.Equal(t, multiSigBalance, transferAmount) + + // Send from multisig to validator + // create unsign tx + var newTransferAmount int64 = 100 + bankSendCmdArgs := []string{"tx", "bank", "send", multiSigAddr, valAddr, fmt.Sprintf("%d%s", newTransferAmount, denom), fmt.Sprintf("--chain-id=%s", sut.chainID), "--fees=10stake", "--sign-mode=direct", "--generate-only"} + res := cli.RunCommandWithArgs(bankSendCmdArgs...) + txFile := StoreTempFile(t, []byte(res)) + + res = cli.RunCommandWithArgs("tx", "sign", txFile.Name(), fmt.Sprintf("--from=%s", "account1"), fmt.Sprintf("--multisig=%s", multiSigAddr), fmt.Sprintf("--chain-id=%s", sut.chainID), "--keyring-backend=test", "--home=./testnet") + account1Signed := StoreTempFile(t, []byte(res)) + res = cli.RunCommandWithArgs("tx", "sign", txFile.Name(), fmt.Sprintf("--from=%s", "account2"), fmt.Sprintf("--multisig=%s", multiSigAddr), fmt.Sprintf("--chain-id=%s", sut.chainID), "--keyring-backend=test", "--home=./testnet") + account2Signed := StoreTempFile(t, []byte(res)) + + res = cli.RunCommandWithArgs("tx", "multisign-batch", txFile.Name(), multiSigName, account1Signed.Name(), account2Signed.Name(), fmt.Sprintf("--chain-id=%s", sut.chainID), "--keyring-backend=test", "--home=./testnet") + txSignedFile := StoreTempFile(t, []byte(res)) + + res = cli.Run("tx", "broadcast", txSignedFile.Name()) + RequireTxSuccess(t, res) + + multiSigBalance = cli.QueryBalance(multiSigAddr, denom) + require.Equal(t, multiSigBalance, transferAmount-newTransferAmount-10) +} + +func readTestAminoTxJSON(t *testing.T, aminoCodec *codec.LegacyAmino) ([]byte, *legacytx.StdTx) { + txJSONBytes, err := os.ReadFile("testdata/tx_amino1.json") + require.NoError(t, err) + var stdTx legacytx.StdTx + err = aminoCodec.UnmarshalJSON(txJSONBytes, &stdTx) + require.NoError(t, err) + return txJSONBytes, &stdTx +} + +func readTestAminoTxBinary(t *testing.T, aminoCodec *codec.LegacyAmino) ([]byte, *legacytx.StdTx) { + txJSONBytes, err := os.ReadFile("testdata/tx_amino1.bin") + require.NoError(t, err) + var stdTx legacytx.StdTx + err = aminoCodec.Unmarshal(txJSONBytes, &stdTx) + require.NoError(t, err) + return txJSONBytes, &stdTx +} diff --git a/tools/confix/data/v2-app.toml b/tools/confix/data/v2-app.toml index 842dc0df561b..e478eed3609a 100644 --- a/tools/confix/data/v2-app.toml +++ b/tools/confix/data/v2-app.toml @@ -85,7 +85,7 @@ skip-fast-storage-upgrade = true # Enable enables the application telemetry functionality. When enabled, an in-memory sink is also enabled by default. Operators may also enabled other sinks such as Prometheus. enable = true # Address defines the metrics server address to bind to. -address = 'localhost:1318' +address = 'localhost:1327' # Prefixed with keys to separate services. service-name = '' # Enable prefixing gauge values with hostname. diff --git a/types/mempool/priority_nonce_test.go b/types/mempool/priority_nonce_test.go index 3bfd7e4ba86c..73d61cb9c2e9 100644 --- a/types/mempool/priority_nonce_test.go +++ b/types/mempool/priority_nonce_test.go @@ -540,10 +540,8 @@ func (s *MempoolTestSuite) TestRandomTxOrderManyTimes() { // validateOrder checks that the txs are ordered by priority and nonce // in O(n^2) time by checking each tx against all the other txs func validateOrder(mtxs []sdk.Tx) error { - iterations := 0 var itxs []txSpec for i, mtx := range mtxs { - iterations++ tx := mtx.(testTx) itxs = append(itxs, txSpec{p: int(tx.priority), n: int(tx.nonce), a: tx.address, i: i}) } @@ -556,7 +554,6 @@ func validateOrder(mtxs []sdk.Tx) error { for _, a := range itxs { for _, b := range itxs { - iterations++ // when b is before a // when a is before b @@ -574,7 +571,6 @@ func validateOrder(mtxs []sdk.Tx) error { // find a tx with same sender as b and lower nonce found := false for _, c := range itxs { - iterations++ if c.a.Equals(b.a) && c.n < b.n && c.p <= a.p { found = true break @@ -588,7 +584,6 @@ func validateOrder(mtxs []sdk.Tx) error { } } } - // fmt.Printf("validation in iterations: %d\n", iterations) return nil } diff --git a/x/accounts/README.md b/x/accounts/README.md index 48daac8acb2a..37c09e2630f5 100644 --- a/x/accounts/README.md +++ b/x/accounts/README.md @@ -360,7 +360,9 @@ To implement the `Authentication` interface in x/accounts, an account must expos The key message type for authentication is `MsgAuthenticate`, which is defined in the module's protocol buffer files: -[interfaces/account_abstraction/v1/interface.proto](./proto/cosmos/accounts/interfaces/account_abstraction/v1/interface.proto) +```go reference +https://github.com/cosmos/cosmos-sdk/blob/main/x/accounts/proto/cosmos/accounts/interfaces/account_abstraction/v1/interface.proto#L9-L24 +``` ### Authentication Mechanism diff --git a/x/accounts/defaults/base/go.mod b/x/accounts/defaults/base/go.mod index 69957b5dd4b2..8019839d405a 100644 --- a/x/accounts/defaults/base/go.mod +++ b/x/accounts/defaults/base/go.mod @@ -8,7 +8,7 @@ require ( cosmossdk.io/core v1.0.0-alpha.4 cosmossdk.io/depinject v1.0.0 cosmossdk.io/x/accounts v0.0.0-20240913065641-0064ccbce64e - cosmossdk.io/x/tx v0.13.3 + cosmossdk.io/x/tx v1.0.0-alpha.1 github.com/cosmos/cosmos-sdk v0.53.0 github.com/cosmos/gogoproto v1.7.0 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 diff --git a/x/accounts/defaults/lockup/TUTORIAL.md b/x/accounts/defaults/lockup/TUTORIAL.md index 1a308cbcea7c..f8ff4bdbee43 100644 --- a/x/accounts/defaults/lockup/TUTORIAL.md +++ b/x/accounts/defaults/lockup/TUTORIAL.md @@ -1,14 +1,15 @@ # Using lockup account on Cosmos sdk -* [Setup](#setup) -* [Init](#init) -* [Execution](#execution) +* [Using lockup account on Cosmos sdk](#using-lockup-account-on-cosmos-sdk) + * [Setup](#setup) + * [Init](#init) + * [Execution](#execution) * [Delegate](#delegate) * [Undelegate](#undelegate) * [Withdraw reward](#withdraw-reward) * [Withdraw unlocked token](#withdraw-unlocked-token) * [Send coins](#send-coins) -* [Query](#query) + * [Query](#query) * [Query account info](#query-account-info) * [Query periodic lockup account locking periods](#query-periodic-lockup-account-locking-periods) @@ -207,7 +208,7 @@ To query a lockup account state, we can use the command below: ```bash querycontents=$(cat query.json) -simd tx accounts query $querycontents --from owner +simd tx accounts query $querycontents ``` ### Query account info diff --git a/x/accounts/defaults/lockup/go.mod b/x/accounts/defaults/lockup/go.mod index 315965d73c53..c2d044aee831 100644 --- a/x/accounts/defaults/lockup/go.mod +++ b/x/accounts/defaults/lockup/go.mod @@ -24,7 +24,7 @@ require ( cosmossdk.io/math v1.3.0 cosmossdk.io/schema v0.3.1-0.20240930054013-7c6e0388a3f9 // indirect cosmossdk.io/store v1.1.1-0.20240418092142-896cdf1971bc // indirect - cosmossdk.io/x/tx v0.13.3 // indirect + cosmossdk.io/x/tx v1.0.0-alpha.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect diff --git a/x/accounts/defaults/lockup/v1/tx.pb.go b/x/accounts/defaults/lockup/v1/tx.pb.go index 3ce47aa3b924..eb831479e0fc 100644 --- a/x/accounts/defaults/lockup/v1/tx.pb.go +++ b/x/accounts/defaults/lockup/v1/tx.pb.go @@ -33,14 +33,13 @@ var _ = time.Kitchen // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// MsgInitLockupAccount defines a message that enables creating a lockup -// account. +// MsgInitLockupAccount defines a message that enables creating a lockup account. type MsgInitLockupAccount struct { // owner of the vesting account Owner string `protobuf:"bytes,1,opt,name=owner,proto3" json:"owner,omitempty"` - // end of lockup + // end_time is end of lockup EndTime time.Time `protobuf:"bytes,2,opt,name=end_time,json=endTime,proto3,stdtime" json:"end_time"` - // start of lockup + // start_time is start of lockup StartTime time.Time `protobuf:"bytes,3,opt,name=start_time,json=startTime,proto3,stdtime" json:"start_time"` } diff --git a/x/accounts/defaults/multisig/go.mod b/x/accounts/defaults/multisig/go.mod index 5601d2011c46..5a3151771995 100644 --- a/x/accounts/defaults/multisig/go.mod +++ b/x/accounts/defaults/multisig/go.mod @@ -26,7 +26,7 @@ require ( cosmossdk.io/schema v0.3.1-0.20240930054013-7c6e0388a3f9 // indirect cosmossdk.io/store v1.1.1-0.20240418092142-896cdf1971bc // indirect cosmossdk.io/x/staking v0.0.0-00010101000000-000000000000 // indirect - cosmossdk.io/x/tx v0.13.3 // indirect + cosmossdk.io/x/tx v1.0.0-alpha.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect diff --git a/x/accounts/defaults/multisig/v1/multisig.pb.go b/x/accounts/defaults/multisig/v1/multisig.pb.go index 0cb432c87a54..649a62b27f49 100644 --- a/x/accounts/defaults/multisig/v1/multisig.pb.go +++ b/x/accounts/defaults/multisig/v1/multisig.pb.go @@ -98,8 +98,10 @@ func (VoteOption) EnumDescriptor() ([]byte, []int) { // MsgInit is used to initialize a multisig account. type MsgInit struct { + // members are the members of the multisig account. Members []*Member `protobuf:"bytes,1,rep,name=members,proto3" json:"members,omitempty"` - Config *Config `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"` + // config is the configuration of the multisig account. + Config *Config `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"` } func (m *MsgInit) Reset() { *m = MsgInit{} } @@ -603,8 +605,10 @@ func (m *Member) GetWeight() uint64 { // Config defines the configuration of the multisig account. type Config struct { + // threshold is the minimum weight required for a proposal to pass. Threshold int64 `protobuf:"varint,1,opt,name=threshold,proto3" json:"threshold,omitempty"` - Quorum int64 `protobuf:"varint,2,opt,name=quorum,proto3" json:"quorum,omitempty"` + // quorum is the minimum number of members that need to vote for a proposal to pass. + Quorum int64 `protobuf:"varint,2,opt,name=quorum,proto3" json:"quorum,omitempty"` // voting_period is the duration in seconds for the voting period. VotingPeriod int64 `protobuf:"varint,3,opt,name=voting_period,json=votingPeriod,proto3" json:"voting_period,omitempty"` // revote defines if members can change their vote. @@ -683,12 +687,16 @@ func (m *Config) GetEarlyExecution() bool { // Proposal defines the structure of a proposal. type Proposal struct { - Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` - Summary string `protobuf:"bytes,2,opt,name=summary,proto3" json:"summary,omitempty"` + // title is the title of the proposal. + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + // summary is the summary of the proposal. + Summary string `protobuf:"bytes,2,opt,name=summary,proto3" json:"summary,omitempty"` + // messages are the messages that will be executed Messages []*any.Any `protobuf:"bytes,3,rep,name=messages,proto3" json:"messages,omitempty"` // voting_period_end will be set by the account when the proposal is created. - VotingPeriodEnd int64 `protobuf:"varint,4,opt,name=voting_period_end,json=votingPeriodEnd,proto3" json:"voting_period_end,omitempty"` - Status ProposalStatus `protobuf:"varint,5,opt,name=status,proto3,enum=cosmos.accounts.defaults.multisig.v1.ProposalStatus" json:"status,omitempty"` + VotingPeriodEnd int64 `protobuf:"varint,4,opt,name=voting_period_end,json=votingPeriodEnd,proto3" json:"voting_period_end,omitempty"` + // status is the current status of the proposal. + Status ProposalStatus `protobuf:"varint,5,opt,name=status,proto3,enum=cosmos.accounts.defaults.multisig.v1.ProposalStatus" json:"status,omitempty"` } func (m *Proposal) Reset() { *m = Proposal{} } @@ -881,8 +889,10 @@ var xxx_messageInfo_QueryConfig proto.InternalMessageInfo // QueryConfigResponse returns the config of the account. type QueryConfigResponse struct { + // members are the current members of the account. Members []*Member `protobuf:"bytes,1,rep,name=members,proto3" json:"members,omitempty"` - Config *Config `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"` + // config is the current config of the account. + Config *Config `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"` } func (m *QueryConfigResponse) Reset() { *m = QueryConfigResponse{} } diff --git a/x/accounts/go.mod b/x/accounts/go.mod index 0420c3db5591..4239be9a2ffa 100644 --- a/x/accounts/go.mod +++ b/x/accounts/go.mod @@ -9,7 +9,7 @@ require ( cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29 cosmossdk.io/depinject v1.0.0 cosmossdk.io/x/bank v0.0.0-20240226161501-23359a0b6d91 - cosmossdk.io/x/tx v0.13.3 + cosmossdk.io/x/tx v1.0.0-alpha.1 github.com/cosmos/cosmos-sdk v0.53.0 github.com/cosmos/gogoproto v1.7.0 github.com/spf13/cobra v1.8.1 diff --git a/x/accounts/keeper.go b/x/accounts/keeper.go index fee356a7736f..003e55715fb0 100644 --- a/x/accounts/keeper.go +++ b/x/accounts/keeper.go @@ -10,6 +10,7 @@ import ( gogoproto "github.com/cosmos/gogoproto/proto" + _ "cosmossdk.io/api/cosmos/accounts/defaults/base/v1" // import for side-effects "cosmossdk.io/collections" "cosmossdk.io/core/address" "cosmossdk.io/core/appmodule" diff --git a/x/accounts/module.go b/x/accounts/module.go index 1ed89d87d8dd..f7958240b7b5 100644 --- a/x/accounts/module.go +++ b/x/accounts/module.go @@ -42,21 +42,21 @@ type AppModule struct { k Keeper } -func (m AppModule) IsAppModule() {} +func (AppModule) IsAppModule() {} // Name returns the module's name. // Deprecated: kept for legacy reasons. -func (AppModule) Name() string { return ModuleName } +func (am AppModule) Name() string { return ModuleName } -func (m AppModule) RegisterInterfaces(registrar registry.InterfaceRegistrar) { +func (AppModule) RegisterInterfaces(registrar registry.InterfaceRegistrar) { msgservice.RegisterMsgServiceDesc(registrar, v1.MsgServiceDesc()) } // App module services -func (m AppModule) RegisterServices(registar grpc.ServiceRegistrar) error { - v1.RegisterQueryServer(registar, NewQueryServer(m.k)) - v1.RegisterMsgServer(registar, NewMsgServer(m.k)) +func (am AppModule) RegisterServices(registrar grpc.ServiceRegistrar) error { + v1.RegisterQueryServer(registrar, NewQueryServer(am.k)) + v1.RegisterMsgServer(registrar, NewMsgServer(am.k)) return nil } diff --git a/x/accounts/proto/cosmos/accounts/defaults/lockup/v1/tx.proto b/x/accounts/proto/cosmos/accounts/defaults/lockup/v1/tx.proto index e76b0e1e2c46..980cc90c5307 100644 --- a/x/accounts/proto/cosmos/accounts/defaults/lockup/v1/tx.proto +++ b/x/accounts/proto/cosmos/accounts/defaults/lockup/v1/tx.proto @@ -12,22 +12,17 @@ import "google/protobuf/timestamp.proto"; option go_package = "cosmossdk.io/x/accounts/defaults/lockup/v1"; -//-------------------------------------- INIT -------------------------------------- - -// MsgInitLockupAccount defines a message that enables creating a lockup -// account. +// MsgInitLockupAccount defines a message that enables creating a lockup account. message MsgInitLockupAccount { - option (amino.name) = "cosmos-sdk/MsgInitLockupAccount"; - + option (amino.name) = "cosmos-sdk/MsgInitLockupAccount"; option (gogoproto.equal) = true; // owner of the vesting account string owner = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; - - // end of lockup + // end_time is end of lockup google.protobuf.Timestamp end_time = 2 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true, (gogoproto.stdtime) = true]; - // start of lockup + // start_time is start of lockup google.protobuf.Timestamp start_time = 3 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true, (gogoproto.stdtime) = true]; } @@ -38,8 +33,7 @@ message MsgInitLockupAccountResponse {} // MsgInitPeriodicLockingAccount defines a message that enables creating a periodic locking // account. message MsgInitPeriodicLockingAccount { - option (amino.name) = "cosmos-sdk/MsgInitPeriodLockupAccount"; - + option (amino.name) = "cosmos-sdk/MsgInitPeriodLockupAccount"; option (gogoproto.equal) = false; // owner of the lockup account @@ -56,8 +50,7 @@ message MsgInitPeriodicLockingAccountResponse {} // MsgDelegate defines a message that enable lockup account to execute delegate message message MsgDelegate { - option (cosmos.msg.v1.signer) = "sender"; - + option (cosmos.msg.v1.signer) = "sender"; option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; @@ -69,8 +62,7 @@ message MsgDelegate { // MsgUndelegate defines a message that enable lockup account to execute undelegate message message MsgUndelegate { - option (cosmos.msg.v1.signer) = "sender"; - + option (cosmos.msg.v1.signer) = "sender"; option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; @@ -81,8 +73,7 @@ message MsgUndelegate { // MsgWithdrawReward defines a message that enable lockup account to execute withdraw reward message message MsgWithdrawReward { - option (cosmos.msg.v1.signer) = "sender"; - + option (cosmos.msg.v1.signer) = "sender"; option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; @@ -92,8 +83,7 @@ message MsgWithdrawReward { // MsgSend defines a message that enable lockup account to execute send message message MsgSend { - option (cosmos.msg.v1.signer) = "sender"; - + option (cosmos.msg.v1.signer) = "sender"; option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; @@ -115,8 +105,7 @@ message MsgExecuteMessagesResponse { // MsgWithdraw defines a message that the owner of the lockup can perform to withdraw unlocked token to an account of // choice message MsgWithdraw { - option (cosmos.msg.v1.signer) = "withdrawer"; - + option (cosmos.msg.v1.signer) = "withdrawer"; option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; diff --git a/x/accounts/proto/cosmos/accounts/defaults/multisig/v1/multisig.proto b/x/accounts/proto/cosmos/accounts/defaults/multisig/v1/multisig.proto index 0d4a51e4dfe9..dd425b253e55 100644 --- a/x/accounts/proto/cosmos/accounts/defaults/multisig/v1/multisig.proto +++ b/x/accounts/proto/cosmos/accounts/defaults/multisig/v1/multisig.proto @@ -9,8 +9,10 @@ option go_package = "cosmossdk.io/x/accounts/defaults/multisig/v1"; // MsgInit is used to initialize a multisig account. message MsgInit { + // members are the members of the multisig account. repeated Member members = 1; - Config config = 2; + // config is the configuration of the multisig account. + Config config = 2; } // MsgInitResponse is the response returned after account initialization. @@ -68,8 +70,10 @@ message Member { // Config defines the configuration of the multisig account. message Config { + // threshold is the minimum weight required for a proposal to pass. int64 threshold = 1; + // quorum is the minimum number of members that need to vote for a proposal to pass. int64 quorum = 2; // voting_period is the duration in seconds for the voting period. @@ -84,13 +88,19 @@ message Config { // Proposal defines the structure of a proposal. message Proposal { - string title = 1; - string summary = 2; + // title is the title of the proposal. + string title = 1; + + // summary is the summary of the proposal. + string summary = 2; + + // messages are the messages that will be executed repeated google.protobuf.Any messages = 3; // voting_period_end will be set by the account when the proposal is created. int64 voting_period_end = 4; + // status is the current status of the proposal. ProposalStatus status = 5; } @@ -108,8 +118,10 @@ message QueryConfig {} // QueryConfigResponse returns the config of the account. message QueryConfigResponse { + // members are the current members of the account. repeated Member members = 1; + // config is the current config of the account. Config config = 2; } diff --git a/x/authz/go.mod b/x/authz/go.mod index b75000dc56ee..8f2324c6f906 100644 --- a/x/authz/go.mod +++ b/x/authz/go.mod @@ -12,7 +12,7 @@ require ( cosmossdk.io/store v1.1.1-0.20240418092142-896cdf1971bc cosmossdk.io/x/bank v0.0.0-20240226161501-23359a0b6d91 cosmossdk.io/x/staking v0.0.0-00010101000000-000000000000 - cosmossdk.io/x/tx v0.13.3 + cosmossdk.io/x/tx v1.0.0-alpha.1 github.com/cosmos/cosmos-proto v1.0.0-beta.5 github.com/cosmos/cosmos-sdk v0.53.0 github.com/cosmos/gogoproto v1.7.0 diff --git a/x/bank/go.mod b/x/bank/go.mod index 57885f75d54b..b273bff86cd5 100644 --- a/x/bank/go.mod +++ b/x/bank/go.mod @@ -32,7 +32,7 @@ require ( buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.35.1-20240130113600-88ef6483f90f.1 // indirect cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29 cosmossdk.io/x/staking v0.0.0-00010101000000-000000000000 // indirect - cosmossdk.io/x/tx v0.13.3 // indirect + cosmossdk.io/x/tx v1.0.0-alpha.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect diff --git a/x/circuit/autocli.go b/x/circuit/autocli.go index e9cc67701cf7..a1cb8ada74e6 100644 --- a/x/circuit/autocli.go +++ b/x/circuit/autocli.go @@ -43,7 +43,7 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { "SOME_MSGS" = 1, "ALL_MSGS" = 2, "SUPER_ADMIN" = 3,`, - Example: fmt.Sprintf(`%s tx circuit authorize [address] '{"level":1,"limit_type_urls":["/cosmos.bank.v1beta1.MsgSend, /cosmos.bank.v1beta1.MsgMultiSend"]}'"`, version.AppName), + Example: fmt.Sprintf(`%s tx circuit authorize [address] '{"level":1,"limit_type_urls":["/cosmos.bank.v1beta1.MsgSend", "/cosmos.bank.v1beta1.MsgMultiSend"]}'"`, version.AppName), PositionalArgs: []*autocliv1.PositionalArgDescriptor{ {ProtoField: "grantee"}, {ProtoField: "permissions"}, // TODO(@julienrbrt) Support flattening msg for setting each field as a positional arg diff --git a/x/circuit/go.mod b/x/circuit/go.mod index 8b62a92892a3..cc7bbefe172e 100644 --- a/x/circuit/go.mod +++ b/x/circuit/go.mod @@ -27,7 +27,7 @@ require ( cosmossdk.io/schema v0.3.1-0.20240930054013-7c6e0388a3f9 // indirect cosmossdk.io/x/bank v0.0.0-20240226161501-23359a0b6d91 // indirect cosmossdk.io/x/staking v0.0.0-00010101000000-000000000000 // indirect - cosmossdk.io/x/tx v0.13.3 // indirect + cosmossdk.io/x/tx v1.0.0-alpha.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect diff --git a/x/consensus/go.mod b/x/consensus/go.mod index d7d18f611e58..d8dd49174c58 100644 --- a/x/consensus/go.mod +++ b/x/consensus/go.mod @@ -30,7 +30,7 @@ require ( cosmossdk.io/schema v0.3.1-0.20240930054013-7c6e0388a3f9 // indirect cosmossdk.io/x/bank v0.0.0-20240226161501-23359a0b6d91 // indirect cosmossdk.io/x/staking v0.0.0-00010101000000-000000000000 // indirect - cosmossdk.io/x/tx v0.13.3 // indirect + cosmossdk.io/x/tx v1.0.0-alpha.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect diff --git a/x/distribution/go.mod b/x/distribution/go.mod index ed454d5c31b3..fb69978f928f 100644 --- a/x/distribution/go.mod +++ b/x/distribution/go.mod @@ -31,7 +31,7 @@ require ( cosmossdk.io/log v1.4.1 // indirect cosmossdk.io/schema v0.3.1-0.20240930054013-7c6e0388a3f9 // indirect cosmossdk.io/x/bank v0.0.0-20240226161501-23359a0b6d91 // indirect - cosmossdk.io/x/tx v0.13.3 // indirect + cosmossdk.io/x/tx v1.0.0-alpha.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect diff --git a/x/epochs/go.mod b/x/epochs/go.mod index 7fc714002adb..5fbb1647d68d 100644 --- a/x/epochs/go.mod +++ b/x/epochs/go.mod @@ -29,7 +29,7 @@ require ( cosmossdk.io/math v1.3.0 // indirect cosmossdk.io/x/bank v0.0.0-20240226161501-23359a0b6d91 // indirect cosmossdk.io/x/staking v0.0.0-00010101000000-000000000000 // indirect - cosmossdk.io/x/tx v0.13.3 // indirect + cosmossdk.io/x/tx v1.0.0-alpha.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect diff --git a/x/evidence/go.mod b/x/evidence/go.mod index 25e2d8221dea..2db9245de044 100644 --- a/x/evidence/go.mod +++ b/x/evidence/go.mod @@ -31,7 +31,7 @@ require ( cosmossdk.io/schema v0.3.1-0.20240930054013-7c6e0388a3f9 // indirect cosmossdk.io/x/bank v0.0.0-20240226161501-23359a0b6d91 // indirect cosmossdk.io/x/staking v0.0.0-00010101000000-000000000000 // indirect - cosmossdk.io/x/tx v0.13.3 // indirect + cosmossdk.io/x/tx v1.0.0-alpha.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect diff --git a/x/feegrant/go.mod b/x/feegrant/go.mod index 3871cf57139b..4f1975c00166 100644 --- a/x/feegrant/go.mod +++ b/x/feegrant/go.mod @@ -40,7 +40,7 @@ require ( cosmossdk.io/schema v0.3.1-0.20240930054013-7c6e0388a3f9 // indirect cosmossdk.io/x/protocolpool v0.0.0-20230925135524-a1bc045b3190 // indirect cosmossdk.io/x/staking v0.0.0-00010101000000-000000000000 // indirect - cosmossdk.io/x/tx v0.13.3 // indirect + cosmossdk.io/x/tx v1.0.0-alpha.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect diff --git a/x/gov/go.mod b/x/gov/go.mod index 05115ce30964..9d37de53be7a 100644 --- a/x/gov/go.mod +++ b/x/gov/go.mod @@ -36,7 +36,7 @@ require ( buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.35.1-20240701160653-fedbb9acfd2f.1 // indirect buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.35.1-20240130113600-88ef6483f90f.1 // indirect cosmossdk.io/schema v0.3.1-0.20240930054013-7c6e0388a3f9 // indirect - cosmossdk.io/x/tx v0.13.3 // indirect + cosmossdk.io/x/tx v1.0.0-alpha.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect diff --git a/x/group/go.mod b/x/group/go.mod index 8883eefcc238..8e48243d5ec9 100644 --- a/x/group/go.mod +++ b/x/group/go.mod @@ -40,7 +40,7 @@ require ( cosmossdk.io/collections v0.4.0 // indirect cosmossdk.io/schema v0.3.1-0.20240930054013-7c6e0388a3f9 // indirect cosmossdk.io/x/epochs v0.0.0-20240522060652-a1ae4c3e0337 // indirect - cosmossdk.io/x/tx v0.13.3 // indirect + cosmossdk.io/x/tx v1.0.0-alpha.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect diff --git a/x/mint/go.mod b/x/mint/go.mod index 72eb389ca4b0..1cad7f554413 100644 --- a/x/mint/go.mod +++ b/x/mint/go.mod @@ -32,7 +32,7 @@ require ( cosmossdk.io/schema v0.3.1-0.20240930054013-7c6e0388a3f9 // indirect cosmossdk.io/x/bank v0.0.0-20240226161501-23359a0b6d91 // indirect cosmossdk.io/x/staking v0.0.0-00010101000000-000000000000 // indirect - cosmossdk.io/x/tx v0.13.3 // indirect + cosmossdk.io/x/tx v1.0.0-alpha.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect diff --git a/x/nft/go.mod b/x/nft/go.mod index a7850b4196a1..77536d1b8a3d 100644 --- a/x/nft/go.mod +++ b/x/nft/go.mod @@ -29,7 +29,7 @@ require ( cosmossdk.io/schema v0.3.1-0.20240930054013-7c6e0388a3f9 // indirect cosmossdk.io/x/bank v0.0.0-20240226161501-23359a0b6d91 // indirect cosmossdk.io/x/staking v0.0.0-00010101000000-000000000000 // indirect - cosmossdk.io/x/tx v0.13.3 // indirect + cosmossdk.io/x/tx v1.0.0-alpha.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect diff --git a/x/params/go.mod b/x/params/go.mod index f80ffacf7580..8357b46db57b 100644 --- a/x/params/go.mod +++ b/x/params/go.mod @@ -30,7 +30,7 @@ require ( buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.35.1-20240130113600-88ef6483f90f.1 // indirect cosmossdk.io/collections v0.4.0 // indirect cosmossdk.io/schema v0.3.1-0.20240930054013-7c6e0388a3f9 // indirect - cosmossdk.io/x/tx v0.13.3 // indirect + cosmossdk.io/x/tx v1.0.0-alpha.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect diff --git a/x/protocolpool/go.mod b/x/protocolpool/go.mod index 386dc1672dbc..e3ef7efb1957 100644 --- a/x/protocolpool/go.mod +++ b/x/protocolpool/go.mod @@ -30,7 +30,7 @@ require ( cosmossdk.io/schema v0.3.1-0.20240930054013-7c6e0388a3f9 // indirect cosmossdk.io/x/bank v0.0.0-20240226161501-23359a0b6d91 // indirect cosmossdk.io/x/staking v0.0.0-00010101000000-000000000000 // indirect - cosmossdk.io/x/tx v0.13.3 // indirect + cosmossdk.io/x/tx v1.0.0-alpha.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect diff --git a/x/slashing/go.mod b/x/slashing/go.mod index aa7ff1650254..ff10738fdf0f 100644 --- a/x/slashing/go.mod +++ b/x/slashing/go.mod @@ -32,7 +32,7 @@ require ( cosmossdk.io/log v1.4.1 // indirect cosmossdk.io/schema v0.3.1-0.20240930054013-7c6e0388a3f9 // indirect cosmossdk.io/x/bank v0.0.0-20240226161501-23359a0b6d91 // indirect - cosmossdk.io/x/tx v0.13.3 // indirect + cosmossdk.io/x/tx v1.0.0-alpha.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect diff --git a/x/staking/go.mod b/x/staking/go.mod index 902634281cd4..f93e1618ee9c 100644 --- a/x/staking/go.mod +++ b/x/staking/go.mod @@ -31,7 +31,7 @@ require ( require ( buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.35.1-20240130113600-88ef6483f90f.1 // indirect cosmossdk.io/x/bank v0.0.0-20240226161501-23359a0b6d91 // indirect - cosmossdk.io/x/tx v0.13.3 // indirect + cosmossdk.io/x/tx v1.0.0-alpha.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect diff --git a/x/staking/keeper/query_utils.go b/x/staking/keeper/query_utils.go index 625984dbd44a..ee0b042b8433 100644 --- a/x/staking/keeper/query_utils.go +++ b/x/staking/keeper/query_utils.go @@ -65,12 +65,9 @@ func (k Keeper) GetDelegatorValidator( func (k Keeper) GetAllDelegatorDelegations(ctx context.Context, delegator sdk.AccAddress) ([]types.Delegation, error) { delegations := make([]types.Delegation, 0) - var i int64 rng := collections.NewPrefixedPairRange[sdk.AccAddress, sdk.ValAddress](delegator) err := k.Delegations.Walk(ctx, rng, func(key collections.Pair[sdk.AccAddress, sdk.ValAddress], del types.Delegation) (stop bool, err error) { delegations = append(delegations, del) - i++ - return false, nil }) if err != nil { diff --git a/x/upgrade/go.mod b/x/upgrade/go.mod index e775340906f8..21bde3f38dec 100644 --- a/x/upgrade/go.mod +++ b/x/upgrade/go.mod @@ -45,7 +45,7 @@ require ( cosmossdk.io/schema v0.3.1-0.20240930054013-7c6e0388a3f9 // indirect cosmossdk.io/x/bank v0.0.0-20240226161501-23359a0b6d91 // indirect cosmossdk.io/x/staking v0.0.0-00010101000000-000000000000 // indirect - cosmossdk.io/x/tx v0.13.3 // indirect + cosmossdk.io/x/tx v1.0.0-alpha.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect