Verify frozen bank from snapshot by hashing (#8184)
This commit is contained in:
parent
1528959327
commit
7614af2a45
|
@ -374,6 +374,7 @@ impl Accounts {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn verify_bank_hash(&self, slot: Slot, ancestors: &HashMap<Slot, usize>) -> bool {
|
pub fn verify_bank_hash(&self, slot: Slot, ancestors: &HashMap<Slot, usize>) -> bool {
|
||||||
if let Err(err) = self.accounts_db.verify_bank_hash(slot, ancestors) {
|
if let Err(err) = self.accounts_db.verify_bank_hash(slot, ancestors) {
|
||||||
warn!("verify_bank_hash failed: {:?}", err);
|
warn!("verify_bank_hash failed: {:?}", err);
|
||||||
|
|
|
@ -1826,19 +1826,38 @@ impl Bank {
|
||||||
|
|
||||||
/// Recalculate the hash_internal_state from the account stores. Would be used to verify a
|
/// Recalculate the hash_internal_state from the account stores. Would be used to verify a
|
||||||
/// snapshot.
|
/// snapshot.
|
||||||
pub fn verify_hash_internal_state(&self) -> bool {
|
#[must_use]
|
||||||
|
fn verify_bank_hash(&self) -> bool {
|
||||||
self.rc
|
self.rc
|
||||||
.accounts
|
.accounts
|
||||||
.verify_bank_hash(self.slot(), &self.ancestors)
|
.verify_bank_hash(self.slot(), &self.ancestors)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
fn verify_hash(&self) -> bool {
|
||||||
|
assert!(self.is_frozen());
|
||||||
|
let calculated_hash = self.hash_internal_state();
|
||||||
|
let expected_hash = self.hash();
|
||||||
|
|
||||||
|
if calculated_hash == expected_hash {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
warn!(
|
||||||
|
"verify failed: slot: {}, {} (calculated) != {} (expected)",
|
||||||
|
self.slot(),
|
||||||
|
calculated_hash,
|
||||||
|
expected_hash
|
||||||
|
);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A snapshot bank should be purged of 0 lamport accounts which are not part of the hash
|
/// A snapshot bank should be purged of 0 lamport accounts which are not part of the hash
|
||||||
/// calculation and could shield other real accounts.
|
/// calculation and could shield other real accounts.
|
||||||
pub fn verify_snapshot_bank(&self) -> bool {
|
pub fn verify_snapshot_bank(&self) -> bool {
|
||||||
self.purge_zero_lamport_accounts();
|
self.purge_zero_lamport_accounts();
|
||||||
self.rc
|
// Order and short-circuiting is significant; verify_hash requires a valid bank hash
|
||||||
.accounts
|
self.verify_bank_hash() && self.verify_hash()
|
||||||
.verify_bank_hash(self.slot(), &self.ancestors)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the number of hashes per tick
|
/// Return the number of hashes per tick
|
||||||
|
@ -3085,21 +3104,21 @@ mod tests {
|
||||||
assert_eq!(bank0.get_account(&keypair.pubkey()).unwrap().lamports, 10);
|
assert_eq!(bank0.get_account(&keypair.pubkey()).unwrap().lamports, 10);
|
||||||
assert_eq!(bank1.get_account(&keypair.pubkey()), None);
|
assert_eq!(bank1.get_account(&keypair.pubkey()), None);
|
||||||
|
|
||||||
assert!(bank0.verify_hash_internal_state());
|
assert!(bank0.verify_bank_hash());
|
||||||
|
|
||||||
// Squash and then verify hash_internal value
|
// Squash and then verify hash_internal value
|
||||||
bank0.squash();
|
bank0.squash();
|
||||||
assert!(bank0.verify_hash_internal_state());
|
assert!(bank0.verify_bank_hash());
|
||||||
|
|
||||||
bank1.squash();
|
bank1.squash();
|
||||||
assert!(bank1.verify_hash_internal_state());
|
assert!(bank1.verify_bank_hash());
|
||||||
|
|
||||||
// keypair should have 0 tokens on both forks
|
// keypair should have 0 tokens on both forks
|
||||||
assert_eq!(bank0.get_account(&keypair.pubkey()), None);
|
assert_eq!(bank0.get_account(&keypair.pubkey()), None);
|
||||||
assert_eq!(bank1.get_account(&keypair.pubkey()), None);
|
assert_eq!(bank1.get_account(&keypair.pubkey()), None);
|
||||||
bank1.purge_zero_lamport_accounts();
|
bank1.purge_zero_lamport_accounts();
|
||||||
|
|
||||||
assert!(bank1.verify_hash_internal_state());
|
assert!(bank1.verify_bank_hash());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -3820,7 +3839,7 @@ mod tests {
|
||||||
let pubkey2 = Pubkey::new_rand();
|
let pubkey2 = Pubkey::new_rand();
|
||||||
info!("transfer 2 {}", pubkey2);
|
info!("transfer 2 {}", pubkey2);
|
||||||
bank2.transfer(10, &mint_keypair, &pubkey2).unwrap();
|
bank2.transfer(10, &mint_keypair, &pubkey2).unwrap();
|
||||||
assert!(bank2.verify_hash_internal_state());
|
assert!(bank2.verify_bank_hash());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -3843,17 +3862,40 @@ mod tests {
|
||||||
|
|
||||||
// Checkpointing should never modify the checkpoint's state once frozen
|
// Checkpointing should never modify the checkpoint's state once frozen
|
||||||
let bank0_state = bank0.hash_internal_state();
|
let bank0_state = bank0.hash_internal_state();
|
||||||
assert!(bank2.verify_hash_internal_state());
|
assert!(bank2.verify_bank_hash());
|
||||||
let bank3 = new_from_parent(&bank0);
|
let bank3 = new_from_parent(&bank0);
|
||||||
assert_eq!(bank0_state, bank0.hash_internal_state());
|
assert_eq!(bank0_state, bank0.hash_internal_state());
|
||||||
assert!(bank2.verify_hash_internal_state());
|
assert!(bank2.verify_bank_hash());
|
||||||
assert!(bank3.verify_hash_internal_state());
|
assert!(bank3.verify_bank_hash());
|
||||||
|
|
||||||
let pubkey2 = Pubkey::new_rand();
|
let pubkey2 = Pubkey::new_rand();
|
||||||
info!("transfer 2 {}", pubkey2);
|
info!("transfer 2 {}", pubkey2);
|
||||||
bank2.transfer(10, &mint_keypair, &pubkey2).unwrap();
|
bank2.transfer(10, &mint_keypair, &pubkey2).unwrap();
|
||||||
assert!(bank2.verify_hash_internal_state());
|
assert!(bank2.verify_bank_hash());
|
||||||
assert!(bank3.verify_hash_internal_state());
|
assert!(bank3.verify_bank_hash());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic(expected = "assertion failed: self.is_frozen()")]
|
||||||
|
fn test_verify_hash_unfrozen() {
|
||||||
|
let (genesis_config, _mint_keypair) = create_genesis_config(2_000);
|
||||||
|
let bank = Bank::new(&genesis_config);
|
||||||
|
assert!(bank.verify_hash());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_verify_snapshot_bank() {
|
||||||
|
let pubkey = Pubkey::new_rand();
|
||||||
|
let (genesis_config, mint_keypair) = create_genesis_config(2_000);
|
||||||
|
let bank = Bank::new(&genesis_config);
|
||||||
|
|
||||||
|
bank.transfer(1_000, &mint_keypair, &pubkey).unwrap();
|
||||||
|
bank.freeze();
|
||||||
|
assert!(bank.verify_snapshot_bank());
|
||||||
|
|
||||||
|
// tamper the bank after freeze!
|
||||||
|
bank.increment_signature_count(1);
|
||||||
|
assert!(!bank.verify_snapshot_bank());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that two bank forks with the same accounts should not hash to the same value.
|
// Test that two bank forks with the same accounts should not hash to the same value.
|
||||||
|
|
Loading…
Reference in New Issue