Blob verify (#4951)
* Ensure signable data is not out of range * Add a broadcast stage that puts bad sizes in blobs * Resign blob after modifyign size * Remove assertions that fail when size != meta.size
This commit is contained in:
@ -463,7 +463,7 @@ impl BankingStage {
|
||||
// we just attempted to record) as retryable
|
||||
return (res, processed_transactions_indexes);
|
||||
}
|
||||
Err(_) => panic!("Poh recorder returned unexpected error"),
|
||||
Err(e) => panic!(format!("Poh recorder returned unexpected error: {:?}", e)),
|
||||
}
|
||||
poh_record.stop();
|
||||
}
|
||||
|
@ -1490,8 +1490,6 @@ fn recover(
|
||||
}
|
||||
}
|
||||
|
||||
assert_ne!(size, 0);
|
||||
|
||||
for i in start_idx..data_end_idx {
|
||||
let set_relative_idx = erasure_meta.data_index_in_set(i).unwrap() as usize;
|
||||
|
||||
|
@ -78,7 +78,7 @@ pub struct ErasureMeta {
|
||||
/// Which erasure set in the slot this is
|
||||
pub set_index: u64,
|
||||
/// Size of shards in this erasure set
|
||||
pub size: usize,
|
||||
size: usize,
|
||||
/// Bitfield representing presence/absence of data blobs
|
||||
data: u64,
|
||||
/// Bitfield representing presence/absence of coding blobs
|
||||
@ -106,7 +106,7 @@ impl ErasureMeta {
|
||||
let (data_missing, coding_missing) =
|
||||
(NUM_DATA - self.num_data(), NUM_CODING - self.num_coding());
|
||||
if data_missing > 0 && data_missing + coding_missing <= NUM_CODING {
|
||||
assert!(self.size != 0);
|
||||
//assert!(self.size != 0);
|
||||
ErasureMetaStatus::CanRecover
|
||||
} else if data_missing == 0 {
|
||||
ErasureMetaStatus::DataFull
|
||||
|
@ -1,4 +1,5 @@
|
||||
//! A stage to broadcast data from a leader node to validators
|
||||
use self::broadcast_bad_blob_sizes::BroadcastBadBlobSizes;
|
||||
use self::broadcast_fake_blobs_run::BroadcastFakeBlobsRun;
|
||||
use self::fail_entry_verification_broadcast_run::FailEntryVerificationBroadcastRun;
|
||||
use self::standard_broadcast_run::StandardBroadcastRun;
|
||||
@ -21,6 +22,7 @@ use std::sync::{Arc, RwLock};
|
||||
use std::thread::{self, Builder, JoinHandle};
|
||||
use std::time::Instant;
|
||||
|
||||
mod broadcast_bad_blob_sizes;
|
||||
mod broadcast_fake_blobs_run;
|
||||
mod broadcast_utils;
|
||||
mod fail_entry_verification_broadcast_run;
|
||||
@ -38,6 +40,7 @@ pub enum BroadcastStageType {
|
||||
Standard,
|
||||
FailEntryVerification,
|
||||
BroadcastFakeBlobs,
|
||||
BroadcastBadBlobSizes,
|
||||
}
|
||||
|
||||
impl BroadcastStageType {
|
||||
@ -76,6 +79,15 @@ impl BroadcastStageType {
|
||||
blocktree,
|
||||
BroadcastFakeBlobsRun::new(0),
|
||||
),
|
||||
|
||||
BroadcastStageType::BroadcastBadBlobSizes => BroadcastStage::new(
|
||||
sock,
|
||||
cluster_info,
|
||||
receiver,
|
||||
exit_sender,
|
||||
blocktree,
|
||||
BroadcastBadBlobSizes::new(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
83
core/src/broadcast_stage/broadcast_bad_blob_sizes.rs
Normal file
83
core/src/broadcast_stage/broadcast_bad_blob_sizes.rs
Normal file
@ -0,0 +1,83 @@
|
||||
use super::*;
|
||||
use crate::packet::BLOB_HEADER_SIZE;
|
||||
use solana_sdk::hash::Hash;
|
||||
use solana_sdk::signature::Signable;
|
||||
|
||||
pub(super) struct BroadcastBadBlobSizes {}
|
||||
|
||||
impl BroadcastBadBlobSizes {
|
||||
pub(super) fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl BroadcastRun for BroadcastBadBlobSizes {
|
||||
fn run(
|
||||
&mut self,
|
||||
broadcast: &mut Broadcast,
|
||||
cluster_info: &Arc<RwLock<ClusterInfo>>,
|
||||
receiver: &Receiver<WorkingBankEntries>,
|
||||
sock: &UdpSocket,
|
||||
blocktree: &Arc<Blocktree>,
|
||||
) -> Result<()> {
|
||||
// 1) Pull entries from banking stage
|
||||
let mut receive_results = broadcast_utils::recv_slot_blobs(receiver)?;
|
||||
let bank = receive_results.bank.clone();
|
||||
let last_tick = receive_results.last_tick;
|
||||
|
||||
// 2) Convert entries to blobs + generate coding blobs. Set a garbage PoH on the last entry
|
||||
// in the slot to make verification fail on validators
|
||||
if last_tick == bank.max_tick_height() {
|
||||
let mut last_entry = receive_results
|
||||
.ventries
|
||||
.last_mut()
|
||||
.unwrap()
|
||||
.last_mut()
|
||||
.unwrap();
|
||||
last_entry.0.hash = Hash::default();
|
||||
}
|
||||
|
||||
let keypair = &cluster_info.read().unwrap().keypair.clone();
|
||||
let latest_blob_index = blocktree
|
||||
.meta(bank.slot())
|
||||
.expect("Database error")
|
||||
.map(|meta| meta.consumed)
|
||||
.unwrap_or(0);
|
||||
|
||||
let (data_blobs, coding_blobs) = broadcast_utils::entries_to_blobs(
|
||||
receive_results.ventries,
|
||||
&broadcast.thread_pool,
|
||||
latest_blob_index,
|
||||
last_tick,
|
||||
&bank,
|
||||
&keypair,
|
||||
&mut broadcast.coding_generator,
|
||||
);
|
||||
|
||||
for b in data_blobs.iter().chain(coding_blobs.iter()) {
|
||||
let mut w_b = b.write().unwrap();
|
||||
let real_size = w_b.meta.size;
|
||||
// corrupt the size in the header
|
||||
w_b.set_size(std::usize::MAX - BLOB_HEADER_SIZE);
|
||||
// resign the blob
|
||||
w_b.sign(&keypair);
|
||||
// don't corrupt the size in the meta so that broadcast will still work
|
||||
w_b.meta.size = real_size;
|
||||
}
|
||||
|
||||
blocktree.write_shared_blobs(data_blobs.iter().chain(coding_blobs.iter()))?;
|
||||
|
||||
// 3) Start broadcast step
|
||||
let bank_epoch = bank.get_stakers_epoch(bank.slot());
|
||||
let stakes = staking_utils::staked_nodes_at_epoch(&bank, bank_epoch);
|
||||
|
||||
// Broadcast data + erasures
|
||||
cluster_info.read().unwrap().broadcast(
|
||||
sock,
|
||||
data_blobs.iter().chain(coding_blobs.iter()),
|
||||
stakes.as_ref(),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -414,7 +414,7 @@ impl Blob {
|
||||
|
||||
let bytes = &data[..data_len];
|
||||
blob.data[..data_len].copy_from_slice(bytes);
|
||||
blob.meta.size = blob.data_size() as usize;
|
||||
blob.meta.size = data_len;
|
||||
blob
|
||||
}
|
||||
|
||||
@ -504,7 +504,10 @@ impl Blob {
|
||||
}
|
||||
|
||||
pub fn data_size(&self) -> u64 {
|
||||
LittleEndian::read_u64(&self.data[SIZE_RANGE])
|
||||
cmp::min(
|
||||
LittleEndian::read_u64(&self.data[SIZE_RANGE]),
|
||||
BLOB_SIZE as u64,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set_data_size(&mut self, size: u64) {
|
||||
|
Reference in New Issue
Block a user