Skip to content
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
f30c29b
backport unordered tx
technicallyty Feb 14, 2025
f0d0d04
fix test
technicallyty Feb 14, 2025
c28ae02
Fix test
technicallyty Feb 14, 2025
17b8543
Merge branch 'release/v0.53.x' into technicallyty/backport-6ec53aaf54…
technicallyty Feb 14, 2025
f9b42d8
update go mod
technicallyty Feb 14, 2025
fa6c344
Merge branch 'release/v0.53.x' into technicallyty/backport-6ec53aaf54…
technicallyty Feb 14, 2025
e254223
feat: [ADR-070] Unordered Transactions (1/2) (#18641)
alexanderbez Jan 4, 2024
ff6063f
import ordering
technicallyty Feb 15, 2025
c56005b
changelog and upgrading
technicallyty Feb 15, 2025
77a4db0
Merge branch 'release/v0.53.x' into technicallyty/backport-6ec53aaf54…
technicallyty Feb 21, 2025
daf1ce6
Merge branch 'release/v0.53.x' into technicallyty/backport-6ec53aaf54…
technicallyty Feb 24, 2025
73aa638
Merge branch 'release/v0.53.x' into technicallyty/backport-6ec53aaf54…
technicallyty Feb 25, 2025
e4fce16
Merge branch 'release/v0.53.x' into technicallyty/backport-6ec53aaf54…
technicallyty Feb 26, 2025
0272e5e
add changelog entry
technicallyty Feb 26, 2025
f815582
remove upgrading for now
technicallyty Feb 26, 2025
4572229
make upgrading.md for v53
technicallyty Feb 26, 2025
b754f48
fix(unorderedtx): issues reported in audit (#21467) (#23727)
technicallyty Feb 26, 2025
426c38d
Merge branch 'release/v0.53.x' into technicallyty/backport-6ec53aaf54…
technicallyty Feb 26, 2025
6274a10
make unordered and timeouttimestamp required together
technicallyty Feb 26, 2025
926b02b
revise adr
technicallyty Feb 26, 2025
9188d9e
lint fixes, proto comment fix
technicallyty Feb 26, 2025
f1cd89f
Merge branch 'release/v0.53.x' into technicallyty/backport-6ec53aaf54…
technicallyty Feb 26, 2025
7f8c878
fix sigverify business and restore ante handlers
technicallyty Feb 26, 2025
70a67aa
Merge branch 'release/v0.53.x' into technicallyty/backport-6ec53aaf54…
Feb 27, 2025
1b6d687
optional utx
technicallyty Feb 27, 2025
43c8f5c
Merge branch 'technicallyty/backport-6ec53aaf54-unorderedtx-part-1' o…
technicallyty Feb 27, 2025
af456e8
changelog
technicallyty Feb 27, 2025
e58306f
fix test
technicallyty Feb 27, 2025
1fd8c3d
linter
technicallyty Feb 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 64 additions & 62 deletions CHANGELOG.md

Large diffs are not rendered by default.

587 changes: 97 additions & 490 deletions UPGRADING.md

Large diffs are not rendered by default.

554 changes: 367 additions & 187 deletions api/cosmos/tx/v1beta1/tx.pulsar.go

Large diffs are not rendered by default.

87 changes: 48 additions & 39 deletions baseapp/abci_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
)

type (
// ValidatorStore defines the interface contract require for verifying vote
// ValidatorStore defines the interface contract required for verifying vote
// extension signatures. Typically, this will be implemented by the x/staking
// module, which has knowledge of the CometBFT public key.
ValidatorStore interface {
Expand Down Expand Up @@ -83,7 +83,7 @@ func ValidateVoteExtensions(
totalVP += vote.Validator.Power

// Only check + include power if the vote is a commit vote. There must be super-majority, otherwise the
// previous block (the block vote is for) could not have been committed.
// previous block (the block the vote is for) could not have been committed.
if vote.BlockIdFlag != cmtproto.BlockIDFlagCommit {
continue
}
Expand Down Expand Up @@ -286,35 +286,41 @@ func (h *DefaultProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHan
invalidTxs []sdk.Tx // invalid txs to be removed out of the loop to avoid dead lock
)
mempool.SelectBy(ctx, h.mempool, req.Txs, func(memTx sdk.Tx) bool {
signerData, err := h.signerExtAdapter.GetSigners(memTx)
if err != nil {
// propagate the error to the caller
resError = err
return false
}

// If the signers aren't in selectedTxsSignersSeqs then we haven't seen them before
// so we add them and continue given that we don't need to check the sequence.
shouldAdd := true
unorderedTx, ok := memTx.(sdk.TxWithUnordered)
isUnordered := ok && unorderedTx.GetUnordered()
txSignersSeqs := make(map[string]uint64)
for _, signer := range signerData {
seq, ok := selectedTxsSignersSeqs[signer.Signer.String()]
if !ok {
txSignersSeqs[signer.Signer.String()] = signer.Sequence
continue

// if the tx is unordered, we don't need to check the sequence, we just add it
if !isUnordered {
signerData, err := h.signerExtAdapter.GetSigners(memTx)
if err != nil {
// propagate the error to the caller
resError = err
return false
}

// If we have seen this signer before in this block, we must make
// sure that the current sequence is seq+1; otherwise is invalid
// and we skip it.
if seq+1 != signer.Sequence {
shouldAdd = false
break
// If the signers aren't in selectedTxsSignersSeqs then we haven't seen them before
// so we add them and continue given that we don't need to check the sequence.
shouldAdd := true
for _, signer := range signerData {
seq, ok := selectedTxsSignersSeqs[signer.Signer.String()]
if !ok {
txSignersSeqs[signer.Signer.String()] = signer.Sequence
continue
}

// If we have seen this signer before in this block, we must make
// sure that the current sequence is seq+1; otherwise is invalid
// and we skip it.
if seq+1 != signer.Sequence {
shouldAdd = false
break
}
txSignersSeqs[signer.Signer.String()] = signer.Sequence
}
if !shouldAdd {
return true
}
txSignersSeqs[signer.Signer.String()] = signer.Sequence
}
if !shouldAdd {
return true
}

// NOTE: Since transaction verification was already executed in CheckTx,
Expand All @@ -331,18 +337,21 @@ func (h *DefaultProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHan
}

txsLen := len(h.txSelector.SelectedTxs(ctx))
for sender, seq := range txSignersSeqs {
// If txsLen != selectedTxsNums is true, it means that we've
// added a new tx to the selected txs, so we need to update
// the sequence of the sender.
if txsLen != selectedTxsNums {
selectedTxsSignersSeqs[sender] = seq
} else if _, ok := selectedTxsSignersSeqs[sender]; !ok {
// The transaction hasn't been added but it passed the
// verification, so we know that the sequence is correct.
// So we set this sender's sequence to seq-1, in order
// to avoid unnecessary calls to PrepareProposalVerifyTx.
selectedTxsSignersSeqs[sender] = seq - 1
// If the tx is unordered, we don't need to update the sender sequence.
if !isUnordered {
for sender, seq := range txSignersSeqs {
// If txsLen != selectedTxsNums is true, it means that we've
// added a new tx to the selected txs, so we need to update
// the sequence of the sender.
if txsLen != selectedTxsNums {
selectedTxsSignersSeqs[sender] = seq
} else if _, ok := selectedTxsSignersSeqs[sender]; !ok {
// The transaction hasn't been added but it passed the
// verification, so we know that the sequence is correct.
// So we set this sender's sequence to seq-1, in order
// to avoid unnecessary calls to PrepareProposalVerifyTx.
selectedTxsSignersSeqs[sender] = seq - 1
}
}
}
selectedTxsNums = txsLen
Expand Down
6 changes: 3 additions & 3 deletions baseapp/block_gas_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ func TestBaseApp_BlockGas(t *testing.T) {
configurator.NewAppConfig(
configurator.AuthModule(),
configurator.TxModule(),
configurator.ParamsModule(),
configurator.ConsensusModule(),
configurator.BankModule(),
configurator.StakingModule(),
Expand Down Expand Up @@ -115,12 +114,13 @@ func TestBaseApp_BlockGas(t *testing.T) {
genState := GenesisStateWithSingleValidator(t, cdc, appBuilder)
stateBytes, err := cmtjson.MarshalIndent(genState, "", " ")
require.NoError(t, err)
bapp.InitChain(&abci.RequestInitChain{
_, err = bapp.InitChain(&abci.RequestInitChain{
Validators: []abci.ValidatorUpdate{},
ConsensusParams: simtestutil.DefaultConsensusParams,
AppStateBytes: stateBytes,
})

require.NoError(t, err)
ctx := bapp.NewContext(false)

// tx fee
Expand Down Expand Up @@ -174,7 +174,7 @@ func TestBaseApp_BlockGas(t *testing.T) {
require.Equal(t, []byte("ok"), okValue)
}
// check block gas is always consumed
baseGas := uint64(57504) // baseGas is the gas consumed before tx msg
baseGas := uint64(54436) // baseGas is the gas consumed before tx msg
expGasConsumed := addUint64Saturating(tc.gasToConsume, baseGas)
if expGasConsumed > uint64(simtestutil.DefaultConsensusParams.Block.MaxGas) {
// capped by gasLimit
Expand Down
9 changes: 8 additions & 1 deletion client/flags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ const (
FlagOffset = "offset"
FlagCountTotal = "count-total"
FlagTimeoutHeight = "timeout-height"
FlagTimeoutTimestamp = "timeout-timestamp"
FlagUnordered = "unordered"
FlagKeyAlgorithm = "algo"
FlagKeyType = "key-type"
FlagFeePayer = "fee-payer"
Expand Down Expand Up @@ -135,7 +137,9 @@ func AddTxFlagsToCmd(cmd *cobra.Command) {
f.Bool(FlagOffline, false, "Offline mode (does not allow any online functionality)")
f.BoolP(FlagSkipConfirmation, "y", false, "Skip tx broadcasting prompt confirmation")
f.String(FlagSignMode, "", "Choose sign mode (direct|amino-json|direct-aux|textual), this is an advanced feature")
f.Uint64(FlagTimeoutHeight, 0, "Set a block timeout height to prevent the tx from being committed past a certain height")
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")
f.Int64(FlagTimeoutTimestamp, 0, "Set a block timeout timestamp to prevent the tx from being committed past a certain time")
f.Bool(FlagUnordered, false, "Enable unordered transaction delivery; must be used in conjunction with --timeout-timestamp")
f.String(FlagFeePayer, "", "Fee payer pays fees for the transaction instead of deducting from the signer")
f.String(FlagFeeGranter, "", "Fee granter grants fees for the transaction")
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")
Expand All @@ -145,6 +149,9 @@ func AddTxFlagsToCmd(cmd *cobra.Command) {
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)",
GasFlagAuto, GasFlagAuto, FlagFees, DefaultGasLimit))

cmd.MarkFlagsMutuallyExclusive(FlagTimeoutHeight, FlagTimeoutTimestamp)
cmd.MarkFlagsRequiredTogether(FlagUnordered, FlagTimeoutTimestamp)

AddKeyringFlags(f)
}

Expand Down
17 changes: 14 additions & 3 deletions client/tx/aux_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package tx

import (
"context"
"time"

"github.com/cosmos/gogoproto/proto"
"google.golang.org/protobuf/types/known/anypb"
"google.golang.org/protobuf/types/known/timestamppb"

txv1beta1 "cosmossdk.io/api/cosmos/tx/v1beta1"
txsigning "cosmossdk.io/x/tx/signing"
Expand Down Expand Up @@ -58,6 +60,14 @@ func (b *AuxTxBuilder) SetTimeoutHeight(height uint64) {
b.auxSignerData.SignDoc.BodyBytes = nil
}

// SetTimeoutTimestamp sets a timeout timestamp in the tx.
func (b *AuxTxBuilder) SetTimeoutTimestamp(timestamp time.Time) {
b.checkEmptyFields()

b.body.TimeoutTimestamp = timestamppb.New(timestamp)
b.auxSignerData.SignDoc.BodyBytes = nil
}

// SetMsgs sets an array of Msgs in the tx.
func (b *AuxTxBuilder) SetMsgs(msgs ...sdk.Msg) error {
anys := make([]*anypb.Any, len(msgs))
Expand Down Expand Up @@ -209,9 +219,10 @@ func (b *AuxTxBuilder) GetSignBytes() ([]byte, error) {
})

auxBody := &txv1beta1.TxBody{
Messages: body.Messages,
Memo: body.Memo,
TimeoutHeight: body.TimeoutHeight,
Messages: body.Messages,
Memo: body.Memo,
TimeoutHeight: body.TimeoutHeight,
TimeoutTimestamp: body.TimeoutTimestamp,
// AuxTxBuilder has no concern with extension options, so we set them to nil.
// This preserves pre-PR#16025 behavior where extension options were ignored, this code path:
// https://github.com/cosmos/cosmos-sdk/blob/ac3c209326a26b46f65a6cc6f5b5ebf6beb79b38/client/tx/aux_builder.go#L193
Expand Down
57 changes: 46 additions & 11 deletions client/tx/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package tx
import (
"errors"
"fmt"
"math/big"
"os"
"strings"
"time"

"github.com/cosmos/go-bip39"
"github.com/spf13/pflag"
Expand Down Expand Up @@ -32,9 +34,11 @@ type Factory struct {
sequence uint64
gas uint64
timeoutHeight uint64
timeoutTimestamp time.Time
gasAdjustment float64
chainID string
fromName string
unordered bool
offline bool
generateOnly bool
memo string
Expand All @@ -50,6 +54,14 @@ type Factory struct {

// NewFactoryCLI creates a new Factory.
func NewFactoryCLI(clientCtx client.Context, flagSet *pflag.FlagSet) (Factory, error) {
if clientCtx.Viper == nil {
clientCtx = clientCtx.WithViper("")
}

if err := clientCtx.Viper.BindPFlags(flagSet); err != nil {
return Factory{}, fmt.Errorf("failed to bind flags to viper: %w", err)
}

signMode := signing.SignMode_SIGN_MODE_UNSPECIFIED
switch clientCtx.SignModeStr {
case flags.SignModeDirect:
Expand All @@ -67,18 +79,21 @@ func NewFactoryCLI(clientCtx client.Context, flagSet *pflag.FlagSet) (Factory, e
var accNum, accSeq uint64
if clientCtx.Offline {
if flagSet.Changed(flags.FlagAccountNumber) && flagSet.Changed(flags.FlagSequence) {
accNum, _ = flagSet.GetUint64(flags.FlagAccountNumber)
accSeq, _ = flagSet.GetUint64(flags.FlagSequence)
accNum = clientCtx.Viper.GetUint64(flags.FlagAccountNumber)
accSeq = clientCtx.Viper.GetUint64(flags.FlagSequence)
} else {
return Factory{}, errors.New("account-number and sequence must be set in offline mode")
}
}

gasAdj, _ := flagSet.GetFloat64(flags.FlagGasAdjustment)
memo, _ := flagSet.GetString(flags.FlagNote)
timeoutHeight, _ := flagSet.GetUint64(flags.FlagTimeoutHeight)
gasAdj := clientCtx.Viper.GetFloat64(flags.FlagGasAdjustment)
memo := clientCtx.Viper.GetString(flags.FlagNote)
timestampUnix := clientCtx.Viper.GetInt64(flags.FlagTimeoutTimestamp)
timeoutTimestamp := time.Unix(timestampUnix, 0)
timeoutHeight := clientCtx.Viper.GetUint64(flags.FlagTimeoutHeight)
unordered := clientCtx.Viper.GetBool(flags.FlagUnordered)

gasStr, _ := flagSet.GetString(flags.FlagGas)
gasStr := clientCtx.Viper.GetString(flags.FlagGas)
gasSetting, _ := flags.ParseGasSetting(gasStr)

f := Factory{
Expand All @@ -94,17 +109,19 @@ func NewFactoryCLI(clientCtx client.Context, flagSet *pflag.FlagSet) (Factory, e
accountNumber: accNum,
sequence: accSeq,
timeoutHeight: timeoutHeight,
timeoutTimestamp: timeoutTimestamp,
unordered: unordered,
gasAdjustment: gasAdj,
memo: memo,
signMode: signMode,
feeGranter: clientCtx.FeeGranter,
feePayer: clientCtx.FeePayer,
}

feesStr, _ := flagSet.GetString(flags.FlagFees)
feesStr := clientCtx.Viper.GetString(flags.FlagFees)
f = f.WithFees(feesStr)

gasPricesStr, _ := flagSet.GetString(flags.FlagGasPrices)
gasPricesStr := clientCtx.Viper.GetString(flags.FlagGasPrices)
f = f.WithGasPrices(gasPricesStr)

f = f.WithPreprocessTxHook(clientCtx.PreprocessTxHook)
Expand All @@ -123,6 +140,8 @@ func (f Factory) Fees() sdk.Coins { return f.fees }
func (f Factory) GasPrices() sdk.DecCoins { return f.gasPrices }
func (f Factory) AccountRetriever() client.AccountRetriever { return f.accountRetriever }
func (f Factory) TimeoutHeight() uint64 { return f.timeoutHeight }
func (f Factory) TimeoutTimestamp() time.Time { return f.timeoutTimestamp }
func (f Factory) Unordered() bool { return f.unordered }
func (f Factory) FromName() string { return f.fromName }

// SimulateAndExecute returns the option to simulate and then execute the transaction
Expand Down Expand Up @@ -236,6 +255,18 @@ func (f Factory) WithTimeoutHeight(height uint64) Factory {
return f
}

// WithTimeoutTimestamp returns a copy of the Factory with an updated timeout timestamp.
func (f Factory) WithTimeoutTimestamp(timestamp time.Time) Factory {
f.timeoutTimestamp = timestamp
return f
}

// WithUnordered returns a copy of the Factory with an updated unordered field.
func (f Factory) WithUnordered(v bool) Factory {
f.unordered = v
return f
}

// WithFeeGranter returns a copy of the Factory with an updated fee granter.
func (f Factory) WithFeeGranter(fg sdk.AccAddress) Factory {
f.feeGranter = fg
Expand Down Expand Up @@ -311,14 +342,16 @@ func (f Factory) BuildUnsignedTx(msgs ...sdk.Msg) (client.TxBuilder, error) {
return nil, errors.New("cannot provide both fees and gas prices")
}

glDec := math.LegacyNewDec(int64(f.gas))
// f.gas is a uint64 and we should convert to LegacyDec
// without the risk of under/overflow via uint64->int64.
gasLimitDec := math.LegacyNewDecFromBigInt(new(big.Int).SetUint64(f.gas))

// Derive the fees based on the provided gas prices, where
// fee = ceil(gasPrice * gasLimit).
fees = make(sdk.Coins, len(f.gasPrices))

for i, gp := range f.gasPrices {
fee := gp.Amount.Mul(glDec)
fee := gp.Amount.Mul(gasLimitDec)
fees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt())
}
}
Expand All @@ -340,6 +373,8 @@ func (f Factory) BuildUnsignedTx(msgs ...sdk.Msg) (client.TxBuilder, error) {
tx.SetFeeGranter(f.feeGranter)
tx.SetFeePayer(f.feePayer)
tx.SetTimeoutHeight(f.TimeoutHeight())
tx.SetTimeoutTimestamp(f.TimeoutTimestamp())
tx.SetUnordered(f.Unordered())

if etx, ok := tx.(client.ExtendedTxBuilder); ok {
etx.SetExtensionOptions(f.extOptions...)
Expand Down Expand Up @@ -482,7 +517,7 @@ func (f Factory) Prepare(clientCtx client.Context) (Factory, error) {
}

fc := f
from := clientCtx.GetFromAddress()
from := clientCtx.FromAddress

if err := fc.accountRetriever.EnsureExists(clientCtx, from); err != nil {
return fc, err
Expand Down
4 changes: 4 additions & 0 deletions client/tx_config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package client

import (
"time"

txsigning "cosmossdk.io/x/tx/signing"

codectypes "github.com/cosmos/cosmos-sdk/codec/types"
Expand Down Expand Up @@ -48,6 +50,8 @@ type (
SetFeePayer(feePayer sdk.AccAddress)
SetGasLimit(limit uint64)
SetTimeoutHeight(height uint64)
SetTimeoutTimestamp(timestamp time.Time)
SetUnordered(v bool)
SetFeeGranter(feeGranter sdk.AccAddress)
AddAuxSignerData(tx.AuxSignerData) error
}
Expand Down
Loading