2022-04-12 10:21:46 -07:00
|
|
|
//! Randomised data generation for state data.
|
|
|
|
|
2021-07-27 17:01:19 -07:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
2021-08-25 06:57:07 -07:00
|
|
|
use zebra_chain::{
|
|
|
|
amount::{Amount, NegativeAllowed},
|
|
|
|
block::{self, Block},
|
|
|
|
transaction::Transaction,
|
|
|
|
transparent,
|
|
|
|
value_balance::ValueBalance,
|
|
|
|
};
|
2021-07-27 17:01:19 -07:00
|
|
|
|
2022-03-09 15:34:50 -08:00
|
|
|
use crate::{
|
2023-06-01 05:29:03 -07:00
|
|
|
request::ContextuallyVerifiedBlock, service::chain_tip::ChainTipBlock, CheckpointVerifiedBlock,
|
|
|
|
SemanticallyVerifiedBlock,
|
2022-03-09 15:34:50 -08:00
|
|
|
};
|
2021-07-27 17:01:19 -07:00
|
|
|
|
|
|
|
/// Mocks computation done during semantic validation
|
|
|
|
pub trait Prepare {
|
2022-09-28 09:09:56 -07:00
|
|
|
/// Runs block semantic validation computation, and returns the result.
|
|
|
|
/// Test-only method.
|
2023-06-01 05:29:03 -07:00
|
|
|
fn prepare(self) -> SemanticallyVerifiedBlock;
|
2021-07-27 17:01:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Prepare for Arc<Block> {
|
2023-06-01 05:29:03 -07:00
|
|
|
fn prepare(self) -> SemanticallyVerifiedBlock {
|
2021-07-27 17:01:19 -07:00
|
|
|
let block = self;
|
|
|
|
let hash = block.hash();
|
|
|
|
let height = block.coinbase_height().unwrap();
|
2021-08-30 11:42:07 -07:00
|
|
|
let transaction_hashes: Arc<[_]> = block.transactions.iter().map(|tx| tx.hash()).collect();
|
2022-03-09 15:34:50 -08:00
|
|
|
let new_outputs =
|
|
|
|
transparent::new_ordered_outputs_with_height(&block, height, &transaction_hashes);
|
2021-07-27 17:01:19 -07:00
|
|
|
|
2023-06-01 05:29:03 -07:00
|
|
|
SemanticallyVerifiedBlock {
|
2021-07-27 17:01:19 -07:00
|
|
|
block,
|
|
|
|
hash,
|
|
|
|
height,
|
|
|
|
new_outputs,
|
|
|
|
transaction_hashes,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-08-25 06:57:07 -07:00
|
|
|
|
2021-09-01 15:31:16 -07:00
|
|
|
impl<T> From<T> for ChainTipBlock
|
|
|
|
where
|
|
|
|
T: Prepare,
|
|
|
|
{
|
|
|
|
fn from(block: T) -> Self {
|
|
|
|
block.prepare().into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-01 05:29:03 -07:00
|
|
|
impl From<SemanticallyVerifiedBlock> for ChainTipBlock {
|
|
|
|
fn from(prepared: SemanticallyVerifiedBlock) -> Self {
|
|
|
|
let SemanticallyVerifiedBlock {
|
2021-09-01 19:25:42 -07:00
|
|
|
block,
|
2021-09-01 15:31:16 -07:00
|
|
|
hash,
|
|
|
|
height,
|
|
|
|
new_outputs: _,
|
|
|
|
transaction_hashes,
|
|
|
|
} = prepared;
|
2022-10-24 12:48:45 -07:00
|
|
|
|
2021-09-01 15:31:16 -07:00
|
|
|
Self {
|
|
|
|
hash,
|
|
|
|
height,
|
2022-02-10 17:27:02 -08:00
|
|
|
time: block.header.time,
|
2022-10-24 12:48:45 -07:00
|
|
|
transactions: block.transactions.clone(),
|
2021-09-01 15:31:16 -07:00
|
|
|
transaction_hashes,
|
2021-09-01 19:25:42 -07:00
|
|
|
previous_block_hash: block.header.previous_block_hash,
|
2021-09-01 15:31:16 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-01 05:29:03 -07:00
|
|
|
impl SemanticallyVerifiedBlock {
|
|
|
|
/// Returns a [`ContextuallyVerifiedBlock`] created from this block,
|
2021-08-25 06:57:07 -07:00
|
|
|
/// with fake zero-valued spent UTXOs.
|
|
|
|
///
|
|
|
|
/// Only for use in tests.
|
2022-06-02 08:07:35 -07:00
|
|
|
#[cfg(test)]
|
2023-06-01 05:29:03 -07:00
|
|
|
pub fn test_with_zero_spent_utxos(&self) -> ContextuallyVerifiedBlock {
|
|
|
|
ContextuallyVerifiedBlock::test_with_zero_spent_utxos(self)
|
2021-08-25 06:57:07 -07:00
|
|
|
}
|
|
|
|
|
2023-06-01 05:29:03 -07:00
|
|
|
/// Returns a [`ContextuallyVerifiedBlock`] created from this block,
|
2021-08-25 06:57:07 -07:00
|
|
|
/// using a fake chain value pool change.
|
|
|
|
///
|
|
|
|
/// Only for use in tests.
|
2022-06-02 08:07:35 -07:00
|
|
|
#[cfg(test)]
|
2021-08-25 06:57:07 -07:00
|
|
|
pub fn test_with_chain_pool_change(
|
|
|
|
&self,
|
|
|
|
fake_chain_value_pool_change: ValueBalance<NegativeAllowed>,
|
2023-06-01 05:29:03 -07:00
|
|
|
) -> ContextuallyVerifiedBlock {
|
|
|
|
ContextuallyVerifiedBlock::test_with_chain_pool_change(self, fake_chain_value_pool_change)
|
2021-08-25 06:57:07 -07:00
|
|
|
}
|
|
|
|
|
2023-06-01 05:29:03 -07:00
|
|
|
/// Returns a [`ContextuallyVerifiedBlock`] created from this block,
|
2021-08-25 06:57:07 -07:00
|
|
|
/// with no chain value pool change.
|
|
|
|
///
|
|
|
|
/// Only for use in tests.
|
2022-06-02 08:07:35 -07:00
|
|
|
#[cfg(test)]
|
2023-06-01 05:29:03 -07:00
|
|
|
pub fn test_with_zero_chain_pool_change(&self) -> ContextuallyVerifiedBlock {
|
|
|
|
ContextuallyVerifiedBlock::test_with_zero_chain_pool_change(self)
|
2021-08-25 06:57:07 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-01 05:29:03 -07:00
|
|
|
impl ContextuallyVerifiedBlock {
|
2022-06-13 18:22:16 -07:00
|
|
|
/// Create a block that's ready for non-finalized `Chain` contextual
|
2023-06-01 05:29:03 -07:00
|
|
|
/// validation, using a [`SemanticallyVerifiedBlock`] and fake zero-valued spent UTXOs.
|
2021-08-25 06:57:07 -07:00
|
|
|
///
|
|
|
|
/// Only for use in tests.
|
2023-06-01 05:29:03 -07:00
|
|
|
pub fn test_with_zero_spent_utxos(block: impl Into<SemanticallyVerifiedBlock>) -> Self {
|
2021-08-25 06:57:07 -07:00
|
|
|
let block = block.into();
|
|
|
|
|
2022-04-12 10:21:46 -07:00
|
|
|
let zero_output = transparent::Output {
|
|
|
|
value: Amount::zero(),
|
|
|
|
lock_script: transparent::Script::new(&[]),
|
2021-08-25 06:57:07 -07:00
|
|
|
};
|
|
|
|
|
2022-04-12 10:21:46 -07:00
|
|
|
let zero_utxo = transparent::OrderedUtxo::new(zero_output, block::Height(1), 1);
|
|
|
|
|
2021-08-25 06:57:07 -07:00
|
|
|
let zero_spent_utxos = block
|
|
|
|
.block
|
|
|
|
.transactions
|
|
|
|
.iter()
|
|
|
|
.map(AsRef::as_ref)
|
|
|
|
.flat_map(Transaction::inputs)
|
|
|
|
.flat_map(transparent::Input::outpoint)
|
|
|
|
.map(|outpoint| (outpoint, zero_utxo.clone()))
|
|
|
|
.collect();
|
|
|
|
|
2023-06-01 05:29:03 -07:00
|
|
|
ContextuallyVerifiedBlock::with_block_and_spent_utxos(block, zero_spent_utxos)
|
2021-08-25 06:57:07 -07:00
|
|
|
.expect("all UTXOs are provided with zero values")
|
|
|
|
}
|
|
|
|
|
2023-06-01 05:29:03 -07:00
|
|
|
/// Create a [`ContextuallyVerifiedBlock`] from a [`Block`] or [`SemanticallyVerifiedBlock`],
|
2021-08-25 06:57:07 -07:00
|
|
|
/// using a fake chain value pool change.
|
|
|
|
///
|
|
|
|
/// Only for use in tests.
|
|
|
|
pub fn test_with_chain_pool_change(
|
2023-06-01 05:29:03 -07:00
|
|
|
block: impl Into<SemanticallyVerifiedBlock>,
|
2021-08-25 06:57:07 -07:00
|
|
|
fake_chain_value_pool_change: ValueBalance<NegativeAllowed>,
|
|
|
|
) -> Self {
|
2023-06-01 05:29:03 -07:00
|
|
|
let SemanticallyVerifiedBlock {
|
2021-08-25 06:57:07 -07:00
|
|
|
block,
|
|
|
|
hash,
|
|
|
|
height,
|
|
|
|
new_outputs,
|
|
|
|
transaction_hashes,
|
|
|
|
} = block.into();
|
|
|
|
|
|
|
|
Self {
|
|
|
|
block,
|
|
|
|
hash,
|
|
|
|
height,
|
2022-04-12 10:21:46 -07:00
|
|
|
new_outputs: new_outputs.clone(),
|
|
|
|
// Just re-use the outputs we created in this block, even though that's incorrect.
|
|
|
|
//
|
|
|
|
// TODO: fix the tests, and stop adding unrelated inputs and outputs.
|
|
|
|
spent_outputs: new_outputs,
|
2021-08-25 06:57:07 -07:00
|
|
|
transaction_hashes,
|
|
|
|
chain_value_pool_change: fake_chain_value_pool_change,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-01 05:29:03 -07:00
|
|
|
/// Create a [`ContextuallyVerifiedBlock`] from a [`Block`] or [`SemanticallyVerifiedBlock`],
|
2021-08-25 06:57:07 -07:00
|
|
|
/// with no chain value pool change.
|
|
|
|
///
|
|
|
|
/// Only for use in tests.
|
2023-06-01 05:29:03 -07:00
|
|
|
pub fn test_with_zero_chain_pool_change(block: impl Into<SemanticallyVerifiedBlock>) -> Self {
|
2021-08-25 06:57:07 -07:00
|
|
|
Self::test_with_chain_pool_change(block, ValueBalance::zero())
|
|
|
|
}
|
|
|
|
}
|
2022-03-09 15:34:50 -08:00
|
|
|
|
2023-06-01 05:29:03 -07:00
|
|
|
impl CheckpointVerifiedBlock {
|
2022-03-09 15:34:50 -08:00
|
|
|
/// Create a block that's ready to be committed to the finalized state,
|
|
|
|
/// using a precalculated [`block::Hash`] and [`block::Height`].
|
|
|
|
///
|
2023-06-01 05:29:03 -07:00
|
|
|
/// This is a test-only method, prefer [`CheckpointVerifiedBlock::with_hash`].
|
2022-03-09 15:34:50 -08:00
|
|
|
#[cfg(any(test, feature = "proptest-impl"))]
|
|
|
|
pub fn with_hash_and_height(
|
|
|
|
block: Arc<Block>,
|
|
|
|
hash: block::Hash,
|
|
|
|
height: block::Height,
|
|
|
|
) -> Self {
|
|
|
|
let transaction_hashes: Arc<[_]> = block.transactions.iter().map(|tx| tx.hash()).collect();
|
2023-06-19 15:48:59 -07:00
|
|
|
let new_outputs =
|
|
|
|
transparent::new_ordered_outputs_with_height(&block, height, &transaction_hashes);
|
2022-03-09 15:34:50 -08:00
|
|
|
|
2023-06-21 09:58:11 -07:00
|
|
|
Self(SemanticallyVerifiedBlock {
|
2022-03-09 15:34:50 -08:00
|
|
|
block,
|
|
|
|
hash,
|
|
|
|
height,
|
|
|
|
new_outputs,
|
|
|
|
transaction_hashes,
|
2023-06-21 09:58:11 -07:00
|
|
|
})
|
2022-03-09 15:34:50 -08:00
|
|
|
}
|
|
|
|
}
|