Check transaction signatures in entry verify (#8596)
This commit is contained in:
@ -258,6 +258,7 @@ pub trait EntrySlice {
|
|||||||
fn verify_tick_hash_count(&self, tick_hash_count: &mut u64, hashes_per_tick: u64) -> bool;
|
fn verify_tick_hash_count(&self, tick_hash_count: &mut u64, hashes_per_tick: u64) -> bool;
|
||||||
/// Counts tick entries
|
/// Counts tick entries
|
||||||
fn tick_count(&self) -> u64;
|
fn tick_count(&self) -> u64;
|
||||||
|
fn verify_transaction_signatures(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EntrySlice for [Entry] {
|
impl EntrySlice for [Entry] {
|
||||||
@ -304,11 +305,35 @@ impl EntrySlice for [Entry] {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn verify_transaction_signatures(&self) -> bool {
|
||||||
|
PAR_THREAD_POOL.with(|thread_pool| {
|
||||||
|
thread_pool.borrow().install(|| {
|
||||||
|
self.par_iter().all(|e| {
|
||||||
|
e.transactions
|
||||||
|
.par_iter()
|
||||||
|
.all(|transaction| transaction.verify().is_ok())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn start_verify(
|
fn start_verify(
|
||||||
&self,
|
&self,
|
||||||
start_hash: &Hash,
|
start_hash: &Hash,
|
||||||
recyclers: VerifyRecyclers,
|
recyclers: VerifyRecyclers,
|
||||||
) -> EntryVerificationState {
|
) -> EntryVerificationState {
|
||||||
|
let start = Instant::now();
|
||||||
|
let res = self.verify_transaction_signatures();
|
||||||
|
if !res {
|
||||||
|
return EntryVerificationState::CPU(VerificationData {
|
||||||
|
thread_h: None,
|
||||||
|
verification_status: EntryVerificationStatus::Failure,
|
||||||
|
duration_ms: timing::duration_as_ms(&start.elapsed()),
|
||||||
|
hashes: None,
|
||||||
|
tx_hashes: vec![],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let api = perf_libs::api();
|
let api = perf_libs::api();
|
||||||
if api.is_none() {
|
if api.is_none() {
|
||||||
return self.verify_cpu(start_hash);
|
return self.verify_cpu(start_hash);
|
||||||
@ -316,8 +341,6 @@ impl EntrySlice for [Entry] {
|
|||||||
let api = api.unwrap();
|
let api = api.unwrap();
|
||||||
inc_new_counter_warn!("entry_verify-num_entries", self.len() as usize);
|
inc_new_counter_warn!("entry_verify-num_entries", self.len() as usize);
|
||||||
|
|
||||||
let start = Instant::now();
|
|
||||||
|
|
||||||
let genesis = [Entry {
|
let genesis = [Entry {
|
||||||
num_hashes: 0,
|
num_hashes: 0,
|
||||||
hash: *start_hash,
|
hash: *start_hash,
|
||||||
@ -509,6 +532,40 @@ mod tests {
|
|||||||
assert!(!e0.verify(&zero));
|
assert!(!e0.verify(&zero));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_transaction_signing() {
|
||||||
|
use solana_sdk::signature::Signature;
|
||||||
|
let zero = Hash::default();
|
||||||
|
|
||||||
|
let keypair = Keypair::new();
|
||||||
|
let tx0 = system_transaction::transfer(&keypair, &keypair.pubkey(), 0, zero);
|
||||||
|
let tx1 = system_transaction::transfer(&keypair, &keypair.pubkey(), 1, zero);
|
||||||
|
|
||||||
|
// Verify entry with 2 transctions
|
||||||
|
let mut e0 = vec![Entry::new(&zero, 0, vec![tx0.clone(), tx1.clone()])];
|
||||||
|
assert!(e0.verify(&zero));
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
|
||||||
|
// restore original signature
|
||||||
|
e0[0].transactions[0].signatures[0] = orig_sig;
|
||||||
|
assert!(e0.verify(&zero));
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
|
||||||
|
// Pass an entry with no transactions
|
||||||
|
let e0 = vec![Entry::new(&zero, 0, vec![])];
|
||||||
|
assert!(e0.verify(&zero));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_witness_reorder_attack() {
|
fn test_witness_reorder_attack() {
|
||||||
let zero = Hash::default();
|
let zero = Hash::default();
|
||||||
@ -597,7 +654,7 @@ mod tests {
|
|||||||
let zero = Hash::default();
|
let zero = Hash::default();
|
||||||
let one = hash(&zero.as_ref());
|
let one = hash(&zero.as_ref());
|
||||||
let two = hash(&one.as_ref());
|
let two = hash(&one.as_ref());
|
||||||
let alice_pubkey = Keypair::default();
|
let alice_pubkey = Keypair::new();
|
||||||
let tx0 = create_sample_payment(&alice_pubkey, one);
|
let tx0 = create_sample_payment(&alice_pubkey, one);
|
||||||
let tx1 = create_sample_timestamp(&alice_pubkey, one);
|
let tx1 = create_sample_timestamp(&alice_pubkey, one);
|
||||||
assert_eq!(vec![][..].verify(&one), true); // base case
|
assert_eq!(vec![][..].verify(&one), true); // base case
|
||||||
|
Reference in New Issue
Block a user