Skip to content

Commit

Permalink
Pass threadpool around in entry tests
Browse files Browse the repository at this point in the history
  • Loading branch information
steviez committed Mar 25, 2024
1 parent 67f5082 commit 732905f
Showing 1 changed file with 95 additions and 30 deletions.
125 changes: 95 additions & 30 deletions entry/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -611,10 +611,23 @@ fn compare_hashes(computed_hash: Hash, ref_entry: &Entry) -> bool {
pub trait EntrySlice {
/// Verifies the hashes and counts of a slice of transactions are all consistent.
fn verify_cpu(&self, start_hash: &Hash, thread_pool: &ThreadPool) -> EntryVerificationState;
fn verify_cpu_generic(&self, start_hash: &Hash, thread_pool: &ThreadPool) -> EntryVerificationState;
fn verify_cpu_x86_simd(&self, start_hash: &Hash, simd_len: usize, thread_pool: &ThreadPool) -> EntryVerificationState;
fn start_verify(&self, start_hash: &Hash, thread_pool: &ThreadPool, recyclers: VerifyRecyclers)
-> EntryVerificationState;
fn verify_cpu_generic(
&self,
start_hash: &Hash,
thread_pool: &ThreadPool,
) -> EntryVerificationState;
fn verify_cpu_x86_simd(
&self,
start_hash: &Hash,
simd_len: usize,
thread_pool: &ThreadPool,
) -> EntryVerificationState;
fn start_verify(
&self,
start_hash: &Hash,
thread_pool: &ThreadPool,
recyclers: VerifyRecyclers,
) -> EntryVerificationState;
fn verify(&self, start_hash: &Hash, thread_pool: &ThreadPool) -> bool;
/// Checks that each entry tick has the correct number of hashes. Entry slices do not
/// necessarily end in a tick, so `tick_hash_count` is used to carry over the hash count
Expand All @@ -630,7 +643,11 @@ impl EntrySlice for [Entry] {
.finish_verify(thread_pool)
}

fn verify_cpu_generic(&self, start_hash: &Hash, thread_pool: &ThreadPool) -> EntryVerificationState {
fn verify_cpu_generic(
&self,
start_hash: &Hash,
thread_pool: &ThreadPool,
) -> EntryVerificationState {
let now = Instant::now();
let genesis = [Entry {
num_hashes: 0,
Expand Down Expand Up @@ -664,7 +681,12 @@ impl EntrySlice for [Entry] {
}
}

fn verify_cpu_x86_simd(&self, start_hash: &Hash, simd_len: usize, thread_pool: &ThreadPool) -> EntryVerificationState {
fn verify_cpu_x86_simd(
&self,
start_hash: &Hash,
simd_len: usize,
thread_pool: &ThreadPool,
) -> EntryVerificationState {
use solana_sdk::hash::HASH_BYTES;
let now = Instant::now();
let genesis = [Entry {
Expand Down Expand Up @@ -947,6 +969,14 @@ mod tests {
},
};

fn test_threadpool() -> ThreadPool {
rayon::ThreadPoolBuilder::new()
.num_threads(2)
.thread_name(|i| format!("solEntryTest{i:02}"))
.build()
.expect("rayon threadpool")
}

#[test]
fn test_entry_verify() {
let zero = Hash::default();
Expand All @@ -961,6 +991,7 @@ mod tests {
entries: Vec<Entry>,
skip_verification: bool,
verify_recyclers: VerifyRecyclers,
thread_pool: &ThreadPool,
verify: Arc<
dyn Fn(
VersionedTransaction,
Expand All @@ -982,10 +1013,16 @@ mod tests {
}
};

let cpu_verify_result = verify_transactions(entries.clone(), Arc::new(verify_func));
let cpu_verify_result =
verify_transactions(entries.clone(), thread_pool, Arc::new(verify_func));
let mut gpu_verify_result: EntrySigVerificationState = {
let verify_result =
start_verify_transactions(entries, skip_verification, verify_recyclers, verify);
let verify_result = start_verify_transactions(
entries,
skip_verification,
thread_pool,
verify_recyclers,
verify,
);
match verify_result {
Ok(res) => res,
_ => EntrySigVerificationState {
Expand Down Expand Up @@ -1015,6 +1052,8 @@ mod tests {

#[test]
fn test_entry_gpu_verify() {
let threadpool = test_threadpool();

let verify_transaction = {
move |versioned_tx: VersionedTransaction,
verification_mode: TransactionVerificationMode|
Expand Down Expand Up @@ -1060,12 +1099,14 @@ mod tests {
entries_invalid,
false,
recycler.clone(),
&threadpool,
Arc::new(verify_transaction)
));
assert!(test_verify_transactions(
entries_valid,
false,
recycler,
&threadpool,
Arc::new(verify_transaction)
));
}
Expand All @@ -1089,6 +1130,8 @@ mod tests {

#[test]
fn test_transaction_signing() {
let threadpool = test_threadpool();

use solana_sdk::signature::Signature;
let zero = Hash::default();

Expand All @@ -1098,27 +1141,27 @@ mod tests {

// Verify entry with 2 transactions
let mut e0 = [Entry::new(&zero, 0, vec![tx0, tx1])];
assert!(e0.verify(&zero));
assert!(e0.verify(&zero, &threadpool));

// Clear signature of the first transaction, see that it does not verify
let orig_sig = e0[0].transactions[0].signatures[0];
e0[0].transactions[0].signatures[0] = Signature::default();
assert!(!e0.verify(&zero));
assert!(!e0.verify(&zero, &threadpool));

// restore original signature
e0[0].transactions[0].signatures[0] = orig_sig;
assert!(e0.verify(&zero));
assert!(e0.verify(&zero, &threadpool));

// Resize signatures and see verification fails.
let len = e0[0].transactions[0].signatures.len();
e0[0].transactions[0]
.signatures
.resize(len - 1, Signature::default());
assert!(!e0.verify(&zero));
assert!(!e0.verify(&zero, &threadpool));

// Pass an entry with no transactions
let e0 = [Entry::new(&zero, 0, vec![])];
assert!(e0.verify(&zero));
assert!(e0.verify(&zero, &threadpool));
}

#[test]
Expand Down Expand Up @@ -1151,64 +1194,86 @@ mod tests {
#[test]
fn test_verify_slice1() {
solana_logger::setup();
let threadpool = test_threadpool();

let zero = Hash::default();
let one = hash(zero.as_ref());
assert!(vec![][..].verify(&zero)); // base case
assert!(vec![Entry::new_tick(0, &zero)][..].verify(&zero)); // singleton case 1
assert!(!vec![Entry::new_tick(0, &zero)][..].verify(&one)); // singleton case 2, bad
assert!(vec![next_entry(&zero, 0, vec![]); 2][..].verify(&zero)); // inductive step
// base case
assert!(vec![][..].verify(&zero, &threadpool));
// singleton case 1
assert!(vec![Entry::new_tick(0, &zero)][..].verify(&zero, &threadpool));
// singleton case 2, bad
assert!(!vec![Entry::new_tick(0, &zero)][..].verify(&one, &threadpool));
// inductive step
assert!(vec![next_entry(&zero, 0, vec![]); 2][..].verify(&zero, &threadpool));

let mut bad_ticks = vec![next_entry(&zero, 0, vec![]); 2];
bad_ticks[1].hash = one;
assert!(!bad_ticks.verify(&zero)); // inductive step, bad
// inductive step, bad
assert!(!bad_ticks.verify(&zero, &threadpool));
}

#[test]
fn test_verify_slice_with_hashes1() {
solana_logger::setup();
let threadpool = test_threadpool();

let zero = Hash::default();
let one = hash(zero.as_ref());
let two = hash(one.as_ref());
assert!(vec![][..].verify(&one)); // base case
assert!(vec![Entry::new_tick(1, &two)][..].verify(&one)); // singleton case 1
assert!(!vec![Entry::new_tick(1, &two)][..].verify(&two)); // singleton case 2, bad
// base case
assert!(vec![][..].verify(&one, &threadpool));
// singleton case 1
assert!(vec![Entry::new_tick(1, &two)][..].verify(&one, &threadpool));
// singleton case 2, bad
assert!(!vec![Entry::new_tick(1, &two)][..].verify(&two, &threadpool));

let mut ticks = vec![next_entry(&one, 1, vec![])];
ticks.push(next_entry(&ticks.last().unwrap().hash, 1, vec![]));
assert!(ticks.verify(&one)); // inductive step
// inductive step
assert!(ticks.verify(&one, &threadpool));

let mut bad_ticks = vec![next_entry(&one, 1, vec![])];
bad_ticks.push(next_entry(&bad_ticks.last().unwrap().hash, 1, vec![]));
bad_ticks[1].hash = one;
assert!(!bad_ticks.verify(&one)); // inductive step, bad
// inductive step, bad
assert!(!bad_ticks.verify(&one, &threadpool));
}

#[test]
fn test_verify_slice_with_hashes_and_transactions() {
solana_logger::setup();
let threadpool = test_threadpool();

let zero = Hash::default();
let one = hash(zero.as_ref());
let two = hash(one.as_ref());
let alice_keypair = Keypair::new();
let bob_keypair = Keypair::new();
let tx0 = system_transaction::transfer(&alice_keypair, &bob_keypair.pubkey(), 1, one);
let tx1 = system_transaction::transfer(&bob_keypair, &alice_keypair.pubkey(), 1, one);
assert!(vec![][..].verify(&one)); // base case
assert!(vec![next_entry(&one, 1, vec![tx0.clone()])][..].verify(&one)); // singleton case 1
assert!(!vec![next_entry(&one, 1, vec![tx0.clone()])][..].verify(&two)); // singleton case 2, bad
// base case
assert!(vec![][..].verify(&one, &threadpool));
// singleton case 1
assert!(vec![next_entry(&one, 1, vec![tx0.clone()])][..].verify(&one, &threadpool));
// singleton case 2, bad
assert!(!vec![next_entry(&one, 1, vec![tx0.clone()])][..].verify(&two, &threadpool));

let mut ticks = vec![next_entry(&one, 1, vec![tx0.clone()])];
ticks.push(next_entry(
&ticks.last().unwrap().hash,
1,
vec![tx1.clone()],
));
assert!(ticks.verify(&one)); // inductive step

// inductive step
assert!(ticks.verify(&one, &threadpool));

let mut bad_ticks = vec![next_entry(&one, 1, vec![tx0])];
bad_ticks.push(next_entry(&bad_ticks.last().unwrap().hash, 1, vec![tx1]));
bad_ticks[1].hash = one;
assert!(!bad_ticks.verify(&one)); // inductive step, bad
// inductive step, bad
assert!(!bad_ticks.verify(&one, &threadpool));
}

#[test]
Expand Down Expand Up @@ -1347,7 +1412,7 @@ mod tests {

info!("done.. {}", time);
let mut time = Measure::start("poh");
let res = entries.verify(&Hash::default());
let res = entries.verify(&Hash::default(), &test_threadpool());
assert_eq!(res, !modified);
time.stop();
info!("{} {}", time, res);
Expand Down

0 comments on commit 732905f

Please sign in to comment.