2020-08-18 11:08:53 -07:00
|
|
|
//! Zebra script verification wrapping zcashd's zcash_script library
|
2020-07-17 16:45:29 -07:00
|
|
|
#![doc(html_favicon_url = "https://www.zfnd.org/images/zebra-favicon-128.png")]
|
2020-02-26 21:10:08 -08:00
|
|
|
#![doc(html_logo_url = "https://www.zfnd.org/images/zebra-icon.png")]
|
|
|
|
#![doc(html_root_url = "https://doc.zebra.zfnd.org/zebra_script")]
|
2022-01-24 08:25:06 -08:00
|
|
|
// We allow unsafe code, so we can call zcash_script
|
|
|
|
#![allow(unsafe_code)]
|
2021-11-15 12:55:32 -08:00
|
|
|
|
2022-01-24 08:25:06 -08:00
|
|
|
use std::sync::Arc;
|
2020-02-26 21:10:08 -08:00
|
|
|
|
2020-08-18 11:08:53 -07:00
|
|
|
use displaydoc::Display;
|
|
|
|
use thiserror::Error;
|
2021-11-15 12:55:32 -08:00
|
|
|
|
2020-08-18 11:08:53 -07:00
|
|
|
use zcash_script::{
|
|
|
|
zcash_script_error_t, zcash_script_error_t_zcash_script_ERR_OK,
|
|
|
|
zcash_script_error_t_zcash_script_ERR_TX_DESERIALIZE,
|
|
|
|
zcash_script_error_t_zcash_script_ERR_TX_INDEX,
|
|
|
|
zcash_script_error_t_zcash_script_ERR_TX_SIZE_MISMATCH,
|
|
|
|
};
|
2021-11-15 12:55:32 -08:00
|
|
|
|
2020-08-18 11:08:53 -07:00
|
|
|
use zebra_chain::{
|
|
|
|
parameters::ConsensusBranchId, serialization::ZcashSerialize, transaction::Transaction,
|
|
|
|
transparent,
|
|
|
|
};
|
|
|
|
|
2021-10-06 18:20:38 -07:00
|
|
|
#[derive(Copy, Clone, Debug, Display, Error, PartialEq, Eq)]
|
2020-08-18 11:08:53 -07:00
|
|
|
#[non_exhaustive]
|
|
|
|
/// An Error type representing the error codes returned from zcash_script.
|
|
|
|
pub enum Error {
|
|
|
|
/// script failed to verify
|
|
|
|
#[non_exhaustive]
|
|
|
|
ScriptInvalid,
|
|
|
|
/// could not to deserialize tx
|
|
|
|
#[non_exhaustive]
|
|
|
|
TxDeserialize,
|
|
|
|
/// input index out of bounds for transaction's inputs
|
|
|
|
#[non_exhaustive]
|
|
|
|
TxIndex,
|
|
|
|
/// tx is an invalid size for it's protocol
|
|
|
|
#[non_exhaustive]
|
|
|
|
TxSizeMismatch,
|
|
|
|
/// encountered unknown error kind from zcash_script: {0}
|
|
|
|
#[non_exhaustive]
|
|
|
|
Unknown(zcash_script_error_t),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<zcash_script_error_t> for Error {
|
|
|
|
#[allow(non_upper_case_globals)]
|
|
|
|
fn from(err_code: zcash_script_error_t) -> Error {
|
|
|
|
match err_code {
|
|
|
|
zcash_script_error_t_zcash_script_ERR_OK => Error::ScriptInvalid,
|
|
|
|
zcash_script_error_t_zcash_script_ERR_TX_DESERIALIZE => Error::TxDeserialize,
|
|
|
|
zcash_script_error_t_zcash_script_ERR_TX_INDEX => Error::TxIndex,
|
|
|
|
zcash_script_error_t_zcash_script_ERR_TX_SIZE_MISMATCH => Error::TxSizeMismatch,
|
|
|
|
unknown => Error::Unknown(unknown),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-31 07:28:42 -08:00
|
|
|
/// A preprocessed Transaction which can be used to verify scripts within said
|
2020-12-17 19:18:28 -08:00
|
|
|
/// Transaction.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct CachedFfiTransaction {
|
2021-11-15 12:55:32 -08:00
|
|
|
/// The deserialized Zebra transaction.
|
|
|
|
///
|
2022-01-31 07:28:42 -08:00
|
|
|
/// This field is private so that `transaction`, `all_previous_outputs`, and `precomputed` always match.
|
2020-12-17 19:18:28 -08:00
|
|
|
transaction: Arc<Transaction>,
|
2021-11-15 12:55:32 -08:00
|
|
|
|
2022-01-31 07:28:42 -08:00
|
|
|
/// The outputs from previous transactions that match each input in the transaction
|
|
|
|
/// being verified.
|
|
|
|
///
|
|
|
|
/// SAFETY: this field must be private,
|
|
|
|
/// and `CachedFfiTransaction::new` must be the only method that modifies it,
|
|
|
|
/// so that it is [`Send`], [`Sync`], consistent with `transaction` and `precomputed`.
|
|
|
|
all_previous_outputs: Vec<transparent::Output>,
|
|
|
|
|
2021-11-15 12:55:32 -08:00
|
|
|
/// The deserialized `zcash_script` transaction, as a C++ object.
|
|
|
|
///
|
|
|
|
/// SAFETY: this field must be private,
|
|
|
|
/// and `CachedFfiTransaction::new` must be the only method that modifies it,
|
|
|
|
/// so that it is [`Send`], [`Sync`], valid, and not NULL.
|
2020-12-17 19:18:28 -08:00
|
|
|
precomputed: *mut std::ffi::c_void,
|
|
|
|
}
|
2020-08-18 11:08:53 -07:00
|
|
|
|
2020-12-17 19:18:28 -08:00
|
|
|
impl CachedFfiTransaction {
|
2022-01-31 07:28:42 -08:00
|
|
|
/// Construct a `PrecomputedTransaction` from a `Transaction` and the outputs
|
|
|
|
/// from previous transactions that match each input in the transaction
|
|
|
|
/// being verified.
|
|
|
|
pub fn new(
|
|
|
|
transaction: Arc<Transaction>,
|
|
|
|
all_previous_outputs: Vec<transparent::Output>,
|
|
|
|
) -> Self {
|
2022-01-31 22:24:08 -08:00
|
|
|
let tx_to_serialized = transaction
|
2020-12-17 19:18:28 -08:00
|
|
|
.zcash_serialize_to_vec()
|
|
|
|
.expect("serialization into a vec is infallible");
|
|
|
|
|
2022-01-31 22:24:08 -08:00
|
|
|
let tx_to_serialized_ptr = tx_to_serialized.as_ptr();
|
|
|
|
let tx_to_serialized_len = tx_to_serialized
|
2021-11-15 12:55:32 -08:00
|
|
|
.len()
|
|
|
|
.try_into()
|
|
|
|
.expect("serialized transaction lengths are much less than u32::MAX");
|
2020-12-17 19:18:28 -08:00
|
|
|
let mut err = 0;
|
|
|
|
|
2022-01-31 22:24:08 -08:00
|
|
|
let all_previous_outputs_serialized = all_previous_outputs
|
2022-01-31 07:28:42 -08:00
|
|
|
.zcash_serialize_to_vec()
|
|
|
|
.expect("serialization into a vec is infallible");
|
|
|
|
// TODO: pass to zcash_script after API update
|
2022-01-31 22:24:08 -08:00
|
|
|
let _all_previous_outputs_serialized_ptr = all_previous_outputs_serialized.as_ptr();
|
|
|
|
let _all_previous_outputs_serialized_len: u32 = all_previous_outputs_serialized
|
2022-01-31 07:28:42 -08:00
|
|
|
.len()
|
|
|
|
.try_into()
|
|
|
|
.expect("serialized transaction lengths are much less than u32::MAX");
|
|
|
|
|
|
|
|
// SAFETY:
|
|
|
|
// the `tx_to_*` fields are created from a valid Rust `Vec`
|
|
|
|
// the `all_previous_outputs_*` fields are created from a valid Rust `Vec`
|
2020-12-17 19:18:28 -08:00
|
|
|
let precomputed = unsafe {
|
2022-01-31 07:28:42 -08:00
|
|
|
zcash_script::zcash_script_new_precomputed_tx(
|
2022-01-31 22:24:08 -08:00
|
|
|
tx_to_serialized_ptr,
|
|
|
|
tx_to_serialized_len,
|
2022-01-31 07:28:42 -08:00
|
|
|
// all_previous_outputs_ptr,
|
|
|
|
// all_previous_outputs_len,
|
|
|
|
&mut err,
|
|
|
|
)
|
2020-12-17 19:18:28 -08:00
|
|
|
};
|
2021-11-15 12:55:32 -08:00
|
|
|
// SAFETY: the safety of other methods depends on `precomputed` being valid and not NULL.
|
2021-10-05 18:08:41 -07:00
|
|
|
assert!(
|
|
|
|
!precomputed.is_null(),
|
|
|
|
"zcash_script_new_precomputed_tx returned {} ({})",
|
|
|
|
err,
|
|
|
|
Error::from(err)
|
|
|
|
);
|
2020-12-17 19:18:28 -08:00
|
|
|
|
|
|
|
Self {
|
|
|
|
transaction,
|
2022-01-31 07:28:42 -08:00
|
|
|
all_previous_outputs,
|
2021-11-15 12:55:32 -08:00
|
|
|
// SAFETY: `precomputed` must not be modified after initialisation,
|
|
|
|
// so that it is `Send` and `Sync`.
|
2020-12-17 19:18:28 -08:00
|
|
|
precomputed,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-03 15:48:40 -07:00
|
|
|
/// Returns the transparent inputs for this transaction.
|
2020-12-17 19:18:28 -08:00
|
|
|
pub fn inputs(&self) -> &[transparent::Input] {
|
|
|
|
self.transaction.inputs()
|
|
|
|
}
|
|
|
|
|
2022-01-31 07:28:42 -08:00
|
|
|
/// Returns the outputs from previous transactions that match each input in the transaction
|
|
|
|
/// being verified.
|
|
|
|
pub fn all_previous_outputs(&self) -> &Vec<transparent::Output> {
|
|
|
|
&self.all_previous_outputs
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Verify if the script in the input at `input_index` of a transaction correctly
|
2022-01-31 22:24:08 -08:00
|
|
|
/// spends the matching [`transparent::Output`] it refers to, with the [`ConsensusBranchId`]
|
2022-01-31 07:28:42 -08:00
|
|
|
/// of the block containing the transaction.
|
|
|
|
pub fn is_valid(&self, branch_id: ConsensusBranchId, input_index: usize) -> Result<(), Error> {
|
|
|
|
let previous_output = self
|
|
|
|
.all_previous_outputs
|
|
|
|
.get(input_index)
|
|
|
|
.ok_or(Error::TxIndex)?
|
|
|
|
.clone();
|
2020-12-17 19:18:28 -08:00
|
|
|
let transparent::Output { value, lock_script } = previous_output;
|
2021-05-27 06:04:10 -07:00
|
|
|
let script_pub_key: &[u8] = lock_script.as_raw_bytes();
|
2021-11-15 12:55:32 -08:00
|
|
|
|
|
|
|
// This conversion is useful on some platforms, but not others.
|
|
|
|
#[allow(clippy::useless_conversion)]
|
|
|
|
let n_in = input_index
|
|
|
|
.try_into()
|
|
|
|
.expect("transaction indexes are much less than c_uint::MAX");
|
2020-12-17 19:18:28 -08:00
|
|
|
|
|
|
|
let script_ptr = script_pub_key.as_ptr();
|
|
|
|
let script_len = script_pub_key.len();
|
|
|
|
|
|
|
|
let amount = value.into();
|
2021-11-15 12:55:32 -08:00
|
|
|
|
2020-12-17 19:18:28 -08:00
|
|
|
let flags = zcash_script::zcash_script_SCRIPT_FLAGS_VERIFY_P2SH
|
|
|
|
| zcash_script::zcash_script_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY;
|
2021-11-15 12:55:32 -08:00
|
|
|
// This conversion is useful on some platforms, but not others.
|
|
|
|
#[allow(clippy::useless_conversion)]
|
|
|
|
let flags = flags
|
|
|
|
.try_into()
|
|
|
|
.expect("zcash_script_SCRIPT_FLAGS_VERIFY_* enum values fit in a c_uint");
|
2020-12-17 19:18:28 -08:00
|
|
|
|
|
|
|
let consensus_branch_id = branch_id.into();
|
|
|
|
|
|
|
|
let mut err = 0;
|
|
|
|
|
2021-11-15 12:55:32 -08:00
|
|
|
// SAFETY: `CachedFfiTransaction::new` makes sure `self.precomputed` is not NULL.
|
|
|
|
// The `script_*` fields are created from a valid Rust `slice`.
|
2020-12-17 19:18:28 -08:00
|
|
|
let ret = unsafe {
|
|
|
|
zcash_script::zcash_script_verify_precomputed(
|
|
|
|
self.precomputed,
|
|
|
|
n_in,
|
|
|
|
script_ptr,
|
2021-11-15 12:55:32 -08:00
|
|
|
script_len
|
|
|
|
.try_into()
|
|
|
|
.expect("script lengths are much less than u32::MAX"),
|
2020-12-17 19:18:28 -08:00
|
|
|
amount,
|
|
|
|
flags,
|
|
|
|
consensus_branch_id,
|
|
|
|
&mut err,
|
|
|
|
)
|
|
|
|
};
|
|
|
|
|
|
|
|
if ret == 1 {
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(Error::from(err))
|
|
|
|
}
|
2020-08-18 11:08:53 -07:00
|
|
|
}
|
2021-11-15 12:55:32 -08:00
|
|
|
|
|
|
|
/// Returns the number of transparent signature operations in the
|
|
|
|
/// transparent inputs and outputs of this transaction.
|
|
|
|
pub fn legacy_sigop_count(&self) -> Result<u64, Error> {
|
|
|
|
let mut err = 0;
|
|
|
|
|
|
|
|
// SAFETY: `CachedFfiTransaction::new` makes sure `self.precomputed` is not NULL.
|
|
|
|
let ret = unsafe {
|
|
|
|
zcash_script::zcash_script_legacy_sigop_count_precomputed(self.precomputed, &mut err)
|
|
|
|
};
|
|
|
|
|
|
|
|
if err == zcash_script_error_t_zcash_script_ERR_OK {
|
|
|
|
let ret = ret.try_into().expect("c_uint fits in a u64");
|
|
|
|
Ok(ret)
|
|
|
|
} else {
|
|
|
|
Err(Error::from(err))
|
|
|
|
}
|
|
|
|
}
|
2020-08-18 11:08:53 -07:00
|
|
|
}
|
|
|
|
|
2020-12-17 19:18:28 -08:00
|
|
|
// # SAFETY
|
|
|
|
//
|
|
|
|
// ## Justification
|
|
|
|
//
|
|
|
|
// `CachedFfiTransaction` is not `Send` and `Sync` by default because of the
|
|
|
|
// `*mut c_void` it contains. This is because raw pointers could allow the same
|
|
|
|
// data to be mutated from different threads if copied.
|
|
|
|
//
|
|
|
|
// CachedFFiTransaction needs to be Send and Sync to be stored within a `Box<dyn
|
|
|
|
// Future + Send + Sync + static>`. In `zebra_consensus/src/transaction.rs`, an
|
|
|
|
// async block owns a `CachedFfiTransaction`, and holds it across an await
|
|
|
|
// point, while the transaction verifier is spawning all of the script verifier
|
|
|
|
// futures. The service readiness check requires this await between each task
|
|
|
|
// spawn. Each `script` future needs a copy of the
|
2021-11-12 11:30:22 -08:00
|
|
|
// `Arc<CachedFfiTransaction>` so that it can simultaneously verify inputs
|
2020-12-17 19:18:28 -08:00
|
|
|
// without cloning the c++ allocated type unnecessarily.
|
|
|
|
//
|
|
|
|
// ## Explanation
|
|
|
|
//
|
|
|
|
// It is safe for us to mark this as `Send` and `Sync` because the data pointed
|
|
|
|
// to by `precomputed` is never modified after it is constructed and points to
|
|
|
|
// heap memory with a stable memory location. The function
|
|
|
|
// `zcash_script::zcash_script_verify_precomputed` only reads from the
|
|
|
|
// precomputed context while verifying inputs, which makes it safe to treat this
|
|
|
|
// pointer like a shared reference (given that is how it is used).
|
2021-11-15 12:55:32 -08:00
|
|
|
//
|
|
|
|
// The function `zcash_script:zcash_script_legacy_sigop_count_precomputed` only reads
|
|
|
|
// from the precomputed context. Currently, these reads happen after all the concurrent
|
|
|
|
// async checks have finished.
|
2022-01-31 07:28:42 -08:00
|
|
|
//
|
|
|
|
// Since we're manually marking it as `Send` and `Sync`, we must ensure that
|
|
|
|
// other fields in the struct are also `Send` and `Sync`. This applies to
|
|
|
|
// `all_previous_outputs`, which are both.
|
|
|
|
//
|
|
|
|
// TODO: create a wrapper for `precomputed` and only make it implement Send/Sync (#3436)
|
2020-12-17 19:18:28 -08:00
|
|
|
unsafe impl Send for CachedFfiTransaction {}
|
|
|
|
unsafe impl Sync for CachedFfiTransaction {}
|
|
|
|
|
|
|
|
impl Drop for CachedFfiTransaction {
|
|
|
|
fn drop(&mut self) {
|
2021-11-15 12:55:32 -08:00
|
|
|
// SAFETY: `CachedFfiTransaction::new` makes sure `self.precomputed` is not NULL.
|
2020-12-17 19:18:28 -08:00
|
|
|
unsafe { zcash_script::zcash_script_free_precomputed_tx(self.precomputed) };
|
|
|
|
}
|
2020-08-18 11:08:53 -07:00
|
|
|
}
|
|
|
|
|
2019-08-29 14:46:54 -07:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2020-08-18 11:08:53 -07:00
|
|
|
use hex::FromHex;
|
|
|
|
use std::convert::TryInto;
|
|
|
|
use std::sync::Arc;
|
2020-08-18 22:14:58 -07:00
|
|
|
use zebra_chain::{
|
|
|
|
parameters::NetworkUpgrade::*, serialization::ZcashDeserializeInto, transparent,
|
|
|
|
};
|
2020-08-18 11:08:53 -07:00
|
|
|
use zebra_test::prelude::*;
|
|
|
|
|
|
|
|
lazy_static::lazy_static! {
|
2020-09-29 00:22:26 -07:00
|
|
|
pub static ref SCRIPT_PUBKEY: Vec<u8> = <Vec<u8>>::from_hex("76a914f47cac1e6fec195c055994e8064ffccce0044dd788ac")
|
|
|
|
.unwrap();
|
|
|
|
pub static ref SCRIPT_TX: Vec<u8> = <Vec<u8>>::from_hex("0400008085202f8901fcaf44919d4a17f6181a02a7ebe0420be6f7dad1ef86755b81d5a9567456653c010000006a473044022035224ed7276e61affd53315eca059c92876bc2df61d84277cafd7af61d4dbf4002203ed72ea497a9f6b38eb29df08e830d99e32377edb8a574b8a289024f0241d7c40121031f54b095eae066d96b2557c1f99e40e967978a5fd117465dbec0986ca74201a6feffffff020050d6dc0100000017a9141b8a9bda4b62cd0d0582b55455d0778c86f8628f870d03c812030000001976a914e4ff5512ffafe9287992a1cd177ca6e408e0300388ac62070d0095070d000000000000000000000000")
|
|
|
|
.expect("Block bytes are in valid hex representation");
|
2020-08-18 11:08:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2020-12-17 19:18:28 -08:00
|
|
|
fn verify_valid_script() -> Result<()> {
|
2020-08-18 11:08:53 -07:00
|
|
|
zebra_test::init();
|
|
|
|
|
|
|
|
let transaction =
|
|
|
|
SCRIPT_TX.zcash_deserialize_into::<Arc<zebra_chain::transaction::Transaction>>()?;
|
|
|
|
let coin = u64::pow(10, 8);
|
|
|
|
let amount = 212 * coin;
|
|
|
|
let output = transparent::Output {
|
|
|
|
value: amount.try_into()?,
|
2021-05-27 06:04:10 -07:00
|
|
|
lock_script: transparent::Script::new(&SCRIPT_PUBKEY.clone()),
|
2020-08-18 11:08:53 -07:00
|
|
|
};
|
|
|
|
let input_index = 0;
|
2020-08-18 22:14:58 -07:00
|
|
|
let branch_id = Blossom
|
|
|
|
.branch_id()
|
|
|
|
.expect("Blossom has a ConsensusBranchId");
|
2020-08-18 11:08:53 -07:00
|
|
|
|
2022-01-31 07:28:42 -08:00
|
|
|
let previous_output = vec![output];
|
|
|
|
let verifier = super::CachedFfiTransaction::new(transaction, previous_output);
|
|
|
|
verifier.is_valid(branch_id, input_index)?;
|
2020-08-18 11:08:53 -07:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-11-15 12:55:32 -08:00
|
|
|
#[test]
|
|
|
|
fn count_legacy_sigops() -> Result<()> {
|
|
|
|
zebra_test::init();
|
|
|
|
|
|
|
|
let transaction =
|
|
|
|
SCRIPT_TX.zcash_deserialize_into::<Arc<zebra_chain::transaction::Transaction>>()?;
|
|
|
|
|
2022-01-31 07:28:42 -08:00
|
|
|
let cached_tx = super::CachedFfiTransaction::new(transaction, Vec::new());
|
2021-11-15 12:55:32 -08:00
|
|
|
assert_eq!(cached_tx.legacy_sigop_count()?, 1);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-29 14:46:54 -07:00
|
|
|
#[test]
|
2020-12-17 19:18:28 -08:00
|
|
|
fn fail_invalid_script() -> Result<()> {
|
|
|
|
zebra_test::init();
|
|
|
|
|
|
|
|
let transaction =
|
|
|
|
SCRIPT_TX.zcash_deserialize_into::<Arc<zebra_chain::transaction::Transaction>>()?;
|
|
|
|
let coin = u64::pow(10, 8);
|
|
|
|
let amount = 211 * coin;
|
|
|
|
let output = transparent::Output {
|
|
|
|
value: amount.try_into()?,
|
2021-05-27 06:04:10 -07:00
|
|
|
lock_script: transparent::Script::new(&SCRIPT_PUBKEY.clone()[..]),
|
2020-12-17 19:18:28 -08:00
|
|
|
};
|
|
|
|
let input_index = 0;
|
|
|
|
let branch_id = Blossom
|
|
|
|
.branch_id()
|
|
|
|
.expect("Blossom has a ConsensusBranchId");
|
|
|
|
|
2022-01-31 07:28:42 -08:00
|
|
|
let verifier = super::CachedFfiTransaction::new(transaction, vec![output]);
|
|
|
|
verifier.is_valid(branch_id, input_index).unwrap_err();
|
2020-12-17 19:18:28 -08:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn reuse_script_verifier_pass_pass() -> Result<()> {
|
2020-08-18 11:08:53 -07:00
|
|
|
zebra_test::init();
|
|
|
|
|
2020-12-17 19:18:28 -08:00
|
|
|
let coin = u64::pow(10, 8);
|
|
|
|
let transaction =
|
|
|
|
SCRIPT_TX.zcash_deserialize_into::<Arc<zebra_chain::transaction::Transaction>>()?;
|
2022-01-31 07:28:42 -08:00
|
|
|
let amount = 212 * coin;
|
|
|
|
let output = transparent::Output {
|
|
|
|
value: amount.try_into()?,
|
|
|
|
lock_script: transparent::Script::new(&SCRIPT_PUBKEY.clone()),
|
|
|
|
};
|
2020-12-17 19:18:28 -08:00
|
|
|
|
2022-01-31 07:28:42 -08:00
|
|
|
let verifier = super::CachedFfiTransaction::new(transaction, vec![output]);
|
2020-12-17 19:18:28 -08:00
|
|
|
|
|
|
|
let input_index = 0;
|
|
|
|
let branch_id = Blossom
|
|
|
|
.branch_id()
|
|
|
|
.expect("Blossom has a ConsensusBranchId");
|
|
|
|
|
2022-01-31 07:28:42 -08:00
|
|
|
verifier.is_valid(branch_id, input_index)?;
|
2020-08-18 11:08:53 -07:00
|
|
|
|
2022-01-31 07:28:42 -08:00
|
|
|
verifier.is_valid(branch_id, input_index)?;
|
2020-08-18 11:08:53 -07:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2020-12-17 19:18:28 -08:00
|
|
|
fn reuse_script_verifier_pass_fail() -> Result<()> {
|
2020-08-18 11:08:53 -07:00
|
|
|
zebra_test::init();
|
|
|
|
|
2020-12-17 19:18:28 -08:00
|
|
|
let coin = u64::pow(10, 8);
|
2022-01-31 07:28:42 -08:00
|
|
|
let amount = 212 * coin;
|
|
|
|
let output = transparent::Output {
|
|
|
|
value: amount.try_into()?,
|
|
|
|
lock_script: transparent::Script::new(&SCRIPT_PUBKEY.clone()),
|
|
|
|
};
|
2020-12-17 19:18:28 -08:00
|
|
|
let transaction =
|
|
|
|
SCRIPT_TX.zcash_deserialize_into::<Arc<zebra_chain::transaction::Transaction>>()?;
|
|
|
|
|
2022-01-31 07:28:42 -08:00
|
|
|
let verifier = super::CachedFfiTransaction::new(transaction, vec![output]);
|
2020-12-17 19:18:28 -08:00
|
|
|
|
|
|
|
let input_index = 0;
|
|
|
|
let branch_id = Blossom
|
|
|
|
.branch_id()
|
|
|
|
.expect("Blossom has a ConsensusBranchId");
|
|
|
|
|
2022-01-31 07:28:42 -08:00
|
|
|
verifier.is_valid(branch_id, input_index)?;
|
2020-12-17 19:18:28 -08:00
|
|
|
|
2022-01-31 07:28:42 -08:00
|
|
|
verifier.is_valid(branch_id, input_index + 1).unwrap_err();
|
2020-12-17 19:18:28 -08:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn reuse_script_verifier_fail_pass() -> Result<()> {
|
|
|
|
zebra_test::init();
|
|
|
|
|
|
|
|
let coin = u64::pow(10, 8);
|
2022-01-31 07:28:42 -08:00
|
|
|
let amount = 212 * coin;
|
|
|
|
let output = transparent::Output {
|
|
|
|
value: amount.try_into()?,
|
|
|
|
lock_script: transparent::Script::new(&SCRIPT_PUBKEY.clone()),
|
|
|
|
};
|
2020-12-17 19:18:28 -08:00
|
|
|
let transaction =
|
|
|
|
SCRIPT_TX.zcash_deserialize_into::<Arc<zebra_chain::transaction::Transaction>>()?;
|
|
|
|
|
2022-01-31 07:28:42 -08:00
|
|
|
let verifier = super::CachedFfiTransaction::new(transaction, vec![output]);
|
2020-08-18 11:08:53 -07:00
|
|
|
|
2020-12-17 19:18:28 -08:00
|
|
|
let input_index = 0;
|
|
|
|
let branch_id = Blossom
|
|
|
|
.branch_id()
|
|
|
|
.expect("Blossom has a ConsensusBranchId");
|
|
|
|
|
2022-01-31 07:28:42 -08:00
|
|
|
verifier.is_valid(branch_id, input_index + 1).unwrap_err();
|
2020-12-17 19:18:28 -08:00
|
|
|
|
2022-01-31 07:28:42 -08:00
|
|
|
verifier.is_valid(branch_id, input_index)?;
|
2020-12-17 19:18:28 -08:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn reuse_script_verifier_fail_fail() -> Result<()> {
|
|
|
|
zebra_test::init();
|
|
|
|
|
|
|
|
let coin = u64::pow(10, 8);
|
2022-01-31 07:28:42 -08:00
|
|
|
let amount = 212 * coin;
|
|
|
|
let output = transparent::Output {
|
|
|
|
value: amount.try_into()?,
|
|
|
|
lock_script: transparent::Script::new(&SCRIPT_PUBKEY.clone()),
|
|
|
|
};
|
2020-12-17 19:18:28 -08:00
|
|
|
let transaction =
|
|
|
|
SCRIPT_TX.zcash_deserialize_into::<Arc<zebra_chain::transaction::Transaction>>()?;
|
|
|
|
|
2022-01-31 07:28:42 -08:00
|
|
|
let verifier = super::CachedFfiTransaction::new(transaction, vec![output]);
|
2020-12-17 19:18:28 -08:00
|
|
|
|
|
|
|
let input_index = 0;
|
|
|
|
let branch_id = Blossom
|
|
|
|
.branch_id()
|
|
|
|
.expect("Blossom has a ConsensusBranchId");
|
|
|
|
|
2022-01-31 07:28:42 -08:00
|
|
|
verifier.is_valid(branch_id, input_index + 1).unwrap_err();
|
2020-12-17 19:18:28 -08:00
|
|
|
|
2022-01-31 07:28:42 -08:00
|
|
|
verifier.is_valid(branch_id, input_index + 1).unwrap_err();
|
2020-08-18 11:08:53 -07:00
|
|
|
|
|
|
|
Ok(())
|
2019-08-29 14:46:54 -07:00
|
|
|
}
|
|
|
|
}
|