Nonce cleanup followup (bp #13868) (#13922)

* runtime: Factor out `DurableNoncePartial` finishing logic and add tests

(cherry picked from commit 8df2a4bac0)

* accounts: Don't assume fee-payer is the first account

(cherry picked from commit 47af5933ca)

* accounts: Replace nonce_rollback unreachable block with descriptive panic

(cherry picked from commit be7760caa1)

* sdk: Check owner when verifying nonce accounts

(cherry picked from commit 274312ebb5)

* runtime: Replace `HashAgeKind` with `NonceRollbackInfo`

(cherry picked from commit 404fc1570d)

* Make `Accounts::is_non_loader_key()` a method on `Message`

(cherry picked from commit 17defbff13)

Co-authored-by: Trent Nelson <trent@solana.com>
This commit is contained in:
mergify[bot]
2020-12-02 21:34:21 +00:00
committed by GitHub
parent 501fea7a3c
commit da1796f97a
8 changed files with 426 additions and 292 deletions

View File

@@ -298,6 +298,10 @@ impl Message {
false
}
pub fn is_non_loader_key(&self, key: &Pubkey, key_index: usize) -> bool {
!self.program_ids().contains(&key) || self.is_key_passed_to_program(key_index)
}
pub fn program_position(&self, index: usize) -> Option<usize> {
let program_ids = self.program_ids();
program_ids
@@ -794,4 +798,61 @@ mod tests {
);
}
}
#[test]
fn test_program_ids() {
let key0 = Pubkey::new_unique();
let key1 = Pubkey::new_unique();
let loader2 = Pubkey::new_unique();
let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])];
let message = Message::new_with_compiled_instructions(
1,
0,
2,
vec![key0, key1, loader2],
Hash::default(),
instructions,
);
assert_eq!(message.program_ids(), vec![&loader2]);
}
#[test]
fn test_is_key_passed_to_program() {
let key0 = Pubkey::new_unique();
let key1 = Pubkey::new_unique();
let loader2 = Pubkey::new_unique();
let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])];
let message = Message::new_with_compiled_instructions(
1,
0,
2,
vec![key0, key1, loader2],
Hash::default(),
instructions,
);
assert!(message.is_key_passed_to_program(0));
assert!(message.is_key_passed_to_program(1));
assert!(!message.is_key_passed_to_program(2));
}
#[test]
fn test_is_non_loader_key() {
let key0 = Pubkey::new_unique();
let key1 = Pubkey::new_unique();
let loader2 = Pubkey::new_unique();
let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])];
let message = Message::new_with_compiled_instructions(
1,
0,
2,
vec![key0, key1, loader2],
Hash::default(),
instructions,
);
assert!(message.is_non_loader_key(&key0, 0));
assert!(message.is_non_loader_key(&key1, 1));
assert!(!message.is_non_loader_key(&loader2, 2));
}
}

View File

@@ -20,6 +20,9 @@ pub fn create_account(lamports: u64) -> RefCell<Account> {
}
pub fn verify_nonce_account(acc: &Account, hash: &Hash) -> bool {
if acc.owner != crate::system_program::id() {
return false;
}
match StateMut::<Versions>::state(acc).map(|v| v.convert_to_current()) {
Ok(State::Initialized(ref data)) => *hash == data.blockhash,
_ => false,
@@ -35,3 +38,23 @@ pub fn fee_calculator_of(account: &Account) -> Option<FeeCalculator> {
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::pubkey::Pubkey;
#[test]
fn test_verify_bad_account_owner_fails() {
let program_id = Pubkey::new_unique();
assert_ne!(program_id, crate::system_program::id());
let account = Account::new_data_with_space(
42,
&Versions::new_current(State::Uninitialized),
State::size(),
&program_id,
)
.expect("nonce_account");
assert!(!verify_nonce_account(&account, &Hash::default()));
}
}