Nonce Payload Transaction Format #415
Replies: 5 comments
-
|
I really like this approach! One concern I'd flag, from a wallet perspective, is that signing a durable nonce transaction from an arbitrary app is really dangerous and would remain so. It's very easy to craft a transaction that behaves one way when simulated, and a different way when executed, if you can land it at an arbitrary future time, which remains the case here. So I'm not sure this would be an obvious best choice for sponsored transactions, in the case of an arbitrary app and wallet. I think wallets should probably block durable nonce transactions from untrusted apps, with or without this proposal. On "We may want to consider supporting v0 transactions", I think the assumption that people will have used |
Beta Was this translation helpful? Give feedback.
-
|
nonce transactions (and any mechanism that would replace them such as pda signer promotion) are primarily meant to support offline signing flows, for instance orgs with very high security requirements constructing simple transactions (minting tokens, withdrawing from stake accounts) on airgapped computers. in general we assume theyre doing this with the solana cli or their own custom rust code, not using web3js or v0 transactions tbh the idea of users signing arbitrary nonce transactions handed to them by a dapp and then handing them back bothers me, but ultimately if they do this they have to trust the dapp. in any event, upgrading to follow new patterns is much easier for them than the orgs that nonce transactions are primarily intended to serve |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
Yeah probably not, never mind |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Summary
A new transaction format which wraps legacy nonce transactions with an external
fee-payer and blockhash, allowing them to be processed as normal blockhash
transactions.
Motivation
Nonce transactions have been a perennial problem for validator clients:
account state immediately prior to execution, complicating edge filtration.
fees, to prevent transaction replay.
The combination of these three properties makes them an attractive vehicle for
transaction spam, whether malicious (to degrade network performance), or merely
rude (to increase chances of inclusion during network congestion at no cost to
the sender).
In addition,
SIMD-0297
proposes to allow transactions which fail nonce validation to be committed to
chain as no-ops. This has the unfortunate side-effect of making committed
transaction signatures non-unique because it is impossible to determine whether
a nonce transaction has been committed previously if the nonce account is not
mutated. By eliminating top-level nonce transactions, we can preserve signature
uniqueness.
We propose a new transaction format that is effectively an additional header
preceding a full legacy nonce transaction. Users will provide a fee-payer,
recent blockhash, compute budget options, legacy nonce transaction, and a
signature over this complete message. Compared to alternative designs, this has
a number of attractive properties:
transactions through this new mechanism. This allows us to rapidly deprecate and
remove nearly all special handling of nonce transactions from validator clients
while providing a path for full backwards compatibility.
produce a legacy nonce transaction the same way they always did. The only
workflow change is to drop it into a new CLI or wallet flow which wraps the
payload and signs with a hot wallet.
produced and can be chosen arbitrarily prior to submission for execution.
As a side benefit, nonce payload transactions become the obvious best choice for
sponsored transactions. Users do not need to designate an explicit fee-payer so
the proxy can choose one arbitrarily, and attacks using the third-party
fee-payer as a signer become impossible because the inner transaction has no
access to the outer authority.
Dependencies
This proposal depends on the following (not yet previously accepted) proposals:
SIMD-0296: Larger Transaction Size
A legacy transaction may be up to 1232 bytes. We take advantage of larger
transaction sizes to wrap legacy transactions.
New Terminology
transaction.
Detailed Design
Nonce Payload Transaction Specification
The binary layout of a Nonce Payload Transaction is as follows:
XXX repeat version byte inside?
VersionByte
The VersionByte MUST be set to
130to distinguish Nonce Payload Transactionsfrom legacy/v0/v1 formats.
FeePayerAddress
The pubkey of the account which will pay fees on behalf of this transaction.
Note that the
LegacyNonceTransactionitself does not have a fee-payer perse; its first signer has no special significance.
RecentBlockhash
A recent blockhash, identical in meaning to legacy and v0 blockhash
transactions.
TransactionConfigMask
TransactionConfigMaskis explained below in detail.LegacyTransactionLength
2-byte LE u16 encoding the length in bytes of the enveloped legacy nonce
transaction.
LegacyNonceTransaction
A legacy nonce transaction that adheres to all sanitization rules of a normal
legacy transaction. This transaction MUST have
AdvanceNonceAccountas itsfirst instruction, otherwise it is a sanitization failure. It MUST NOT contain
trailing bytes, otherwise it is a sanitization failure.
ConfigValues
ConfigValuesis explained below withTransactionConfigMaskin detail. It isplaced after
LegacyNonceTransactionto allow the nonce payload to sit at afixed offset
for the benefit of SigVerify(edit: may not be necessary).Signature
One signature, by the private key associated with
FeePayerAddress, over thefull serialized message including
LegacyNonceTransaction.TransactionConfigMask
The transaction config mask is used to configure specific fee and resource
requests in a transaction. It is identical to the field as proposed in
SIMD-0385
and intended to allow both transaction formats to be enriched with new features
as desired. There is however no requirement that new config options in one
format be mirrored in the other.
Initially supported fields and assigned bits:
For 2 bit fields, such as priority-fee, both bits MUST be set. If only one of
the bits is set, the transaction is invalid and cannot be included in blocks.
All
ComputeBudgetPrograminstructions on the nonce payload are ignored, evenif they are invalid. This design is intended to allow the external fee-payer to
determine what priority fee and resource limits they are willing to pay.
SigVerify
The nested nature of a Nonce Payload Transaction requires special handling by
SigVerify.
Signatureis to be verified over the entire signed message usingthe pubkey specified in
FeePayerAddress. Signatures insideLegacyNonceTransactionmust be verified against that message itself.FeePayerAddressandLegacyNonceTransactionstart at fixed offsets, whichminimizes the computational cost to the greatest extent possible.
(edit: as noted by starry, we can just run sigverify on the main, toplevel
signature if it improves this proposal. other signatures can be verified
later in the runtime, and if they fail, we can charge fees on the toplevel feepayer)
Transaction Processing
As noted above, the inner transaction MUST be a valid nonce transaction.
Allowing a legacy blockhash transaction to serve as a payload is fundamentally
unsound, as there is no mechanism to prevent replay.
When a Nonce Payload Transaction is sanitized,
FeePayerAddressis used as thefee-payer,
Signatureis used as the signature,RecentBlockhashis used asthe blockhash,
TransactionConfigMaskandConfigValuesare used to determinepriority fee and resource limits. The message hash is the hash of the bytes
signed by the external fee-payer. All instructions, accounts, and
writable/signer designations are as in
LegacyNonceTransaction. This payload isexecuted normally as if it were the full transaction itself. The payload's own
RecentBlockhashis used as the nonce value just as a legacy nonce transaction.The payload cannot see its external fee-payer and has no access to this account
during execution, unless it provided the account explicitly, in which case the
account is not a signer unless it also properly signed the legacy transaction.
If account loading or transaction execution of the nonce payload fails for any
reason other than inability to properly advance the nonce, it is processed as
a normal fee-only transaction: the external fee-payer pays fees, and the nonce
account is advanced to the next durable nonce. This prevents speculative replay
of a nonce payload, where it is repeatedly run until it succeeds. This mechanism
to advance the nonce account in light of execution failure is the only runtime
support for nonce transactions required.
When
SIMD-0290
is enabled, if the external fee-payer is invalid, the transaction MAY be
committed to chain. Such a transaction induces no state changes, including to
the payload nonce account. This means a future transaction could successfully
execute the payload, but because Nonce Payload Transactions are normal blockhash
transactions, such a transaction will necessarily have a unique signature.
This proposal neither depends on, nor blocks or supersedes,
SIMD-0297,
which deals exclusively with top-level nonce transactions. SIMD-0297 may be
obviated if we fully remove nonce transactions after implementing this proposal,
but such an action is out of scope here and would depend on a future SIMD.
Alternatives Considered
As always, the first alternative is to do nothing. This is highly undesirable
because nonce transactions are a constant thorn with impacts throughout the
transaction processing pipeline.
The leading alternative proposal for replacing nonce transactions is PDA signer
promotion, which would allow an instruction to promote a PDA to function as a
signer from the point of view of all subsequent instructions on the transaction.
However, this has several drawbacks:
potentially years. When we do remove support for nonce transactions, it is
possible users who depended on their perpetual support may be unable to access
funds or perform some other essential operation.
authorities to associated PDAs. This may be a hard sell for conservative
organizations due to inertia, operational risk, and the increased risk surface
of granting an onchain program control over mints, program upgrades, etc.
programs, which may have been designed under the assumption a PDA signer is only
possible via CPI.
fees, so there is no advantage over this proposal in allowing fully cold
transaction creation. However, PDA signer promotion would also require teams to
upgrade their cold toolchains to support the new instruction, whereas this
proposal would not.
A stricter nonce program and stricter rules around valid nonce instruction
placement in transactions would make it feasible to determine if nonce
transactions are valid at time of batching. It would not, however, solve most of
the difficulties such transactions cause, which are inherent in the fact that
they do not carry a real blockhash enforcing a TTL.
We may want to consider supporting v0 transactions for the nonce payload, in
addition to legacy transactions. This was not done for simplicity, and because
we hope to move away from v0 transactions entirely due to address lookup tables.
This would mean that existing v0 nonce transactions become impossible to execute
once nonce support is removed from validator clients. However, there does not
seem to be a legitimate usecase for such transactions, as the typical user
relies on such transactions for simple operations that can easily fit into the
legacy transaction account limit.
Impact
This proposal allows us to begin sunsetting nonce transactions. When that
process begins, ecosystem teams using legacy nonce transactions should be
prepared to sign for them with a hot wallet prior to submitting them to the
chain for execution.
Wallets should provide a flow for dropping a serialized legacy nonce transaction
into a field which wraps them in a Nonce Payload Transaction to be signed and
submitted.
Security Considerations
Because the external fee-payer controls the compute budget parameters, it is
possible for them to "burn" a payload by setting artificially low limits,
forcing an execution failure that advances the nonce. This is unlikely to be a
concern in practice: in most cases, the same user produces the payload and the
final transaction, and the distinction is just to allow separate cold and hot
signing steps. If provided to a proxy, it is expected the nonce payload contains
a tip instruction to compensate for fees paid, so it would be economically
irrational to pay to induce a deliberate failure.
It is possible for a Nonce Payload Transaction to land onchain and pay fees but
fail to advance the nonce. If this is because the nonce account was invalid,
already used, or did not match the payload-defined nonce value, such a payload
can never become valid. However, if the nonce failed to advance because the
provided authority was incorrect, and the account's authority was later changed
to the authority given on the payload, such a payload could become executable.
This seems unlikely to occur as it would require deliberate user manipulation.
However, it could also be obviated by changing
AuthorizeNonceAccounttoidempotently update the account to the latest durable nonce.
Drawbacks
The need to verify two levels of signature over two different bufferscomplicates SigVerify somewhat. However, this should be more than adequately
compensated by the ability to filter all transactions by blockhash validity
after legacy nonce transactions are removed.
In contrast to legacy nonce transactions, Nonce Payload Transactions require a
hot signer able to pay fees. This is inherent in any nonce-like blockhash-based
solution.
Beta Was this translation helpful? Give feedback.
All reactions