@ -26,10 +26,7 @@ account data. A transaction is now constructed in the normal way, but with the
|
|||||||
following additional requirements:
|
following additional requirements:
|
||||||
|
|
||||||
1) The durable nonce value is used in the `recent_blockhash` field
|
1) The durable nonce value is used in the `recent_blockhash` field
|
||||||
2) A `Nonce` instruction is issued (first?)
|
2) A `NonceAdvance` instruction is the first issued in the transaction
|
||||||
3) The appropriate transaction flag is set, signaling that the usual
|
|
||||||
hash age check should be skipped and the previous requirements enforced. This
|
|
||||||
may be unnecessary, see [Runtime Support](#runtime-support) below
|
|
||||||
|
|
||||||
### Contract Mechanics
|
### Contract Mechanics
|
||||||
|
|
||||||
@ -66,21 +63,43 @@ WithdrawInstruction(to, lamports)
|
|||||||
success
|
success
|
||||||
```
|
```
|
||||||
|
|
||||||
A client wishing to use this feature starts by creating a nonce account and
|
A client wishing to use this feature starts by creating a nonce account under
|
||||||
depositing sufficient lamports as to make it rent-exempt. The resultant account
|
the system program. This account will be in the `Uninitialized` state with no
|
||||||
will be in the `Uninitialized` state with no stored hash and thus unusable.
|
stored hash, and thus unusable.
|
||||||
|
|
||||||
The `Nonce` instruction is used to request that a new nonce be stored for the
|
To initialize a newly created account, a `NonceInitialize` instruction must be
|
||||||
calling account. The first `Nonce` instruction run on a newly created account
|
issued. This instruction takes one parameter, the `Pubkey` of the account's
|
||||||
will drive the account's state to `Initialized`. As such, a `Nonce` instruction
|
[authority](../offline-signing/durable-nonce.md#nonce-authority). Nonce accounts
|
||||||
MUST be issued before the account can be used.
|
must be [rent-exempt](rent.md#two-tiered-rent-regime) to meet the data-persistence
|
||||||
|
requirements of the feature, and as such, require that sufficient lamports be
|
||||||
|
deposited before they can be initialized. Upon successful initialization, the
|
||||||
|
cluster's most recent blockhash is stored along with specified nonce authority
|
||||||
|
`Pubkey`.
|
||||||
|
|
||||||
To discard a `NonceAccount`, the client should issue a `Withdraw` instruction
|
The `NonceAdvance` instruction is used to manage the account's stored nonce
|
||||||
which withdraws all lamports, leaving a zero balance and making the account
|
value. It stores the cluster's most recent blockhash in the account's state data,
|
||||||
eligible for deletion.
|
failing if that matches the value already stored there. This check prevents
|
||||||
|
replaying transactions within the same block.
|
||||||
|
|
||||||
`Nonce` and `Withdraw` instructions each will only succeed if the stored
|
Due to nonce accounts' [rent-exempt](rent.md#two-tiered-rent-regime) requirement,
|
||||||
blockhash is no longer resident in sysvar.recent_blockhashes.
|
a custom withdraw instruction is used to move funds out of the account.
|
||||||
|
The `NonceWithdraw` instruction takes a single argument, lamports to withdraw,
|
||||||
|
and enforces rent-exemption by preventing the account's balance from falling
|
||||||
|
below the rent-exempt minimum. An exception to this check is if the final balance
|
||||||
|
would be zero lamports, which makes the account eligible for deletion. This
|
||||||
|
account closure detail has an additional requirement that the stored nonce value
|
||||||
|
must not match the cluster's most recent blockhash, as per `NonceAdvance`.
|
||||||
|
|
||||||
|
The account's [nonce authority](../offline-signing/durable-nonce.md#nonce-authority)
|
||||||
|
can be changed using the `NonceAuthorize` instruction. It takes one parameter,
|
||||||
|
the `Pubkey` of the new authority. Executing this instruction grants full
|
||||||
|
control over the account and its balance to the new authority.
|
||||||
|
|
||||||
|
{% hint style="info" %}
|
||||||
|
`NonceAdvance`, `NonceWithdraw` and `NonceAuthorize` all require the current
|
||||||
|
[nonce authority](../offline-signing/durable-nonce.md#nonce-authority) for the
|
||||||
|
account to sign the transaction.
|
||||||
|
{% endhint %}
|
||||||
|
|
||||||
### Runtime Support
|
### Runtime Support
|
||||||
|
|
||||||
@ -89,25 +108,11 @@ an extant `recent_blockhash` on the transaction and prevent fee theft via
|
|||||||
failed transaction replay, runtime modifications are necessary.
|
failed transaction replay, runtime modifications are necessary.
|
||||||
|
|
||||||
Any transaction failing the usual `check_hash_age` validation will be tested
|
Any transaction failing the usual `check_hash_age` validation will be tested
|
||||||
for a Durable Transaction Nonce. This specifics of this test are undecided, some
|
for a Durable Transaction Nonce. This is signaled by including a `NonceAdvance`
|
||||||
options:
|
instruction as the first instruction in the transaction.
|
||||||
|
|
||||||
1) Require that the `Nonce` instruction be the first in the transaction
|
If the runtime determines that a Durable Transaction Nonce is in use, it will
|
||||||
* + No ABI changes
|
take the following additional actions to validate the transaction:
|
||||||
* + Fast and simple
|
|
||||||
* - Sets a precedent that may lead to incompatible instruction combinations
|
|
||||||
2) Blind search for a `Nonce` instruction over all instructions in the
|
|
||||||
transaction
|
|
||||||
* + No ABI changes
|
|
||||||
* - Potentially slow
|
|
||||||
3) [2], but guarded by a transaction flag
|
|
||||||
* - ABI changes
|
|
||||||
* - Wire size increase
|
|
||||||
* + We'll probably end up with some sort of flags eventually anyway
|
|
||||||
|
|
||||||
Current prototyping will use [1]. If it is determined that a Durable Transaction
|
|
||||||
Nonce is in use, the runtime will take the following actions to validate the
|
|
||||||
transaction:
|
|
||||||
|
|
||||||
1) The `NonceAccount` specified in the `Nonce` instruction is loaded.
|
1) The `NonceAccount` specified in the `Nonce` instruction is loaded.
|
||||||
2) The `NonceState` is deserialized from the `NonceAccount`'s data field and
|
2) The `NonceState` is deserialized from the `NonceAccount`'s data field and
|
||||||
@ -118,6 +123,11 @@ one specified in the transaction's `recent_blockhash` field.
|
|||||||
If all three of the above checks succeed, the transaction is allowed to continue
|
If all three of the above checks succeed, the transaction is allowed to continue
|
||||||
validation.
|
validation.
|
||||||
|
|
||||||
### Open Questions
|
Since transactions that fail with an `InstructionError` are charged a fee and
|
||||||
|
changes to their state rolled back, there is an opportunity for fee theft if a
|
||||||
* Should this feature be restricted in the number of uses per transaction?
|
`NonceAdvance` instruction is reverted. A malicious validator could replay the
|
||||||
|
failed transaction until the stored nonce is successfully advanced. Runtime
|
||||||
|
changes prevent this behavior. When a durable nonce transaction fails with an
|
||||||
|
`InstructionError` aside from the `NonceAdvance` instruction, the nonce account
|
||||||
|
is rolled back to its pre-execution state as usual. Then the runtime advances
|
||||||
|
its nonce value and the advanced nonce account stored as if it succeeded.
|
||||||
|
Reference in New Issue
Block a user