144 lines
5.0 KiB
Rust
144 lines
5.0 KiB
Rust
//! Initialization and arbitrary data generation functions for zebra-state.
|
|
|
|
use std::sync::Arc;
|
|
|
|
use proptest::prelude::*;
|
|
|
|
use zebra_chain::{
|
|
block::{Block, Height},
|
|
parameters::{
|
|
Network::{self, *},
|
|
NetworkUpgrade,
|
|
},
|
|
serialization::ZcashDeserializeInto,
|
|
transaction::{LockTime, Transaction},
|
|
};
|
|
|
|
use crate::{
|
|
service::{
|
|
check, finalized_state::FinalizedState, non_finalized_state::NonFinalizedState, read,
|
|
},
|
|
CheckpointVerifiedBlock, Config,
|
|
};
|
|
|
|
/// Generate a chain that allows us to make tests for the legacy chain rules.
|
|
///
|
|
/// Arguments:
|
|
/// - `transaction_version_override`: See `LedgerState::height_strategy` for details.
|
|
/// - `transaction_has_valid_network_upgrade`: See `LedgerState::height_strategy` for details.
|
|
/// Note: `false` allows zero or more invalid network upgrades.
|
|
/// - `blocks_after_nu_activation`: The number of blocks the strategy will generate
|
|
/// after the provided `network_upgrade`.
|
|
/// - `network_upgrade` - The network upgrade that we are using to simulate from where the
|
|
/// legacy chain checks should start to apply.
|
|
///
|
|
/// Returns:
|
|
/// A generated arbitrary strategy for the provided arguments.
|
|
pub(crate) fn partial_nu5_chain_strategy(
|
|
transaction_version_override: u32,
|
|
transaction_has_valid_network_upgrade: bool,
|
|
blocks_after_nu_activation: u32,
|
|
// TODO: This argument can be removed and just use Nu5 after we have an activation height #1841
|
|
network_upgrade: NetworkUpgrade,
|
|
) -> impl Strategy<
|
|
Value = (
|
|
Network,
|
|
Height,
|
|
zebra_chain::fmt::SummaryDebug<Vec<Arc<Block>>>,
|
|
),
|
|
> {
|
|
(
|
|
any::<Network>(),
|
|
NetworkUpgrade::reduced_branch_id_strategy(),
|
|
)
|
|
.prop_flat_map(move |(network, random_nu)| {
|
|
// TODO: update this to Nu5 after we have a height #1841
|
|
let mut nu = network_upgrade;
|
|
let nu_activation = nu.activation_height(network).unwrap();
|
|
let height = Height(nu_activation.0 + blocks_after_nu_activation);
|
|
|
|
// The `network_upgrade_override` will not be enough as when it is `None`,
|
|
// current network upgrade will be used (`NetworkUpgrade::Canopy`) which will be valid.
|
|
if !transaction_has_valid_network_upgrade {
|
|
nu = random_nu;
|
|
}
|
|
|
|
zebra_chain::block::LedgerState::height_strategy(
|
|
height,
|
|
Some(nu),
|
|
Some(transaction_version_override),
|
|
transaction_has_valid_network_upgrade,
|
|
)
|
|
.prop_flat_map(move |init| {
|
|
Block::partial_chain_strategy(
|
|
init,
|
|
blocks_after_nu_activation as usize,
|
|
check::utxo::transparent_coinbase_spend,
|
|
false,
|
|
)
|
|
})
|
|
.prop_map(move |partial_chain| (network, nu_activation, partial_chain))
|
|
})
|
|
}
|
|
|
|
/// Return a new `StateService` containing the mainnet genesis block.
|
|
/// Also returns the finalized genesis block itself.
|
|
pub(crate) fn new_state_with_mainnet_genesis(
|
|
) -> (FinalizedState, NonFinalizedState, CheckpointVerifiedBlock) {
|
|
let genesis = zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES
|
|
.zcash_deserialize_into::<Arc<Block>>()
|
|
.expect("block should deserialize");
|
|
|
|
let config = Config::ephemeral();
|
|
let network = Mainnet;
|
|
|
|
let mut finalized_state = FinalizedState::new_with_debug(
|
|
&config,
|
|
network,
|
|
// The tests that use this setup function also commit invalid blocks to the state.
|
|
true,
|
|
#[cfg(feature = "elasticsearch")]
|
|
None,
|
|
false,
|
|
);
|
|
let non_finalized_state = NonFinalizedState::new(network);
|
|
|
|
assert_eq!(
|
|
None,
|
|
read::best_tip(&non_finalized_state, &finalized_state.db)
|
|
);
|
|
|
|
let genesis = CheckpointVerifiedBlock::from(genesis);
|
|
finalized_state
|
|
.commit_finalized_direct(genesis.clone().into(), None, "test")
|
|
.expect("unexpected invalid genesis block test vector");
|
|
|
|
assert_eq!(
|
|
Some((Height(0), genesis.hash)),
|
|
read::best_tip(&non_finalized_state, &finalized_state.db)
|
|
);
|
|
|
|
(finalized_state, non_finalized_state, genesis)
|
|
}
|
|
|
|
/// Return a `Transaction::V4` with the coinbase data from `coinbase`.
|
|
///
|
|
/// Used to convert a coinbase transaction to a version that the non-finalized state will accept.
|
|
pub(crate) fn transaction_v4_from_coinbase(coinbase: &Transaction) -> Transaction {
|
|
assert!(
|
|
!coinbase.has_sapling_shielded_data(),
|
|
"conversion assumes sapling shielded data is None"
|
|
);
|
|
|
|
Transaction::V4 {
|
|
inputs: coinbase.inputs().to_vec(),
|
|
outputs: coinbase.outputs().to_vec(),
|
|
lock_time: coinbase.lock_time().unwrap_or_else(LockTime::unlocked),
|
|
// `Height(0)` means that the expiry height is ignored
|
|
expiry_height: coinbase.expiry_height().unwrap_or(Height(0)),
|
|
// invalid for coinbase transactions
|
|
joinsplit_data: None,
|
|
sapling_shielded_data: None,
|
|
}
|
|
}
|