@@ -26,10 +26,7 @@ account data. A transaction is now constructed in the normal way, but with the
26
26
following additional requirements:
27
27
28
28
1 ) The durable nonce value is used in the ` recent_blockhash ` field
29
- 2 ) A ` Nonce ` instruction is issued (first?)
30
- 3 ) The appropriate transaction flag is set, signaling that the usual
31
- hash age check should be skipped and the previous requirements enforced. This
32
- may be unnecessary, see [ Runtime Support] ( #runtime-support ) below
29
+ 2 ) A ` NonceAdvance ` instruction is the first issued in the transaction
33
30
34
31
### Contract Mechanics
35
32
@@ -66,21 +63,43 @@ WithdrawInstruction(to, lamports)
66
63
success
67
64
```
68
65
69
- A client wishing to use this feature starts by creating a nonce account and
70
- depositing sufficient lamports as to make it rent-exempt. The resultant account
71
- will be in the ` Uninitialized ` state with no stored hash and thus unusable.
72
-
73
- The ` Nonce ` instruction is used to request that a new nonce be stored for the
74
- calling account. The first ` Nonce ` instruction run on a newly created account
75
- will drive the account's state to ` Initialized ` . As such, a ` Nonce ` instruction
76
- MUST be issued before the account can be used.
77
-
78
- To discard a ` NonceAccount ` , the client should issue a ` Withdraw ` instruction
79
- which withdraws all lamports, leaving a zero balance and making the account
80
- eligible for deletion.
81
-
82
- ` Nonce ` and ` Withdraw ` instructions each will only succeed if the stored
83
- blockhash is no longer resident in sysvar.recent_blockhashes.
66
+ A client wishing to use this feature starts by creating a nonce account under
67
+ the system program. This account will be in the ` Uninitialized ` state with no
68
+ stored hash, and thus unusable.
69
+
70
+ To initialize a newly created account, a ` NonceInitialize ` instruction must be
71
+ issued. This instruction takes one parameter, the ` Pubkey ` of the account's
72
+ [ authority] ( ../offline-signing/durable-nonce.md#nonce-authority ) . Nonce accounts
73
+ must be [ rent-exempt] ( rent.md#two-tiered-rent-regime ) to meet the data-persistence
74
+ requirements of the feature, and as such, require that sufficient lamports be
75
+ deposited before they can be initialized. Upon successful initialization, the
76
+ cluster's most recent blockhash is stored along with specified nonce authority
77
+ ` Pubkey ` .
78
+
79
+ The ` NonceAdvance ` instruction is used to manage the account's stored nonce
80
+ value. It stores the cluster's most recent blockhash in the account's state data,
81
+ failing if that matches the value already stored there. This check prevents
82
+ replaying transactions within the same block.
83
+
84
+ Due to nonce accounts' [ rent-exempt] ( rent.md#two-tiered-rent-regime ) requirement,
85
+ a custom withdraw instruction is used to move funds out of the account.
86
+ The ` NonceWithdraw ` instruction takes a single argument, lamports to withdraw,
87
+ and enforces rent-exemption by preventing the account's balance from falling
88
+ below the rent-exempt minimum. An exception to this check is if the final balance
89
+ would be zero lamports, which makes the account eligible for deletion. This
90
+ account closure detail has an additional requirement that the stored nonce value
91
+ must not match the cluster's most recent blockhash, as per ` NonceAdvance ` .
92
+
93
+ The account's [ nonce authority] ( ../offline-signing/durable-nonce.md#nonce-authority )
94
+ can be changed using the ` NonceAuthorize ` instruction. It takes one parameter,
95
+ the ` Pubkey ` of the new authority. Executing this instruction grants full
96
+ control over the account and its balance to the new authority.
97
+
98
+ {% hint style="info" %}
99
+ ` NonceAdvance ` , ` NonceWithdraw ` and ` NonceAuthorize ` all require the current
100
+ [ nonce authority] ( ../offline-signing/durable-nonce.md#nonce-authority ) for the
101
+ account to sign the transaction.
102
+ {% endhint %}
84
103
85
104
### Runtime Support
86
105
@@ -89,25 +108,11 @@ an extant `recent_blockhash` on the transaction and prevent fee theft via
89
108
failed transaction replay, runtime modifications are necessary.
90
109
91
110
Any transaction failing the usual ` check_hash_age ` validation will be tested
92
- for a Durable Transaction Nonce. This specifics of this test are undecided, some
93
- options:
94
-
95
- 1 ) Require that the ` Nonce ` instruction be the first in the transaction
96
- * + No ABI changes
97
- * + Fast and simple
98
- * - Sets a precedent that may lead to incompatible instruction combinations
99
- 2 ) Blind search for a ` Nonce ` instruction over all instructions in the
100
- transaction
101
- * + No ABI changes
102
- * - Potentially slow
103
- 3 ) [ 2] , but guarded by a transaction flag
104
- * - ABI changes
105
- * - Wire size increase
106
- * + We'll probably end up with some sort of flags eventually anyway
107
-
108
- Current prototyping will use [ 1] . If it is determined that a Durable Transaction
109
- Nonce is in use, the runtime will take the following actions to validate the
110
- transaction:
111
+ for a Durable Transaction Nonce. This is signaled by including a ` NonceAdvance `
112
+ instruction as the first instruction in the transaction.
113
+
114
+ If the runtime determines that a Durable Transaction Nonce is in use, it will
115
+ take the following additional actions to validate the transaction:
111
116
112
117
1 ) The ` NonceAccount ` specified in the ` Nonce ` instruction is loaded.
113
118
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.
118
123
If all three of the above checks succeed, the transaction is allowed to continue
119
124
validation.
120
125
121
- ### Open Questions
122
-
123
- * Should this feature be restricted in the number of uses per transaction?
126
+ Since transactions that fail with an ` InstructionError ` are charged a fee and
127
+ changes to their state rolled back, there is an opportunity for fee theft if a
128
+ ` NonceAdvance ` instruction is reverted. A malicious validator could replay the
129
+ failed transaction until the stored nonce is successfully advanced. Runtime
130
+ changes prevent this behavior. When a durable nonce transaction fails with an
131
+ ` InstructionError ` aside from the ` NonceAdvance ` instruction, the nonce account
132
+ is rolled back to its pre-execution state as usual. Then the runtime advances
133
+ its nonce value and the advanced nonce account stored as if it succeeded.
0 commit comments