Verifies EAH in SnapshotHash (#28775)

This commit is contained in:
Brooks Prumo 2022-11-14 15:02:08 -06:00 committed by GitHub
parent 1e2989501f
commit 503da50f2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 52 additions and 8 deletions

View File

@ -149,6 +149,30 @@ contain the EAH.
Same as (4). Same as (4).
#### Snapshot Verification
If a snapshot archive includes an EAH, we want to verify the EAH is correct at
load time (instead of waiting until `stop slot`, which could be far in the
future).
If the snapshot archive is for a slot within the `calculation window`†¹, then it
*must* include an EAH. The snapshot hash itself will now also incorporate the
EAH. In pseudo code:
```pseudo
if slot is in calculation window
let snapshot hash = hash(accounts hash, epoch accounts hash)
else
let snapshot hash = accounts hash
endif
```
Since loading from a snapshot archive already verifies the snapshot archive's
hash against the deserialized bank, the EAH will be implicitly verified as
well.
†¹: The `calculation window` is `[start slot, stop slot)`, based on the epoch
of the referenced `Bank`.
#### Corner Cases #### Corner Cases
#### Minimum Slots per Epoch #### Minimum Slots per Epoch

View File

@ -6984,7 +6984,8 @@ impl Bank {
pub fn get_snapshot_hash(&self) -> SnapshotHash { pub fn get_snapshot_hash(&self) -> SnapshotHash {
let accounts_hash = self.get_accounts_hash(); let accounts_hash = self.get_accounts_hash();
SnapshotHash::new(&accounts_hash) let epoch_accounts_hash = self.get_epoch_accounts_hash_to_serialize();
SnapshotHash::new(&accounts_hash, epoch_accounts_hash.as_ref())
} }
pub fn get_thread_pool(&self) -> &ThreadPool { pub fn get_thread_pool(&self) -> &ThreadPool {

View File

@ -1,5 +1,11 @@
//! Helper types and functions for handling and dealing with snapshot hashes. //! Helper types and functions for handling and dealing with snapshot hashes.
use solana_sdk::{clock::Slot, hash::Hash}; use {
crate::epoch_accounts_hash::EpochAccountsHash,
solana_sdk::{
clock::Slot,
hash::{Hash, Hasher},
},
};
/// At startup, when loading from snapshots, the starting snapshot hashes need to be passed to /// At startup, when loading from snapshots, the starting snapshot hashes need to be passed to
/// SnapshotPackagerService, which is in charge of pushing the hashes to CRDS. This struct wraps /// SnapshotPackagerService, which is in charge of pushing the hashes to CRDS. This struct wraps
@ -48,11 +54,19 @@ pub struct IncrementalSnapshotHashes {
pub struct SnapshotHash(pub Hash); pub struct SnapshotHash(pub Hash);
impl SnapshotHash { impl SnapshotHash {
/// Make a snapshot hash from an accounts hash /// Make a snapshot hash from an accounts hash and epoch accounts hash
///
/// Will soon also incorporate the epoch accounts hash
#[must_use] #[must_use]
pub fn new(accounts_hash: &Hash) -> Self { pub fn new(accounts_hash: &Hash, epoch_accounts_hash: Option<&EpochAccountsHash>) -> Self {
Self(*accounts_hash) let snapshot_hash = match epoch_accounts_hash {
None => *accounts_hash,
Some(epoch_accounts_hash) => {
let mut hasher = Hasher::default();
hasher.hash(accounts_hash.as_ref());
hasher.hash(epoch_accounts_hash.as_ref().as_ref());
hasher.result()
}
};
Self(snapshot_hash)
} }
} }

View File

@ -3,6 +3,7 @@ use {
accounts::Accounts, accounts::Accounts,
accounts_db::SnapshotStorages, accounts_db::SnapshotStorages,
bank::{Bank, BankSlotDelta}, bank::{Bank, BankSlotDelta},
epoch_accounts_hash::EpochAccountsHash,
rent_collector::RentCollector, rent_collector::RentCollector,
snapshot_archive_info::{SnapshotArchiveInfo, SnapshotArchiveInfoGetter}, snapshot_archive_info::{SnapshotArchiveInfo, SnapshotArchiveInfoGetter},
snapshot_hash::SnapshotHash, snapshot_hash::SnapshotHash,
@ -107,6 +108,7 @@ impl AccountsPackage {
incremental_snapshot_archives_dir: incremental_snapshot_archives_dir incremental_snapshot_archives_dir: incremental_snapshot_archives_dir
.as_ref() .as_ref()
.to_path_buf(), .to_path_buf(),
epoch_accounts_hash: bank.get_epoch_accounts_hash_to_serialize(),
}; };
Ok(Self::_new( Ok(Self::_new(
package_type, package_type,
@ -177,6 +179,7 @@ impl AccountsPackage {
snapshot_version: SnapshotVersion::default(), snapshot_version: SnapshotVersion::default(),
full_snapshot_archives_dir: PathBuf::default(), full_snapshot_archives_dir: PathBuf::default(),
incremental_snapshot_archives_dir: PathBuf::default(), incremental_snapshot_archives_dir: PathBuf::default(),
epoch_accounts_hash: Option::default(),
}), }),
enqueued: Instant::now(), enqueued: Instant::now(),
} }
@ -217,6 +220,7 @@ pub struct SupplementalSnapshotInfo {
pub snapshot_version: SnapshotVersion, pub snapshot_version: SnapshotVersion,
pub full_snapshot_archives_dir: PathBuf, pub full_snapshot_archives_dir: PathBuf,
pub incremental_snapshot_archives_dir: PathBuf, pub incremental_snapshot_archives_dir: PathBuf,
pub epoch_accounts_hash: Option<EpochAccountsHash>,
} }
/// Accounts packages are sent to the Accounts Hash Verifier for processing. There are multiple /// Accounts packages are sent to the Accounts Hash Verifier for processing. There are multiple
@ -247,7 +251,8 @@ impl SnapshotPackage {
let Some(snapshot_info) = accounts_package.snapshot_info else { let Some(snapshot_info) = accounts_package.snapshot_info else {
panic!("The AccountsPackage must have snapshot info in order to make a SnapshotPackage!"); panic!("The AccountsPackage must have snapshot info in order to make a SnapshotPackage!");
}; };
let snapshot_hash = SnapshotHash::new(&accounts_hash); let snapshot_hash =
SnapshotHash::new(&accounts_hash, snapshot_info.epoch_accounts_hash.as_ref());
let mut snapshot_storages = accounts_package.snapshot_storages; let mut snapshot_storages = accounts_package.snapshot_storages;
let snapshot_archive_path = match snapshot_type { let snapshot_archive_path = match snapshot_type {
SnapshotType::FullSnapshot => snapshot_utils::build_full_snapshot_archive_path( SnapshotType::FullSnapshot => snapshot_utils::build_full_snapshot_archive_path(