Skip to content

Commit c3d4975

Browse files
authored
migration: validate that migrationary blocks are VoM (#566)
Split from #502 #### Problem Blocks in the migration period should not contain user transactions. #565 handles this on the block packing side, but we need verification on the replay side. #### Summary of Changes Mark migration period blocks as vote only. During replay mark vote only blocks which contain user transactions as dead.
1 parent 7f37a4d commit c3d4975

File tree

2 files changed

+39
-6
lines changed

2 files changed

+39
-6
lines changed

core/src/replay_stage.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,7 @@ impl ReplayStage {
809809
&slot_status_notifier,
810810
&mut progress,
811811
&mut replay_timing,
812+
migration_status.as_ref(),
812813
);
813814
generate_new_bank_forks_time.stop();
814815

@@ -4359,6 +4360,7 @@ impl ReplayStage {
43594360
slot_status_notifier: &Option<SlotStatusNotifier>,
43604361
progress: &mut ProgressMap,
43614362
replay_timing: &mut ReplayLoopTiming,
4363+
migration_status: &MigrationStatus,
43624364
) {
43634365
// Find the next slot that chains to the old slot
43644366
let mut generate_new_bank_forks_read_lock =
@@ -4406,14 +4408,21 @@ impl ReplayStage {
44064408
parent_slot,
44074409
forks.root()
44084410
);
4411+
// Migration period banks are VoM
4412+
let options = NewBankOptions {
4413+
vote_only_bank: migration_status.should_bank_be_vote_only(child_slot),
4414+
};
4415+
if options.vote_only_bank {
4416+
info!("Replaying block in slot {child_slot} in VoM");
4417+
}
44094418
let child_bank = Self::new_bank_from_parent_with_notify(
44104419
parent_bank.clone(),
44114420
child_slot,
44124421
forks.root(),
44134422
&leader,
44144423
rpc_subscriptions,
44154424
slot_status_notifier,
4416-
NewBankOptions::default(),
4425+
options,
44174426
);
44184427
blockstore_processor::set_alpenglow_ticks(&child_bank);
44194428
let empty: Vec<Pubkey> = vec![];
@@ -4433,7 +4442,6 @@ impl ReplayStage {
44334442
let mut generate_new_bank_forks_write_lock =
44344443
Measure::start("generate_new_bank_forks_write_lock");
44354444

4436-
// TODO(ksn): should we have this if-statement check?
44374445
if !new_banks.is_empty() {
44384446
let mut forks = bank_forks.write().unwrap();
44394447
let root = forks.root();
@@ -4805,6 +4813,7 @@ pub(crate) mod tests {
48054813
&None,
48064814
&mut progress,
48074815
&mut replay_timing,
4816+
&MigrationStatus::default(),
48084817
);
48094818
assert!(bank_forks
48104819
.read()
@@ -4829,6 +4838,7 @@ pub(crate) mod tests {
48294838
&None,
48304839
&mut progress,
48314840
&mut replay_timing,
4841+
&MigrationStatus::default(),
48324842
);
48334843
assert!(bank_forks
48344844
.read()
@@ -6732,6 +6742,7 @@ pub(crate) mod tests {
67326742
&None,
67336743
&mut progress,
67346744
&mut replay_timing,
6745+
&MigrationStatus::default(),
67356746
);
67366747
assert_eq!(bank_forks.read().unwrap().active_bank_slots(), vec![3]);
67376748

@@ -6762,6 +6773,7 @@ pub(crate) mod tests {
67626773
&None,
67636774
&mut progress,
67646775
&mut replay_timing,
6776+
&MigrationStatus::default(),
67656777
);
67666778
assert_eq!(bank_forks.read().unwrap().active_bank_slots(), vec![5]);
67676779

@@ -6793,6 +6805,7 @@ pub(crate) mod tests {
67936805
&None,
67946806
&mut progress,
67956807
&mut replay_timing,
6808+
&MigrationStatus::default(),
67966809
);
67976810
assert_eq!(bank_forks.read().unwrap().active_bank_slots(), vec![6]);
67986811

@@ -6823,6 +6836,7 @@ pub(crate) mod tests {
68236836
&None,
68246837
&mut progress,
68256838
&mut replay_timing,
6839+
&MigrationStatus::default(),
68266840
);
68276841
assert_eq!(bank_forks.read().unwrap().active_bank_slots(), vec![7]);
68286842
}

ledger/src/blockstore_processor.rs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -833,6 +833,9 @@ pub enum BlockstoreProcessorError {
833833

834834
#[error("non consecutive leader slot for bank {0} parent {1}")]
835835
NonConsecutiveLeaderSlot(Slot, Slot),
836+
837+
#[error("user transactions found in vote only mode bank at slot {0}")]
838+
UserTransactionsInVoteOnlyBank(Slot),
836839
}
837840

838841
/// Callback for accessing bank state after each slot is confirmed while
@@ -1673,14 +1676,30 @@ fn confirm_slot_entries(
16731676
.expect("Transaction verification generates entries");
16741677

16751678
let mut replay_timer = Measure::start("replay_elapsed");
1679+
let is_vote_only_bank = bank.vote_only_bank();
16761680
let replay_entries: Vec<_> = entries
16771681
.into_iter()
16781682
.zip(entry_tx_starting_indexes)
1679-
.map(|(entry, tx_starting_index)| ReplayEntry {
1680-
entry,
1681-
starting_index: tx_starting_index,
1683+
.map(|(entry, tx_starting_index)| {
1684+
// If bank is in vote-only mode, validate that entries contain only vote transactions
1685+
if let EntryType::Transactions(ref transactions) = entry {
1686+
if is_vote_only_bank
1687+
&& transactions
1688+
.iter()
1689+
.any(|tx| !tx.is_simple_vote_transaction())
1690+
{
1691+
return Err(BlockstoreProcessorError::UserTransactionsInVoteOnlyBank(
1692+
bank.slot(),
1693+
));
1694+
}
1695+
}
1696+
Ok(ReplayEntry {
1697+
entry,
1698+
starting_index: tx_starting_index,
1699+
})
16821700
})
1683-
.collect();
1701+
.collect::<result::Result<Vec<_>, _>>()?;
1702+
16841703
let process_result = process_entries(
16851704
bank,
16861705
replay_tx_thread_pool,

0 commit comments

Comments
 (0)