use std::pin::Pin;
use proptest::prelude::*;
use tower::ServiceExt;
use super::{
error::MempoolError, storage::Storage, ActiveState, InboundTxDownloads, Mempool, Request,
};
use crate::{
components::sync::{RecentSyncLengths, SyncStatus},
BoxError,
};
use zebra_chain::{
amount::{Amount, NonNegative},
parameters::NetworkKind,
transaction::{Transaction, UnminedTx, VerifiedUnminedTx},
transparent::{self, Address},
};
mod prop;
mod vector;
impl Mempool {
pub fn storage(&mut self) -> &mut Storage {
match &mut self.active_state {
ActiveState::Disabled => panic!("mempool must be enabled"),
ActiveState::Enabled { storage, .. } => storage,
}
}
pub fn tx_downloads(&self) -> &Pin<Box<InboundTxDownloads>> {
match &self.active_state {
ActiveState::Disabled => panic!("mempool must be enabled"),
ActiveState::Enabled { tx_downloads, .. } => tx_downloads,
}
}
pub async fn enable(&mut self, recent_syncs: &mut RecentSyncLengths) {
SyncStatus::sync_close_to_tip(recent_syncs);
self.dummy_call().await;
}
pub async fn disable(&mut self, recent_syncs: &mut RecentSyncLengths) {
SyncStatus::sync_far_from_tip(recent_syncs);
self.dummy_call().await;
}
pub async fn dummy_call(&mut self) {
self.oneshot(Request::CheckForVerifiedTransactions)
.await
.expect("unexpected failure when checking for verified transactions");
}
}
pub trait UnboxMempoolError {
fn unbox_mempool_error(self) -> MempoolError;
}
impl UnboxMempoolError for MempoolError {
fn unbox_mempool_error(self) -> MempoolError {
self
}
}
impl UnboxMempoolError for BoxError {
fn unbox_mempool_error(self) -> MempoolError {
self.downcast::<MempoolError>()
.expect("error is not an expected `MempoolError`")
.as_ref()
.clone()
}
}
impl<T, E> UnboxMempoolError for Result<T, E>
where
E: UnboxMempoolError,
{
fn unbox_mempool_error(self) -> MempoolError {
match self {
Ok(_) => panic!("expected a mempool error, but got a success instead"),
Err(error) => error.unbox_mempool_error(),
}
}
}
pub fn standard_verified_unmined_tx_strategy() -> BoxedStrategy<VerifiedUnminedTx> {
any::<Transaction>()
.prop_map(|mut transaction| {
standardize_transaction(&mut transaction);
let unmined_tx = UnminedTx::from(transaction);
let miner_fee = unmined_tx.conventional_fee;
VerifiedUnminedTx::new(unmined_tx, miner_fee, 0, std::sync::Arc::new(vec![]))
.expect("standardized transaction should pass ZIP-317 checks")
})
.boxed()
}
pub fn standardize_transaction(transaction: &mut Transaction) {
let lock_script = standard_lock_script();
let output_value = Amount::<NonNegative>::try_from(10_000).expect("valid amount");
for input in transaction.inputs_mut() {
if let transparent::Input::PrevOut { unlock_script, .. } = input {
*unlock_script = transparent::Script::new(&[]);
}
}
for output in transaction.outputs_mut() {
output.lock_script = lock_script.clone();
output.value = output_value;
}
}
fn standard_lock_script() -> transparent::Script {
Address::from_pub_key_hash(NetworkKind::Mainnet, [0u8; 20]).script()
}