Use transcripts in block verify tests (#675)

* change consensus block tests to transcripts

* fix lints

Co-authored-by: Jane Lusby <jlusby42@gmail.com>

Co-authored-by: Jane Lusby <jlusby42@gmail.com>
This commit is contained in:
Alfredo Garcia 2020-08-05 18:41:41 -03:00 committed by GitHub
parent 4a03d76a41
commit ded273413a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 93 additions and 157 deletions

1
Cargo.lock generated
View File

@ -2767,6 +2767,7 @@ dependencies = [
"futures", "futures",
"futures-util", "futures-util",
"metrics", "metrics",
"once_cell",
"rand 0.7.3", "rand 0.7.3",
"redjubjub", "redjubjub",
"spandoc", "spandoc",

View File

@ -8,6 +8,7 @@ edition = "2018"
[dependencies] [dependencies]
chrono = "0.4.13" chrono = "0.4.13"
color-eyre = "0.5" color-eyre = "0.5"
once_cell = "1.4"
rand = "0.7" rand = "0.7"
redjubjub = "0.2" redjubjub = "0.2"

View File

@ -4,55 +4,28 @@ use super::*;
use chrono::Utc; use chrono::Utc;
use color_eyre::eyre::{eyre, Report}; use color_eyre::eyre::{eyre, Report};
use once_cell::sync::Lazy;
use zebra_chain::block::Block; use zebra_chain::block::Block;
use zebra_chain::block::BlockHeader; use zebra_chain::block::BlockHeader;
use zebra_chain::serialization::ZcashDeserialize; use zebra_chain::serialization::{ZcashDeserialize, ZcashDeserializeInto};
use zebra_chain::transaction::Transaction; use zebra_test::transcript::{TransError, Transcript};
#[tokio::test] static VALID_BLOCK_TRANSCRIPT: Lazy<Vec<(Arc<Block>, Result<BlockHeaderHash, TransError>)>> =
async fn verify_test() -> Result<(), Report> { Lazy::new(|| {
verify().await let block: Arc<_> =
} Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..])
.unwrap()
.into();
let hash = Ok(block.as_ref().into());
vec![(block, hash)]
});
#[spandoc::spandoc] static INVALID_TIME_BLOCK_TRANSCRIPT: Lazy<Vec<(Arc<Block>, Result<BlockHeaderHash, TransError>)>> =
async fn verify() -> Result<(), Report> { Lazy::new(|| {
zebra_test::init(); let mut block: Block =
Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..])
let block = .unwrap();
Arc::<Block>::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..])?;
let hash: BlockHeaderHash = block.as_ref().into();
let state_service = Box::new(zebra_state::in_memory::init());
let mut block_verifier = super::init(state_service);
/// SPANDOC: Make sure the verifier service is ready
let ready_verifier_service = block_verifier.ready_and().await.map_err(|e| eyre!(e))?;
/// SPANDOC: Verify the block
let verify_response = ready_verifier_service
.call(block.clone())
.await
.map_err(|e| eyre!(e))?;
assert_eq!(verify_response, hash);
Ok(())
}
#[tokio::test]
async fn verify_fail_future_time_test() -> Result<(), Report> {
verify_fail_future_time().await
}
#[spandoc::spandoc]
async fn verify_fail_future_time() -> Result<(), Report> {
zebra_test::init();
let mut block =
<Block>::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..])?;
let state_service = zebra_state::in_memory::init();
let mut block_verifier = super::init(state_service.clone());
// Modify the block's time // Modify the block's time
// Changing the block header also invalidates the header hashes, but // Changing the block header also invalidates the header hashes, but
@ -60,125 +33,86 @@ async fn verify_fail_future_time() -> Result<(), Report> {
// are more expensive. // are more expensive.
let three_hours_in_the_future = Utc::now() let three_hours_in_the_future = Utc::now()
.checked_add_signed(chrono::Duration::hours(3)) .checked_add_signed(chrono::Duration::hours(3))
.ok_or("overflow when calculating 3 hours in the future") .ok_or_else(|| eyre!("overflow when calculating 3 hours in the future"))
.map_err(|e| eyre!(e))?; .unwrap();
block.header.time = three_hours_in_the_future; block.header.time = three_hours_in_the_future;
let arc_block: Arc<Block> = block.into(); vec![(Arc::new(block), Err(TransError::Any))]
});
/// SPANDOC: Make sure the verifier service is ready static INVALID_HEADER_SOLUTION_TRANSCRIPT: Lazy<
let ready_verifier_service = block_verifier.ready_and().await.map_err(|e| eyre!(e))?; Vec<(Arc<Block>, Result<BlockHeaderHash, TransError>)>,
/// SPANDOC: Try to add the block, and expect failure > = Lazy::new(|| {
// TODO(teor || jlusby): check error kind let mut block: Block =
ready_verifier_service Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..]).unwrap();
.call(arc_block.clone())
.await
.unwrap_err();
Ok(())
}
#[tokio::test]
async fn header_solution_test() -> Result<(), Report> {
header_solution().await
}
#[spandoc::spandoc]
async fn header_solution() -> Result<(), Report> {
zebra_test::init();
// Service variables
let state_service = Box::new(zebra_state::in_memory::init());
let mut block_verifier = super::init(state_service.clone());
let ready_verifier_service = block_verifier.ready_and().await.map_err(|e| eyre!(e))?;
// Get a valid block
let mut block = Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..])
.expect("block test vector should deserialize");
// This should be ok
ready_verifier_service
.call(Arc::new(block.clone()))
.await
.map_err(|e| eyre!(e))?;
// Change nonce to something invalid // Change nonce to something invalid
block.header.nonce = [0; 32]; block.header.nonce = [0; 32];
let ready_verifier_service = block_verifier.ready_and().await.map_err(|e| eyre!(e))?; vec![(Arc::new(block), Err(TransError::Any))]
});
// Error: invalid equihash solution for BlockHeader static INVALID_COINBASE_TRANSCRIPT: Lazy<Vec<(Arc<Block>, Result<BlockHeaderHash, TransError>)>> =
ready_verifier_service Lazy::new(|| {
.call(Arc::new(block.clone())) let header =
.await BlockHeader::zcash_deserialize(&zebra_test::vectors::DUMMY_HEADER[..]).unwrap();
.expect_err("expected the equihash solution to be invalid");
Ok(())
}
#[tokio::test]
#[spandoc::spandoc]
async fn coinbase() -> Result<(), Report> {
zebra_test::init();
// Service variables
let state_service = Box::new(zebra_state::in_memory::init());
let mut block_verifier = super::init(state_service.clone());
// Get a header of a block
let header = BlockHeader::zcash_deserialize(&zebra_test::vectors::DUMMY_HEADER[..]).unwrap();
let ready_verifier_service = block_verifier.ready_and().await.map_err(|e| eyre!(e))?;
// Test 1: Empty transaction // Test 1: Empty transaction
let block = Block { let block1 = Block {
header, header,
transactions: Vec::new(), transactions: Vec::new(),
}; };
// Error: no coinbase transaction in block
ready_verifier_service
.call(Arc::new(block.clone()))
.await
.expect_err("fail with no coinbase transaction in block");
let ready_verifier_service = block_verifier.ready_and().await.map_err(|e| eyre!(e))?;
// Test 2: Transaction at first position is not coinbase // Test 2: Transaction at first position is not coinbase
let mut transactions = Vec::new(); let mut transactions = Vec::new();
let tx = Transaction::zcash_deserialize(&zebra_test::vectors::DUMMY_TX1[..]).unwrap(); let tx = zebra_test::vectors::DUMMY_TX1
transactions.push(Arc::new(tx)); .zcash_deserialize_into()
let block = Block { .unwrap();
transactions.push(tx);
let block2 = Block {
header, header,
transactions, transactions,
}; };
// Error: no coinbase transaction in block
ready_verifier_service
.call(Arc::new(block))
.await
.expect_err("fail with no coinbase transaction in block");
let ready_verifier_service = block_verifier.ready_and().await.map_err(|e| eyre!(e))?;
// Test 3: Invalid coinbase position // Test 3: Invalid coinbase position
let mut block = let mut block3 =
Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..])?; Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..])
assert_eq!(block.transactions.len(), 1); .unwrap();
assert_eq!(block3.transactions.len(), 1);
// Extract the coinbase transaction from the block // Extract the coinbase transaction from the block
let coinbase_transaction = block.transactions.get(0).unwrap().clone(); let coinbase_transaction = block3.transactions.get(0).unwrap().clone();
// Add another coinbase transaction to block // Add another coinbase transaction to block
block.transactions.push(coinbase_transaction); block3.transactions.push(coinbase_transaction);
assert_eq!(block.transactions.len(), 2); assert_eq!(block3.transactions.len(), 2);
// Error: coinbase input found in additional transaction vec![
ready_verifier_service (Arc::new(block1), Err(TransError::Any)),
.call(Arc::new(block)) (Arc::new(block2), Err(TransError::Any)),
.await (Arc::new(block3), Err(TransError::Any)),
.expect_err("fail with coinbase input found in additional transaction"); ]
});
#[tokio::test]
async fn check_transcripts_test() -> Result<(), Report> {
check_transcripts().await
}
#[spandoc::spandoc]
async fn check_transcripts() -> Result<(), Report> {
zebra_test::init();
let state_service = zebra_state::in_memory::init();
let block_verifier = super::init(state_service.clone());
for transcript_data in &[
&VALID_BLOCK_TRANSCRIPT,
&INVALID_TIME_BLOCK_TRANSCRIPT,
&INVALID_HEADER_SOLUTION_TRANSCRIPT,
&INVALID_COINBASE_TRANSCRIPT,
] {
let transcript = Transcript::from(transcript_data.iter().cloned());
transcript.check(block_verifier.clone()).await.unwrap();
}
Ok(()) Ok(())
} }