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:
parent
4a03d76a41
commit
ded273413a
|
@ -2767,6 +2767,7 @@ dependencies = [
|
|||
"futures",
|
||||
"futures-util",
|
||||
"metrics",
|
||||
"once_cell",
|
||||
"rand 0.7.3",
|
||||
"redjubjub",
|
||||
"spandoc",
|
||||
|
|
|
@ -8,6 +8,7 @@ edition = "2018"
|
|||
[dependencies]
|
||||
chrono = "0.4.13"
|
||||
color-eyre = "0.5"
|
||||
once_cell = "1.4"
|
||||
rand = "0.7"
|
||||
redjubjub = "0.2"
|
||||
|
||||
|
|
|
@ -4,181 +4,115 @@ use super::*;
|
|||
|
||||
use chrono::Utc;
|
||||
use color_eyre::eyre::{eyre, Report};
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use zebra_chain::block::Block;
|
||||
use zebra_chain::block::BlockHeader;
|
||||
use zebra_chain::serialization::ZcashDeserialize;
|
||||
use zebra_chain::transaction::Transaction;
|
||||
use zebra_chain::serialization::{ZcashDeserialize, ZcashDeserializeInto};
|
||||
use zebra_test::transcript::{TransError, Transcript};
|
||||
|
||||
#[tokio::test]
|
||||
async fn verify_test() -> Result<(), Report> {
|
||||
verify().await
|
||||
}
|
||||
static VALID_BLOCK_TRANSCRIPT: Lazy<Vec<(Arc<Block>, Result<BlockHeaderHash, TransError>)>> =
|
||||
Lazy::new(|| {
|
||||
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]
|
||||
async fn verify() -> Result<(), Report> {
|
||||
zebra_test::init();
|
||||
static INVALID_TIME_BLOCK_TRANSCRIPT: Lazy<Vec<(Arc<Block>, Result<BlockHeaderHash, TransError>)>> =
|
||||
Lazy::new(|| {
|
||||
let mut block: Block =
|
||||
Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..])
|
||||
.unwrap();
|
||||
|
||||
let block =
|
||||
Arc::<Block>::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..])?;
|
||||
let hash: BlockHeaderHash = block.as_ref().into();
|
||||
// Modify the block's time
|
||||
// Changing the block header also invalidates the header hashes, but
|
||||
// those checks should be performed later in validation, because they
|
||||
// are more expensive.
|
||||
let three_hours_in_the_future = Utc::now()
|
||||
.checked_add_signed(chrono::Duration::hours(3))
|
||||
.ok_or_else(|| eyre!("overflow when calculating 3 hours in the future"))
|
||||
.unwrap();
|
||||
block.header.time = three_hours_in_the_future;
|
||||
|
||||
let state_service = Box::new(zebra_state::in_memory::init());
|
||||
let mut block_verifier = super::init(state_service);
|
||||
vec![(Arc::new(block), Err(TransError::Any))]
|
||||
});
|
||||
|
||||
/// 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
|
||||
// Changing the block header also invalidates the header hashes, but
|
||||
// those checks should be performed later in validation, because they
|
||||
// are more expensive.
|
||||
let three_hours_in_the_future = Utc::now()
|
||||
.checked_add_signed(chrono::Duration::hours(3))
|
||||
.ok_or("overflow when calculating 3 hours in the future")
|
||||
.map_err(|e| eyre!(e))?;
|
||||
block.header.time = three_hours_in_the_future;
|
||||
|
||||
let arc_block: Arc<Block> = block.into();
|
||||
|
||||
/// SPANDOC: Make sure the verifier service is ready
|
||||
let ready_verifier_service = block_verifier.ready_and().await.map_err(|e| eyre!(e))?;
|
||||
/// SPANDOC: Try to add the block, and expect failure
|
||||
// TODO(teor || jlusby): check error kind
|
||||
ready_verifier_service
|
||||
.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))?;
|
||||
static INVALID_HEADER_SOLUTION_TRANSCRIPT: Lazy<
|
||||
Vec<(Arc<Block>, Result<BlockHeaderHash, TransError>)>,
|
||||
> = Lazy::new(|| {
|
||||
let mut block: Block =
|
||||
Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..]).unwrap();
|
||||
|
||||
// Change nonce to something invalid
|
||||
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
|
||||
ready_verifier_service
|
||||
.call(Arc::new(block.clone()))
|
||||
.await
|
||||
.expect_err("expected the equihash solution to be invalid");
|
||||
static INVALID_COINBASE_TRANSCRIPT: Lazy<Vec<(Arc<Block>, Result<BlockHeaderHash, TransError>)>> =
|
||||
Lazy::new(|| {
|
||||
let header =
|
||||
BlockHeader::zcash_deserialize(&zebra_test::vectors::DUMMY_HEADER[..]).unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
// Test 1: Empty transaction
|
||||
let block1 = Block {
|
||||
header,
|
||||
transactions: Vec::new(),
|
||||
};
|
||||
|
||||
// Test 2: Transaction at first position is not coinbase
|
||||
let mut transactions = Vec::new();
|
||||
let tx = zebra_test::vectors::DUMMY_TX1
|
||||
.zcash_deserialize_into()
|
||||
.unwrap();
|
||||
transactions.push(tx);
|
||||
let block2 = Block {
|
||||
header,
|
||||
transactions,
|
||||
};
|
||||
|
||||
// Test 3: Invalid coinbase position
|
||||
let mut block3 =
|
||||
Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..])
|
||||
.unwrap();
|
||||
assert_eq!(block3.transactions.len(), 1);
|
||||
|
||||
// Extract the coinbase transaction from the block
|
||||
let coinbase_transaction = block3.transactions.get(0).unwrap().clone();
|
||||
|
||||
// Add another coinbase transaction to block
|
||||
block3.transactions.push(coinbase_transaction);
|
||||
assert_eq!(block3.transactions.len(), 2);
|
||||
|
||||
vec![
|
||||
(Arc::new(block1), Err(TransError::Any)),
|
||||
(Arc::new(block2), Err(TransError::Any)),
|
||||
(Arc::new(block3), Err(TransError::Any)),
|
||||
]
|
||||
});
|
||||
|
||||
#[tokio::test]
|
||||
async fn check_transcripts_test() -> Result<(), Report> {
|
||||
check_transcripts().await
|
||||
}
|
||||
|
||||
#[spandoc::spandoc]
|
||||
async fn coinbase() -> Result<(), Report> {
|
||||
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());
|
||||
|
||||
// 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
|
||||
let block = Block {
|
||||
header,
|
||||
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
|
||||
let mut transactions = Vec::new();
|
||||
let tx = Transaction::zcash_deserialize(&zebra_test::vectors::DUMMY_TX1[..]).unwrap();
|
||||
transactions.push(Arc::new(tx));
|
||||
let block = Block {
|
||||
header,
|
||||
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
|
||||
let mut block =
|
||||
Block::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..])?;
|
||||
assert_eq!(block.transactions.len(), 1);
|
||||
|
||||
// Extract the coinbase transaction from the block
|
||||
let coinbase_transaction = block.transactions.get(0).unwrap().clone();
|
||||
|
||||
// Add another coinbase transaction to block
|
||||
block.transactions.push(coinbase_transaction);
|
||||
assert_eq!(block.transactions.len(), 2);
|
||||
|
||||
// Error: coinbase input found in additional transaction
|
||||
ready_verifier_service
|
||||
.call(Arc::new(block))
|
||||
.await
|
||||
.expect_err("fail with coinbase input found in additional transaction");
|
||||
|
||||
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(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue