Changelog
- Dec 4, 2023: Initial Draft (@yihuang, @tac0turtle, @alexanderbez)
- Jan 30, 2024: Include section on deterministic transaction encoding
- Mar 18, 2025: Revise implementation to use Cosmos SDK KV Store and require unique timeouts per-address (@technicallyty)
- Apr 25, 2025: Add note about rejecting unordered txs with sequence values.
Status
ACCEPTED Not ImplementedAbstract
We propose a way to do replay-attack protection without enforcing the order of transactions and without requiring the use of monotonically increasing sequences. Instead, we propose the use of a time-based, ephemeral sequence.Context
Account sequence values serve to prevent replay attacks and ensure transactions from the same sender are included into blocks and executed in sequential order. Unfortunately, this makes it difficult to reliably send many concurrent transactions from the same sender. Victims of such limitations include IBC relayers and crypto exchanges.Decision
We propose adding a boolean fieldunordered
and a google.protobuf.Timestamp field timeout_timestamp
to the transaction body.
Unordered transactions will bypass the traditional account sequence rules and follow the rules described
below, without impacting traditional ordered transactions which will follow the same sequence rules as before.
We will introduce new storage of time-based, ephemeral unordered sequences using the SDK’s existing KV Store library.
Specifically, we will leverage the existing x/auth KV store to store the unordered sequences.
When an unordered transaction is included in a block, a concatenation of the timeout_timestamp
and sender’s address bytes
will be recorded to state (i.e. 542939323/<address_bytes>
). In cases of multi-party signing, one entry per signer
will be recorded to state.
New transactions will be checked against the state to prevent duplicate submissions. To prevent the state from growing indefinitely, we propose the following:
- Define an upper bound for the value of
timeout_timestamp
(i.e. 10 minutes). - Add PreBlocker method x/auth that removes state entries with a
timeout_timestamp
earlier than the current block time.
Transaction Format
Replay Protection
We facilitate replay protection by storing the unordered sequence in the Cosmos SDK KV store. Upon transaction ingress, we check if the transaction’s unordered sequence exists in state, or if the TTL value is stale, i.e. before the current block time. If so, we reject it. Otherwise, we add the unordered sequence to the state. This section of the state will belong to thex/auth
module.
The state is evaluated during x/auth’s PreBlocker
. All transactions with an unordered sequence earlier than the current block time
will be deleted.
AnteHandler Decorator
To facilitate bypassing nonce verification, we must modify the existingIncrementSequenceDecorator
AnteHandler decorator to skip the nonce verification
when the transaction is marked as unordered.
Unordered Sequences
Unordered sequences provide a simple, straightforward mechanism to protect against both transaction malleability and transaction duplication. It is important to note that the unordered sequence must still be unique. However, the value is not required to be strictly increasing as with regular sequences, and the order in which the node receives the transactions no longer matters. Clients can handle building unordered transactions similarly to the code below:State Management
The storage of unordered sequences will be facilitated using the Cosmos SDK’s KV Store service.Note On Previous Design Iteration
The previous iteration of unordered transactions worked by using an ad-hoc state-management system that posed severe risks and a vector for duplicated tx processing. It relied on graceful app closure which would flush the current state of the unordered sequence mapping. If the 2/3’s of the network crashed, and the graceful closure did not trigger, the system would lose track of all sequences in the mapping, allowing those transactions to be replayed. The implementation proposed in the updated version of this ADR solves this by writing directly to the Cosmos KV Store. While this is less performant, for the initial implementation, we opted to choose a safer path and postpone performance optimizations until we have more data on real-world impacts and a more battle-tested approach to optimization. Additionally, the previous iteration relied on using hashes to create what we call an “unordered sequence.” There are known issues with transaction malleability in Cosmos SDK signing modes. This ADR gets away from this problem by enforcing single-use unordered nonces, instead of deriving nonces from bytes in the transaction.Consequences
Positive
- Support unordered transaction inclusion, enabling the ability to “fire and forget” many transactions at once.
Negative
- Requires additional storage overhead.
- Requirement of unique timestamps per transaction causes a small amount of additional overhead for clients. Clients must ensure each transaction’s timeout timestamp is different. However, nanosecond differentials suffice.
- Usage of Cosmos SDK KV store is slower in comparison to using a non-merklized store or ad-hoc methods, and block times may slow down as a result.