parent
c948814eae
commit
81ae44f858
|
@ -26,7 +26,7 @@ account data. A transaction is now constructed in the normal way, but with the
|
|||
following additional requirements:
|
||||
|
||||
1) The durable nonce value is used in the `recent_blockhash` field
|
||||
2) A `NonceAdvance` instruction is the first issued in the transaction
|
||||
2) An `AdvanceNonceAccount` instruction is the first issued in the transaction
|
||||
|
||||
### Contract Mechanics
|
||||
|
||||
|
@ -67,7 +67,7 @@ A client wishing to use this feature starts by creating a nonce account under
|
|||
the system program. This account will be in the `Uninitialized` state with no
|
||||
stored hash, and thus unusable.
|
||||
|
||||
To initialize a newly created account, a `NonceInitialize` instruction must be
|
||||
To initialize a newly created account, an `InitializeNonceAccount` instruction must be
|
||||
issued. This instruction takes one parameter, the `Pubkey` of the account's
|
||||
[authority](../offline-signing/durable-nonce.md#nonce-authority). Nonce accounts
|
||||
must be [rent-exempt](rent.md#two-tiered-rent-regime) to meet the data-persistence
|
||||
|
@ -76,27 +76,27 @@ deposited before they can be initialized. Upon successful initialization, the
|
|||
cluster's most recent blockhash is stored along with specified nonce authority
|
||||
`Pubkey`.
|
||||
|
||||
The `NonceAdvance` instruction is used to manage the account's stored nonce
|
||||
The `AdvanceNonceAccount` instruction is used to manage the account's stored nonce
|
||||
value. It stores the cluster's most recent blockhash in the account's state data,
|
||||
failing if that matches the value already stored there. This check prevents
|
||||
replaying transactions within the same block.
|
||||
|
||||
Due to nonce accounts' [rent-exempt](rent.md#two-tiered-rent-regime) requirement,
|
||||
a custom withdraw instruction is used to move funds out of the account.
|
||||
The `NonceWithdraw` instruction takes a single argument, lamports to withdraw,
|
||||
The `WithdrawNonceAccount` 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`.
|
||||
must not match the cluster's most recent blockhash, as per `AdvanceNonceAccount`.
|
||||
|
||||
The account's [nonce authority](../offline-signing/durable-nonce.md#nonce-authority)
|
||||
can be changed using the `NonceAuthorize` instruction. It takes one parameter,
|
||||
can be changed using the `AuthorizeNonceAccount` 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
|
||||
`AdvanceNonceAccount`, `WithdrawNonceAccount` and `AuthorizeNonceAccount` all require the current
|
||||
[nonce authority](../offline-signing/durable-nonce.md#nonce-authority) for the
|
||||
account to sign the transaction.
|
||||
{% endhint %}
|
||||
|
@ -108,7 +108,7 @@ an extant `recent_blockhash` on the transaction and prevent fee theft via
|
|||
failed transaction replay, runtime modifications are necessary.
|
||||
|
||||
Any transaction failing the usual `check_hash_age` validation will be tested
|
||||
for a Durable Transaction Nonce. This is signaled by including a `NonceAdvance`
|
||||
for a Durable Transaction Nonce. This is signaled by including a `AdvanceNonceAccount`
|
||||
instruction as the first instruction in the transaction.
|
||||
|
||||
If the runtime determines that a Durable Transaction Nonce is in use, it will
|
||||
|
@ -124,10 +124,10 @@ If all three of the above checks succeed, the transaction is allowed to continue
|
|||
validation.
|
||||
|
||||
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
|
||||
`NonceAdvance` instruction is reverted. A malicious validator could replay the
|
||||
changes to their state rolled back, there is an opportunity for fee theft if an
|
||||
`AdvanceNonceAccount` 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
|
||||
`InstructionError` aside from the `AdvanceNonceAccount` 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.
|
||||
|
|
|
@ -24,7 +24,7 @@ pub fn transaction_uses_durable_nonce(tx: &Transaction) -> Option<&CompiledInstr
|
|||
}
|
||||
})
|
||||
.filter(|maybe_ix| match limited_deserialize(&maybe_ix.data) {
|
||||
Ok(SystemInstruction::NonceAdvance) => true,
|
||||
Ok(SystemInstruction::AdvanceNonceAccount) => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -236,14 +236,14 @@ pub fn process_instruction(
|
|||
let to = next_keyed_account(keyed_accounts_iter)?;
|
||||
transfer_lamports(from, to, lamports)
|
||||
}
|
||||
SystemInstruction::NonceAdvance => {
|
||||
SystemInstruction::AdvanceNonceAccount => {
|
||||
let me = &mut next_keyed_account(keyed_accounts_iter)?;
|
||||
me.nonce_advance(
|
||||
&RecentBlockhashes::from_keyed_account(next_keyed_account(keyed_accounts_iter)?)?,
|
||||
&signers,
|
||||
)
|
||||
}
|
||||
SystemInstruction::NonceWithdraw(lamports) => {
|
||||
SystemInstruction::WithdrawNonceAccount(lamports) => {
|
||||
let me = &mut next_keyed_account(keyed_accounts_iter)?;
|
||||
let to = &mut next_keyed_account(keyed_accounts_iter)?;
|
||||
me.nonce_withdraw(
|
||||
|
@ -254,7 +254,7 @@ pub fn process_instruction(
|
|||
&signers,
|
||||
)
|
||||
}
|
||||
SystemInstruction::NonceInitialize(authorized) => {
|
||||
SystemInstruction::InitializeNonceAccount(authorized) => {
|
||||
let me = &mut next_keyed_account(keyed_accounts_iter)?;
|
||||
me.nonce_initialize(
|
||||
&authorized,
|
||||
|
@ -262,7 +262,7 @@ pub fn process_instruction(
|
|||
&Rent::from_keyed_account(next_keyed_account(keyed_accounts_iter)?)?,
|
||||
)
|
||||
}
|
||||
SystemInstruction::NonceAuthorize(nonce_authority) => {
|
||||
SystemInstruction::AuthorizeNonceAccount(nonce_authority) => {
|
||||
let me = &mut next_keyed_account(keyed_accounts_iter)?;
|
||||
me.nonce_authorize(&nonce_authority, &signers)
|
||||
}
|
||||
|
@ -902,7 +902,7 @@ mod tests {
|
|||
super::process_instruction(
|
||||
&Pubkey::default(),
|
||||
&mut [],
|
||||
&serialize(&SystemInstruction::NonceAdvance).unwrap()
|
||||
&serialize(&SystemInstruction::AdvanceNonceAccount).unwrap()
|
||||
),
|
||||
Err(InstructionError::NotEnoughAccountKeys),
|
||||
);
|
||||
|
@ -918,7 +918,7 @@ mod tests {
|
|||
true,
|
||||
&mut Account::default(),
|
||||
),],
|
||||
&serialize(&SystemInstruction::NonceAdvance).unwrap(),
|
||||
&serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(),
|
||||
),
|
||||
Err(InstructionError::NotEnoughAccountKeys),
|
||||
);
|
||||
|
@ -937,7 +937,7 @@ mod tests {
|
|||
&mut Account::default(),
|
||||
),
|
||||
],
|
||||
&serialize(&SystemInstruction::NonceAdvance).unwrap(),
|
||||
&serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(),
|
||||
),
|
||||
Err(InstructionError::InvalidArgument),
|
||||
);
|
||||
|
@ -964,7 +964,7 @@ mod tests {
|
|||
&mut sysvar::rent::create_account(1, &Rent::free()),
|
||||
),
|
||||
],
|
||||
&serialize(&SystemInstruction::NonceInitialize(Pubkey::default())).unwrap(),
|
||||
&serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
|
@ -981,7 +981,7 @@ mod tests {
|
|||
),
|
||||
),
|
||||
],
|
||||
&serialize(&SystemInstruction::NonceAdvance).unwrap(),
|
||||
&serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(),
|
||||
),
|
||||
Ok(()),
|
||||
);
|
||||
|
@ -1006,7 +1006,7 @@ mod tests {
|
|||
super::process_instruction(
|
||||
&Pubkey::default(),
|
||||
&mut [],
|
||||
&serialize(&SystemInstruction::NonceWithdraw(42)).unwrap(),
|
||||
&serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
|
||||
),
|
||||
Err(InstructionError::NotEnoughAccountKeys),
|
||||
);
|
||||
|
@ -1022,7 +1022,7 @@ mod tests {
|
|||
true,
|
||||
&mut Account::default(),
|
||||
),],
|
||||
&serialize(&SystemInstruction::NonceWithdraw(42)).unwrap(),
|
||||
&serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
|
||||
),
|
||||
Err(InstructionError::NotEnoughAccountKeys),
|
||||
);
|
||||
|
@ -1042,7 +1042,7 @@ mod tests {
|
|||
&mut Account::default(),
|
||||
),
|
||||
],
|
||||
&serialize(&SystemInstruction::NonceWithdraw(42)).unwrap(),
|
||||
&serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
|
||||
),
|
||||
Err(InstructionError::InvalidArgument),
|
||||
);
|
||||
|
@ -1070,7 +1070,7 @@ mod tests {
|
|||
),
|
||||
KeyedAccount::new(&sysvar::rent::id(), false, &mut Account::default(),),
|
||||
],
|
||||
&serialize(&SystemInstruction::NonceWithdraw(42)).unwrap(),
|
||||
&serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
|
||||
),
|
||||
Err(InstructionError::InvalidArgument),
|
||||
);
|
||||
|
@ -1102,7 +1102,7 @@ mod tests {
|
|||
&mut sysvar::rent::create_account(1, &Rent::free())
|
||||
),
|
||||
],
|
||||
&serialize(&SystemInstruction::NonceWithdraw(42)).unwrap(),
|
||||
&serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
|
||||
),
|
||||
Ok(()),
|
||||
);
|
||||
|
@ -1114,7 +1114,7 @@ mod tests {
|
|||
super::process_instruction(
|
||||
&Pubkey::default(),
|
||||
&mut [],
|
||||
&serialize(&SystemInstruction::NonceInitialize(Pubkey::default())).unwrap(),
|
||||
&serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(),
|
||||
),
|
||||
Err(InstructionError::NotEnoughAccountKeys),
|
||||
);
|
||||
|
@ -1130,7 +1130,7 @@ mod tests {
|
|||
true,
|
||||
&mut nonce_state::create_account(1_000_000),
|
||||
),],
|
||||
&serialize(&SystemInstruction::NonceInitialize(Pubkey::default())).unwrap(),
|
||||
&serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(),
|
||||
),
|
||||
Err(InstructionError::NotEnoughAccountKeys),
|
||||
);
|
||||
|
@ -1153,7 +1153,7 @@ mod tests {
|
|||
&mut Account::default(),
|
||||
),
|
||||
],
|
||||
&serialize(&SystemInstruction::NonceInitialize(Pubkey::default())).unwrap(),
|
||||
&serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(),
|
||||
),
|
||||
Err(InstructionError::InvalidArgument),
|
||||
);
|
||||
|
@ -1180,7 +1180,7 @@ mod tests {
|
|||
),
|
||||
KeyedAccount::new(&sysvar::rent::id(), false, &mut Account::default(),),
|
||||
],
|
||||
&serialize(&SystemInstruction::NonceInitialize(Pubkey::default())).unwrap(),
|
||||
&serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(),
|
||||
),
|
||||
Err(InstructionError::InvalidArgument),
|
||||
);
|
||||
|
@ -1211,7 +1211,7 @@ mod tests {
|
|||
&mut sysvar::rent::create_account(1, &Rent::free())
|
||||
),
|
||||
],
|
||||
&serialize(&SystemInstruction::NonceInitialize(Pubkey::default())).unwrap(),
|
||||
&serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(),
|
||||
),
|
||||
Ok(()),
|
||||
);
|
||||
|
@ -1238,14 +1238,14 @@ mod tests {
|
|||
&mut sysvar::rent::create_account(1, &Rent::free()),
|
||||
),
|
||||
],
|
||||
&serialize(&SystemInstruction::NonceInitialize(Pubkey::default())).unwrap(),
|
||||
&serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
super::process_instruction(
|
||||
&Pubkey::default(),
|
||||
&mut [KeyedAccount::new(&Pubkey::default(), true, &mut nonce_acc,),],
|
||||
&serialize(&SystemInstruction::NonceAuthorize(Pubkey::default(),)).unwrap(),
|
||||
&serialize(&SystemInstruction::AuthorizeNonceAccount(Pubkey::default(),)).unwrap(),
|
||||
),
|
||||
Ok(()),
|
||||
);
|
||||
|
|
|
@ -92,15 +92,15 @@ pub enum SystemInstruction {
|
|||
space: u64,
|
||||
program_id: Pubkey,
|
||||
},
|
||||
/// `NonceAdvance` consumes a stored nonce, replacing it with a successor
|
||||
/// `AdvanceNonceAccount` consumes a stored nonce, replacing it with a successor
|
||||
///
|
||||
/// Expects 2 Accounts:
|
||||
/// 0 - A NonceAccount
|
||||
/// 1 - RecentBlockhashes sysvar
|
||||
///
|
||||
/// The current authority must sign a transaction executing this instrucion
|
||||
NonceAdvance,
|
||||
/// `NonceWithdraw` transfers funds out of the nonce account
|
||||
AdvanceNonceAccount,
|
||||
/// `WithdrawNonceAccount` transfers funds out of the nonce account
|
||||
///
|
||||
/// Expects 4 Accounts:
|
||||
/// 0 - A NonceAccount
|
||||
|
@ -112,8 +112,8 @@ pub enum SystemInstruction {
|
|||
/// account balance above the rent exempt reserve or at zero.
|
||||
///
|
||||
/// The current authority must sign a transaction executing this instruction
|
||||
NonceWithdraw(u64),
|
||||
/// `NonceInitialize` drives state of Uninitalized NonceAccount to Initialized,
|
||||
WithdrawNonceAccount(u64),
|
||||
/// `InitializeNonceAccount` drives state of Uninitalized NonceAccount to Initialized,
|
||||
/// setting the nonce value.
|
||||
///
|
||||
/// Expects 3 Accounts:
|
||||
|
@ -126,8 +126,8 @@ pub enum SystemInstruction {
|
|||
///
|
||||
/// No signatures are required to execute this instruction, enabling derived
|
||||
/// nonce account addresses
|
||||
NonceInitialize(Pubkey),
|
||||
/// `NonceAuthorize` changes the entity authorized to execute nonce instructions
|
||||
InitializeNonceAccount(Pubkey),
|
||||
/// `AuthorizeNonceAccount` changes the entity authorized to execute nonce instructions
|
||||
/// on the account
|
||||
///
|
||||
/// Expects 1 Account:
|
||||
|
@ -136,7 +136,7 @@ pub enum SystemInstruction {
|
|||
/// The `Pubkey` parameter identifies the entity to authorize
|
||||
///
|
||||
/// The current authority must sign a transaction executing this instruction
|
||||
NonceAuthorize(Pubkey),
|
||||
AuthorizeNonceAccount(Pubkey),
|
||||
}
|
||||
|
||||
pub fn create_account(
|
||||
|
@ -256,7 +256,7 @@ pub fn create_nonce_account_with_seed(
|
|||
),
|
||||
Instruction::new(
|
||||
system_program::id(),
|
||||
&SystemInstruction::NonceInitialize(*authority),
|
||||
&SystemInstruction::InitializeNonceAccount(*authority),
|
||||
vec![
|
||||
AccountMeta::new(*nonce_pubkey, false),
|
||||
AccountMeta::new_readonly(recent_blockhashes::id(), false),
|
||||
|
@ -282,7 +282,7 @@ pub fn create_nonce_account(
|
|||
),
|
||||
Instruction::new(
|
||||
system_program::id(),
|
||||
&SystemInstruction::NonceInitialize(*authority),
|
||||
&SystemInstruction::InitializeNonceAccount(*authority),
|
||||
vec![
|
||||
AccountMeta::new(*nonce_pubkey, false),
|
||||
AccountMeta::new_readonly(recent_blockhashes::id(), false),
|
||||
|
@ -300,7 +300,7 @@ pub fn nonce_advance(nonce_pubkey: &Pubkey, authorized_pubkey: &Pubkey) -> Instr
|
|||
.with_signer(authorized_pubkey);
|
||||
Instruction::new(
|
||||
system_program::id(),
|
||||
&SystemInstruction::NonceAdvance,
|
||||
&SystemInstruction::AdvanceNonceAccount,
|
||||
account_metas,
|
||||
)
|
||||
}
|
||||
|
@ -320,7 +320,7 @@ pub fn nonce_withdraw(
|
|||
.with_signer(authorized_pubkey);
|
||||
Instruction::new(
|
||||
system_program::id(),
|
||||
&SystemInstruction::NonceWithdraw(lamports),
|
||||
&SystemInstruction::WithdrawNonceAccount(lamports),
|
||||
account_metas,
|
||||
)
|
||||
}
|
||||
|
@ -333,7 +333,7 @@ pub fn nonce_authorize(
|
|||
let account_metas = vec![AccountMeta::new(*nonce_pubkey, false)].with_signer(authorized_pubkey);
|
||||
Instruction::new(
|
||||
system_program::id(),
|
||||
&SystemInstruction::NonceAuthorize(*new_authority),
|
||||
&SystemInstruction::AuthorizeNonceAccount(*new_authority),
|
||||
account_metas,
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue