Skip to content

Commit e2c7604

Browse files
refactor(client): change flag for unordered tx timeouts (#24561)
1 parent 03e534a commit e2c7604

File tree

6 files changed

+46
-25
lines changed

6 files changed

+46
-25
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
6666

6767
### Improvements
6868

69+
* (client) [#24561](https://github.com/cosmos/cosmos-sdk/pull/24561) TimeoutTimestamp flag has been changed to TimeoutDuration, which now sets the timeout timestamp of unordered transactions to the current time + duration passed.
6970
* (telemetry) [#24541](https://github.com/cosmos/cosmos-sdk/pull/24541) Telemetry now includes a pre_blocker metric key. x/upgrade should migrate to this key in v0.54.0.
7071
* (x/auth) [#24541](https://github.com/cosmos/cosmos-sdk/pull/24541) x/auth's PreBlocker now emits telemetry under the pre_blocker metric key.
7172
* (x/bank) [#24431](https://github.com/cosmos/cosmos-sdk/pull/24431) Reduce the number of `ValidateDenom` calls in `bank.SendCoins` and `Coin`.

client/flags/flags.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ const (
7474
FlagOffset = "offset"
7575
FlagCountTotal = "count-total"
7676
FlagTimeoutHeight = "timeout-height"
77-
FlagTimeoutTimestamp = "timeout-timestamp"
77+
TimeoutDuration = "timeout-duration"
7878
FlagUnordered = "unordered"
7979
FlagKeyAlgorithm = "algo"
8080
FlagKeyType = "key-type"
@@ -137,9 +137,9 @@ func AddTxFlagsToCmd(cmd *cobra.Command) {
137137
f.Bool(FlagOffline, false, "Offline mode (does not allow any online functionality)")
138138
f.BoolP(FlagSkipConfirmation, "y", false, "Skip tx broadcasting prompt confirmation")
139139
f.String(FlagSignMode, "", "Choose sign mode (direct|amino-json|direct-aux|textual), this is an advanced feature")
140-
f.Uint64(FlagTimeoutHeight, 0, "DEPRECATED: Please use --timeout-timestamp instead. Set a block timeout height to prevent the tx from being committed past a certain height")
141-
f.Int64(FlagTimeoutTimestamp, 0, "Set a block timeout timestamp to prevent the tx from being committed past a certain time")
142-
f.Bool(FlagUnordered, false, "Enable unordered transaction delivery; must be used in conjunction with --timeout-timestamp")
140+
f.Uint64(FlagTimeoutHeight, 0, "DEPRECATED: Please use --timeout-duration instead. Set a block timeout height to prevent the tx from being committed past a certain height")
141+
f.Duration(TimeoutDuration, 0, "TimeoutDuration is the duration the transaction will be considered valid in the mempool. The transaction's unordered nonce will be set to the time of transaction creation + the duration value passed. If the transaction is still in the mempool, and the block time has passed the time of submission + TimeoutTimestamp, the transaction will be rejected.")
142+
f.Bool(FlagUnordered, false, "Enable unordered transaction delivery; must be used in conjunction with --timeout-duration")
143143
f.String(FlagFeePayer, "", "Fee payer pays fees for the transaction instead of deducting from the signer")
144144
f.String(FlagFeeGranter, "", "Fee granter grants fees for the transaction")
145145
f.String(FlagTip, "", "Tip is the amount that is going to be transferred to the fee payer on the target chain. This flag is only valid when used with --aux, and is ignored if the target chain didn't enable the TipDecorator")
@@ -149,8 +149,8 @@ func AddTxFlagsToCmd(cmd *cobra.Command) {
149149
f.String(FlagGas, "", fmt.Sprintf("gas limit to set per-transaction; set to %q to calculate sufficient gas automatically. Note: %q option doesn't always report accurate results. Set a valid coin value to adjust the result. Can be used instead of %q. (default %d)",
150150
GasFlagAuto, GasFlagAuto, FlagFees, DefaultGasLimit))
151151

152-
cmd.MarkFlagsMutuallyExclusive(FlagTimeoutHeight, FlagTimeoutTimestamp)
153-
cmd.MarkFlagsRequiredTogether(FlagUnordered, FlagTimeoutTimestamp)
152+
cmd.MarkFlagsMutuallyExclusive(FlagTimeoutHeight, TimeoutDuration)
153+
cmd.MarkFlagsRequiredTogether(FlagUnordered, TimeoutDuration)
154154

155155
AddKeyringFlags(f)
156156
}

client/tx/factory.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,11 @@ func NewFactoryCLI(clientCtx client.Context, flagSet *pflag.FlagSet) (Factory, e
8888

8989
gasAdj := clientCtx.Viper.GetFloat64(flags.FlagGasAdjustment)
9090
memo := clientCtx.Viper.GetString(flags.FlagNote)
91-
timestampUnix := clientCtx.Viper.GetInt64(flags.FlagTimeoutTimestamp)
92-
timeoutTimestamp := time.Unix(timestampUnix, 0)
91+
timeout := clientCtx.Viper.GetDuration(flags.TimeoutDuration)
92+
var timeoutTimestamp time.Time
93+
if timeout > 0 {
94+
timeoutTimestamp = time.Now().Add(timeout)
95+
}
9396
timeoutHeight := clientCtx.Viper.GetUint64(flags.FlagTimeoutHeight)
9497
unordered := clientCtx.Viper.GetBool(flags.FlagUnordered)
9598

docs/docs/learn/beginner/01-tx-lifecycle.md

+9-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,15 @@ Additionally, there are several [flags](../advanced/07-cli.md) users can use to
3939

4040
The ultimate value of the fees paid is equal to the gas multiplied by the gas prices. In other words, `fees = ceil(gas * gasPrices)`. Thus, since fees can be calculated using gas prices and vice versa, the users specify only one of the two.
4141

42-
Later, validators decide whether or not to include the transaction in their block by comparing the given or calculated `gas-prices` to their local `min-gas-prices`. `Tx` is rejected if its `gas-prices` is not high enough, so users are incentivized to pay more.
42+
Later, validators decide whether to include the transaction in their block by comparing the given or calculated `gas-prices` to their local `min-gas-prices`. `Tx` is rejected if its `gas-prices` is not high enough, so users are incentivized to pay more.
43+
44+
#### Unordered Transactions
45+
46+
With Cosmos SDK v0.53.0, users may send unordered transactions to chains that have this feature enabled.
47+
The following flags allow a user to build an unordered transaction from the CLI.
48+
49+
* `--unordered` specifies that this transaction should be unordered.
50+
* `--timeout-duration` specifies the amount of time the unordered transaction should be valid in the mempool. The transaction's unordered nonce will be set to the time of transaction creation + timeout duration.
4351

4452
#### CLI Example
4553

systemtests/cli.go

+1
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ func (c CLIWrapper) RunAndWait(args ...string) string {
195195
// RunCommandWithArgs use for run cli command, not tx
196196
func (c CLIWrapper) RunCommandWithArgs(args ...string) string {
197197
c.t.Helper()
198+
args = c.WithKeyringFlags(args...)
198199
execOutput, _ := c.run(args)
199200
return execOutput
200201
}

tests/systemtests/unordered_tx_test.go

+24-16
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,19 @@ import (
77
"testing"
88
"time"
99

10-
"github.com/stretchr/testify/assert"
1110
"github.com/stretchr/testify/require"
1211
"github.com/tidwall/gjson"
1312

1413
systest "cosmossdk.io/systemtests"
14+
15+
"github.com/cosmos/cosmos-sdk/testutil"
1516
)
1617

1718
func TestUnorderedTXDuplicate(t *testing.T) {
1819
// scenario: test unordered tx duplicate
1920
// given a running chain with a tx in the unordered tx pool
20-
// when a new tx with the same hash is broadcasted
21-
// then the new tx should be rejected
21+
// when a new tx with the same unordered nonce is broadcasted,
22+
// then the new tx should be rejected.
2223

2324
systest.Sut.ResetChain(t)
2425
cli := systest.NewCLIWrapper(t, systest.Sut, systest.Verbose)
@@ -31,22 +32,29 @@ func TestUnorderedTXDuplicate(t *testing.T) {
3132

3233
systest.Sut.StartChain(t)
3334

34-
timeoutTimestamp := time.Now().Add(time.Minute)
3535
// send tokens
36-
cmd := []string{"tx", "bank", "send", account1Addr, account2Addr, "5000stake", "--from=" + account1Addr, "--fees=1stake", fmt.Sprintf("--timeout-timestamp=%v", timeoutTimestamp.Unix()), "--unordered", "--sequence=1", "--note=1"}
37-
rsp1 := cli.Run(cmd...)
36+
cmd := []string{"tx", "bank", "send", account1Addr, account2Addr, "5000stake", "--from=" + account1Addr, "--fees=1stake", "--timeout-duration=5m", "--unordered", "--note=1", "--chain-id=testing", "--generate-only"}
37+
rsp1 := cli.RunCommandWithArgs(cmd...)
38+
txFile := testutil.TempFile(t)
39+
_, err := txFile.WriteString(rsp1)
40+
require.NoError(t, err)
41+
42+
signCmd := []string{"tx", "sign", txFile.Name(), "--from=" + account1Addr, "--chain-id=testing"}
43+
rsp1 = cli.RunCommandWithArgs(signCmd...)
44+
signedFile := testutil.TempFile(t)
45+
_, err = signedFile.WriteString(rsp1)
46+
require.NoError(t, err)
47+
48+
cmd = []string{"tx", "broadcast", signedFile.Name(), "--chain-id=testing"}
49+
rsp1 = cli.RunCommandWithArgs(cmd...)
3850
systest.RequireTxSuccess(t, rsp1)
3951

40-
assertDuplicateErr := func(xt assert.TestingT, gotErr error, gotOutputs ...interface{}) bool {
41-
require.Len(t, gotOutputs, 1)
42-
output := gotOutputs[0].(string)
43-
code := gjson.Get(output, "code")
44-
require.True(t, code.Exists())
45-
require.Equal(t, int64(19), code.Int()) // 19 == already in mempool.
46-
return false // always abort
47-
}
48-
rsp2 := cli.WithRunErrorMatcher(assertDuplicateErr).Run(cmd...)
52+
cmd = []string{"tx", "broadcast", signedFile.Name(), "--chain-id=testing"}
53+
rsp2, _ := cli.RunOnly(cmd...)
4954
systest.RequireTxFailure(t, rsp2)
55+
code := gjson.Get(rsp2, "code")
56+
require.True(t, code.Exists())
57+
require.Equal(t, int64(19), code.Int())
5058

5159
require.Eventually(t, func() bool {
5260
return cli.QueryBalance(account2Addr, "stake") == 5000
@@ -86,7 +94,7 @@ func TestTxBackwardsCompatability(t *testing.T) {
8694
code := gjson.Get(response, "code").Int()
8795
require.Equal(t, int64(0), code)
8896

89-
bankSendCmdArgs = []string{"tx", "bank", "send", senderAddr, valAddr, fmt.Sprintf("%d%s", transferAmount, denom), "--chain-id=" + v50CLI.ChainID(), "--fees=10stake", "--sign-mode=direct", "--unordered", "--timeout-timestamp=10000"}
97+
bankSendCmdArgs = []string{"tx", "bank", "send", senderAddr, valAddr, fmt.Sprintf("%d%s", transferAmount, denom), "--chain-id=" + v50CLI.ChainID(), "--fees=10stake", "--sign-mode=direct", "--unordered", "--timeout-duration=8m"}
9098
res, ok = v53CLI.RunOnly(bankSendCmdArgs...)
9199
require.True(t, ok)
92100

0 commit comments

Comments
 (0)