CAP: 0022
Title: Invalid transactions must have no effects
Author: David Mazières
Status: Draft
Created: 2019-06-20
Discussion: https://groups.google.com/forum/#!topic/stellar-dev/NtCwqWwAxRA
Protocol version: TBD
Invalid transactions lack sufficient signatures for proper authorization, have sequence numbers that have already been used, or have invalid time bounds. Certain edge conditions cause invalid transactions to be included in the transaction set produced by consensus. Currently, Stellar executes and fails invalid transactions in the transaction set, which changes ledger state by increasing sequence numbers and debiting transaction fees. This specification changes Stellar so that invalid transactions have no effect on the ledger.
Allowing invalid--especially unauthorized--transactions to change ledger state can lead to vulnerabilities in higher-layer protocols. Consider a protocol in which two parties, A and B, execute a transaction that contributes funds to an escrow account E and makes E into a 2-of-2 multisig account. The parties might be willing to this given post-dated pre-signed transactions T1, T2 on E that allow each of A and B to recover escrowed funds after a certain delay. Unfortunately, if the previous owner of E can cause an invalid (unauthorized) transaction to use up T1's sequence number, one of the two users will be unable to recover funds.
The changes described in this document help network security by preventing unauthorized transactions from changing account state. They also help scalability by facilitating the design of robust payment channels.
We define three categories of transaction: successful, failed, and invalid. Invalid transactions must never change ledger state, even if they are included in the transaction set output by consensus. New, conservative restrictions rule out current ways of passing invalid transactions through consensus. However, if invalid transactions do make it through consensus through oversight or subsequently added features, they must have no effects on the ledger.
We define the following categories of transaction at the time of execution:
-
A successful transaction is one that meets all transaction- and operation-level prerequisites at the time of its execution. The effects of a successful transaction's operations are applied to the ledger. Successful transactions yield a result in which
TransactionResult.code
istxSUCCESS
. This document does not change which transactions are considered successful or the effects of executing such transactions. -
A failed transaction meets all valid transaction-level preconditions, including a valid transaction-level source account, valid sequence number, valid time bounds, and low signing weight for the source account. However, one or more of a failed transaction's operations cannot execute---for instance because the
destination
of aPAYMENT
no longer exists. Failed transactions increase the sequence number of the transaction-levelsourceAccount
, charge a fee to the transaction-levelsourceAccount
, and yield a result withTransactionResult.code
txFAILED
. -
An invalid transaction fails to meet transaction-level preconditions at the time of execution, for instance because the sequence number is invalid or the signatures are insufficient to meet the
sourceAccount
's low signing threshold. Currently, invalid transactions are executed just like failed ones. This document changes that behavior so that invalid transactions no longer have an effect on the ledger and do not produce aTransactionResult
. If an invalid transaction later becomes valid, it may be included again in a subsequent ledger.
A ledger that contains too many invalid transactions will reduce the number of operations available to successful transactions and negatively impact the ledger. Since the source of an invalid transaction does not incur any transaction cost, and since it may be difficult in the general case to decide if a transaction is valid at the time its fee is charged, we place restrictions on the composition of the transaction set in a single ledger. These rules are conservative; they may force two valid transactions that could have succeeded in the same ledger to be included in different ledgers.
If a transaction set S contains a transaction T, we use S[<=T] to
denote the subset of S consisting of transactions with the same
sourceAccount
as T and a seqNum
less than or equal to that of T (a
set that includes T itself). A set S is admissible, and hence can
be a candidate for the consensus transaction set, if all of the
following hold for each transaction T in S:
-
T's
sourceAccount
must exist and must have sufficient funds to pay the offered transaction fees for all of S[<=T]. (This restriction exists today.) -
T's sequence number will be valid if all other transactions in S[<=T] are executed. (This restriction exists today, and among other things implies a transaction set may not include a transaction with a stale sequence number or two distinct transactions with the same source account and sequence number.)
-
Any transaction in S other than T that contains a
SET_OPTIONS
orBUMP_SEQUENCE
operation on T'ssourceAccount
must have the samesourceAccount
as T and a greater sequence number than T. This guarantees that aSET_OPTIONS
orBUMP_SEQUENCE
on T'ssourceAccount
cannot be ordered before T. This new restriction specified by this document is not enforced today.
In addition to placing these restrictions on transaction sets, we
restore the behavior prior to BUMP_SEQUENCE
in which sequence
numbers are increased at exactly the same time that the fee is
debited, before any operations are executed. Currently, fees are
charged up front before any operations from any transactions execute,
while sequence numbers are increased at the time an operation
executes. Now that we know a BUMP_SEQUENCE
cannot be ordered before
an operation on the source account whose sequence is being bumped, we
can increase the sequence numbers up front when charging fees.
This design prevents people who are no longer authorized signers an on account from affecting the account state. However, it does so in a way that avoids the ability to clog the ledger with invalid transactions.
There are some minor incompatibilities that should not impact users.
First, certain invalid transactions will no longer execute as failed
transactions because they will not execute at all. However, in all
such cases, there was no guarantee the transactions would execute
anyway, because they could only execute when they happened to land in
the same ledger as another transaction with a SET_OPTIONS
or
BUMP_SEQUENCE
operation. Hence the most likely effect of this
change is to thwart attacks on vulnerable higher-layer protocols.
Second, certain transactions can no longer execute in the same ledger. Again, there is never a guarantee that an operation can execute in a particular ledger, so applications could not have relied on this happening anyway.
Finally, sequence number increases will appear in
TransactionMetaV1.txChanges
instead of
TransactionMetaV1.operations[0]
. This should be more intuitive.
The changes outlined in this document should for the most part improve security by providing more consistent authorization of changes to accounts. The one potential risk is that attackers could clog the network with invalid transactions without paying nearly the corresponding amount of transaction fees. That risk is mitigated by the restrictions on transaction sets, but is something that must be kept in mind when future CAPs add additional operations.
Any future operations or other transaction features added to the network that can render transactions invalid may need to revise the transaction set restrictions to prevent invalid transactions from being admissible.
None yet.
None yet.