zebra/zebra-consensus/src/transaction.rs

507 lines
19 KiB
Rust
Raw Normal View History

use std::{
collections::HashMap,
future::Future,
pin::Pin,
sync::Arc,
task::{Context, Poll},
};
use futures::{
stream::{FuturesUnordered, StreamExt},
FutureExt,
};
use tower::{Service, ServiceExt};
use tracing::Instrument;
use zebra_chain::{
block,
parameters::{Network, NetworkUpgrade},
Reject V5 transactions before NU5 activation (#2285) * Add a `Transaction::version` getter Returns the version of the transaction as a `u32`. * Add `Transaction::is_overwintered` helper method Returns if the `fOverwintered` flag should be set for the transaction's version. * Use new helpers to serialize transaction version Reduce the repeated code and make it less error-prone with future changes. * Add getter methods to `transaction::Request` type Refactor to move the type deconstruction code into the `Request` type. The main objective is to make it easier to split the call handler into methods that receive the request directly. * Refactor to create `verify_v4_transaction` helper Split the code specific to V4 transactions into a separate helper method. * Create `verify_v5_transaction` helper method Prepare a separate method to have the validation code. * Add `UnsupportedByNetworkUpgrade` error variant An error for when a transaction's version isn't supported by the network upgrade of the block it's included or for the current network upgrade if the transaction is for the mempool. * Verify a V5 transaction's network upgrade For now, only NU5 supports V5 transactions. * Test that V5 transaction is rejected on Canopy Create a fake V5 transaction and try to verify it using a block height from Canopy's activation. The verifier should reject the transaction with an error saying that the network upgrade does not support that transaction version. * Test if V5 tx. is accepted after NU5 activation Create a fake V5 transaction and pretend it is placed in a block that has a height after the NU5 activation. The test should succeed, but since the NU5 activation height has not been specified yet (neither for the testnet nor the mainnet), for now this test is marked as `should_panic`. * Add `TODO` comment to the code Add more detail to what's left to do, and link to the appropriate PRs. * Use `u32` to store transaction version Use a type consistent with how the version is specified. Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net>
2021-06-14 17:15:59 -07:00
primitives::Groth16Proof,
sapling,
transaction::{self, HashType, Transaction},
transparent,
};
use zebra_script::CachedFfiTransaction;
use zebra_state as zs;
use crate::{error::TransactionError, primitives, script, BoxError};
mod check;
#[cfg(test)]
mod tests;
Validate transparent inputs and outputs in V5 transactions (#2302) * Add missing documentation Document methods to describe what they do and why. * Create an `AsyncChecks` type alias Make it simpler to write the `FuturesUnordered` type with boxed futures. This will also end up being used more when refactoring to return the checks so that the `call` method can wait on them. * Create `verify_transparent_inputs_and_outputs` Refactors the verification of the transparent inputs and outputs into a separate method. * Refactor transparent checks to use `call_all` Instead of pushing the verifications into a stream of unordered futures, use the `ServiceExt::call_all` method to build an equivalent stream after building a stream of requests. * Replace `CallAll` with `FuturesUnordered` Make it more consistent with the rest of the code, and make sure that the `len()` method is available to use for tracing. Co-authored-by: teor <teor@riseup.net> * Refactor to move wait for checks into a new method Allow the code snipped to be reused by other transaction version-specific check methods. * Verify transparent inputs in V5 transactions Use the script verifier to check the transparent inputs in a V5 transaction. * Check `has_inputs_and_outputs` for all versions Check if a transaction has inputs and outputs, independently of the transaction version. * Wait for checks in `call` method Refactor to move the repeated code into the `call` method. Now the validation methods return the set of asynchronous checks to wait for. * Add helper function to mock transparent transfers Creates a fake source UTXO, and then the input and output that represent spending that UTXO. The initial UTXO can be configured to have a script that either accepts or rejects any spend attempt. * Test if transparent V4 transaction is accepted Create a fake V4 transaction that includes a fake transparent transfer of funds. The transfer uses a script to allow any UTXO to spend it. * Test transaction V4 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Test if transparent V5 transaction is accepted Create a mock V5 transaction that includes a transparent transfer of funds. The transaction should be accepted by the verifier. * Test transaction V5 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Update `Request::upgrade` getter documentation Simplify it so that it won't become updated when #1683 is fixed. Co-authored-by: teor <teor@riseup.net>
2021-06-22 18:54:00 -07:00
/// An alias for a set of asynchronous checks that should succeed.
type AsyncChecks = FuturesUnordered<Pin<Box<dyn Future<Output = Result<(), BoxError>> + Send>>>;
/// Asynchronous transaction verification.
///
/// # Correctness
///
/// Transaction verification requests should be wrapped in a timeout, so that
/// out-of-order and invalid requests do not hang indefinitely. See the [`chain`](`crate::chain`)
/// module documentation for details.
#[derive(Debug, Clone)]
pub struct Verifier<ZS> {
network: Network,
script_verifier: script::Verifier<ZS>,
// spend_verifier: groth16::Verifier,
// output_verifier: groth16::Verifier,
// joinsplit_verifier: groth16::Verifier,
}
impl<ZS> Verifier<ZS>
where
ZS: Service<zs::Request, Response = zs::Response, Error = BoxError> + Send + Clone + 'static,
ZS::Future: Send + 'static,
{
// XXX: how should this struct be constructed?
pub fn new(network: Network, script_verifier: script::Verifier<ZS>) -> Self {
// let (spend_verifier, output_verifier, joinsplit_verifier) = todo!();
Self {
network,
script_verifier,
// spend_verifier,
// output_verifier,
// joinsplit_verifier,
}
}
}
/// Specifies whether a transaction should be verified as part of a block or as
/// part of the mempool.
///
/// Transaction verification has slightly different consensus rules, depending on
/// whether the transaction is to be included in a block on in the mempool.
#[allow(dead_code)]
pub enum Request {
/// Verify the supplied transaction as part of a block.
Block {
/// The transaction itself.
transaction: Arc<Transaction>,
/// Additional UTXOs which are known at the time of verification.
known_utxos: Arc<HashMap<transparent::OutPoint, zs::Utxo>>,
/// The height of the block containing this transaction, used to
/// determine the applicable network upgrade.
height: block::Height,
},
/// Verify the supplied transaction as part of the mempool.
Mempool {
/// The transaction itself.
transaction: Arc<Transaction>,
/// Additional UTXOs which are known at the time of verification.
known_utxos: Arc<HashMap<transparent::OutPoint, zs::Utxo>>,
/// Bug: this field should be the next block height, because some
/// consensus rules depend on the exact height. See #1683.
upgrade: NetworkUpgrade,
},
}
Reject V5 transactions before NU5 activation (#2285) * Add a `Transaction::version` getter Returns the version of the transaction as a `u32`. * Add `Transaction::is_overwintered` helper method Returns if the `fOverwintered` flag should be set for the transaction's version. * Use new helpers to serialize transaction version Reduce the repeated code and make it less error-prone with future changes. * Add getter methods to `transaction::Request` type Refactor to move the type deconstruction code into the `Request` type. The main objective is to make it easier to split the call handler into methods that receive the request directly. * Refactor to create `verify_v4_transaction` helper Split the code specific to V4 transactions into a separate helper method. * Create `verify_v5_transaction` helper method Prepare a separate method to have the validation code. * Add `UnsupportedByNetworkUpgrade` error variant An error for when a transaction's version isn't supported by the network upgrade of the block it's included or for the current network upgrade if the transaction is for the mempool. * Verify a V5 transaction's network upgrade For now, only NU5 supports V5 transactions. * Test that V5 transaction is rejected on Canopy Create a fake V5 transaction and try to verify it using a block height from Canopy's activation. The verifier should reject the transaction with an error saying that the network upgrade does not support that transaction version. * Test if V5 tx. is accepted after NU5 activation Create a fake V5 transaction and pretend it is placed in a block that has a height after the NU5 activation. The test should succeed, but since the NU5 activation height has not been specified yet (neither for the testnet nor the mainnet), for now this test is marked as `should_panic`. * Add `TODO` comment to the code Add more detail to what's left to do, and link to the appropriate PRs. * Use `u32` to store transaction version Use a type consistent with how the version is specified. Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net>
2021-06-14 17:15:59 -07:00
impl Request {
Validate transparent inputs and outputs in V5 transactions (#2302) * Add missing documentation Document methods to describe what they do and why. * Create an `AsyncChecks` type alias Make it simpler to write the `FuturesUnordered` type with boxed futures. This will also end up being used more when refactoring to return the checks so that the `call` method can wait on them. * Create `verify_transparent_inputs_and_outputs` Refactors the verification of the transparent inputs and outputs into a separate method. * Refactor transparent checks to use `call_all` Instead of pushing the verifications into a stream of unordered futures, use the `ServiceExt::call_all` method to build an equivalent stream after building a stream of requests. * Replace `CallAll` with `FuturesUnordered` Make it more consistent with the rest of the code, and make sure that the `len()` method is available to use for tracing. Co-authored-by: teor <teor@riseup.net> * Refactor to move wait for checks into a new method Allow the code snipped to be reused by other transaction version-specific check methods. * Verify transparent inputs in V5 transactions Use the script verifier to check the transparent inputs in a V5 transaction. * Check `has_inputs_and_outputs` for all versions Check if a transaction has inputs and outputs, independently of the transaction version. * Wait for checks in `call` method Refactor to move the repeated code into the `call` method. Now the validation methods return the set of asynchronous checks to wait for. * Add helper function to mock transparent transfers Creates a fake source UTXO, and then the input and output that represent spending that UTXO. The initial UTXO can be configured to have a script that either accepts or rejects any spend attempt. * Test if transparent V4 transaction is accepted Create a fake V4 transaction that includes a fake transparent transfer of funds. The transfer uses a script to allow any UTXO to spend it. * Test transaction V4 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Test if transparent V5 transaction is accepted Create a mock V5 transaction that includes a transparent transfer of funds. The transaction should be accepted by the verifier. * Test transaction V5 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Update `Request::upgrade` getter documentation Simplify it so that it won't become updated when #1683 is fixed. Co-authored-by: teor <teor@riseup.net>
2021-06-22 18:54:00 -07:00
/// The transaction to verify that's in this request.
Reject V5 transactions before NU5 activation (#2285) * Add a `Transaction::version` getter Returns the version of the transaction as a `u32`. * Add `Transaction::is_overwintered` helper method Returns if the `fOverwintered` flag should be set for the transaction's version. * Use new helpers to serialize transaction version Reduce the repeated code and make it less error-prone with future changes. * Add getter methods to `transaction::Request` type Refactor to move the type deconstruction code into the `Request` type. The main objective is to make it easier to split the call handler into methods that receive the request directly. * Refactor to create `verify_v4_transaction` helper Split the code specific to V4 transactions into a separate helper method. * Create `verify_v5_transaction` helper method Prepare a separate method to have the validation code. * Add `UnsupportedByNetworkUpgrade` error variant An error for when a transaction's version isn't supported by the network upgrade of the block it's included or for the current network upgrade if the transaction is for the mempool. * Verify a V5 transaction's network upgrade For now, only NU5 supports V5 transactions. * Test that V5 transaction is rejected on Canopy Create a fake V5 transaction and try to verify it using a block height from Canopy's activation. The verifier should reject the transaction with an error saying that the network upgrade does not support that transaction version. * Test if V5 tx. is accepted after NU5 activation Create a fake V5 transaction and pretend it is placed in a block that has a height after the NU5 activation. The test should succeed, but since the NU5 activation height has not been specified yet (neither for the testnet nor the mainnet), for now this test is marked as `should_panic`. * Add `TODO` comment to the code Add more detail to what's left to do, and link to the appropriate PRs. * Use `u32` to store transaction version Use a type consistent with how the version is specified. Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net>
2021-06-14 17:15:59 -07:00
pub fn transaction(&self) -> Arc<Transaction> {
match self {
Request::Block { transaction, .. } => transaction.clone(),
Request::Mempool { transaction, .. } => transaction.clone(),
}
}
Validate transparent inputs and outputs in V5 transactions (#2302) * Add missing documentation Document methods to describe what they do and why. * Create an `AsyncChecks` type alias Make it simpler to write the `FuturesUnordered` type with boxed futures. This will also end up being used more when refactoring to return the checks so that the `call` method can wait on them. * Create `verify_transparent_inputs_and_outputs` Refactors the verification of the transparent inputs and outputs into a separate method. * Refactor transparent checks to use `call_all` Instead of pushing the verifications into a stream of unordered futures, use the `ServiceExt::call_all` method to build an equivalent stream after building a stream of requests. * Replace `CallAll` with `FuturesUnordered` Make it more consistent with the rest of the code, and make sure that the `len()` method is available to use for tracing. Co-authored-by: teor <teor@riseup.net> * Refactor to move wait for checks into a new method Allow the code snipped to be reused by other transaction version-specific check methods. * Verify transparent inputs in V5 transactions Use the script verifier to check the transparent inputs in a V5 transaction. * Check `has_inputs_and_outputs` for all versions Check if a transaction has inputs and outputs, independently of the transaction version. * Wait for checks in `call` method Refactor to move the repeated code into the `call` method. Now the validation methods return the set of asynchronous checks to wait for. * Add helper function to mock transparent transfers Creates a fake source UTXO, and then the input and output that represent spending that UTXO. The initial UTXO can be configured to have a script that either accepts or rejects any spend attempt. * Test if transparent V4 transaction is accepted Create a fake V4 transaction that includes a fake transparent transfer of funds. The transfer uses a script to allow any UTXO to spend it. * Test transaction V4 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Test if transparent V5 transaction is accepted Create a mock V5 transaction that includes a transparent transfer of funds. The transaction should be accepted by the verifier. * Test transaction V5 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Update `Request::upgrade` getter documentation Simplify it so that it won't become updated when #1683 is fixed. Co-authored-by: teor <teor@riseup.net>
2021-06-22 18:54:00 -07:00
/// The set of additional known unspent transaction outputs that's in this request.
Reject V5 transactions before NU5 activation (#2285) * Add a `Transaction::version` getter Returns the version of the transaction as a `u32`. * Add `Transaction::is_overwintered` helper method Returns if the `fOverwintered` flag should be set for the transaction's version. * Use new helpers to serialize transaction version Reduce the repeated code and make it less error-prone with future changes. * Add getter methods to `transaction::Request` type Refactor to move the type deconstruction code into the `Request` type. The main objective is to make it easier to split the call handler into methods that receive the request directly. * Refactor to create `verify_v4_transaction` helper Split the code specific to V4 transactions into a separate helper method. * Create `verify_v5_transaction` helper method Prepare a separate method to have the validation code. * Add `UnsupportedByNetworkUpgrade` error variant An error for when a transaction's version isn't supported by the network upgrade of the block it's included or for the current network upgrade if the transaction is for the mempool. * Verify a V5 transaction's network upgrade For now, only NU5 supports V5 transactions. * Test that V5 transaction is rejected on Canopy Create a fake V5 transaction and try to verify it using a block height from Canopy's activation. The verifier should reject the transaction with an error saying that the network upgrade does not support that transaction version. * Test if V5 tx. is accepted after NU5 activation Create a fake V5 transaction and pretend it is placed in a block that has a height after the NU5 activation. The test should succeed, but since the NU5 activation height has not been specified yet (neither for the testnet nor the mainnet), for now this test is marked as `should_panic`. * Add `TODO` comment to the code Add more detail to what's left to do, and link to the appropriate PRs. * Use `u32` to store transaction version Use a type consistent with how the version is specified. Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net>
2021-06-14 17:15:59 -07:00
pub fn known_utxos(&self) -> Arc<HashMap<transparent::OutPoint, zs::Utxo>> {
match self {
Request::Block { known_utxos, .. } => known_utxos.clone(),
Request::Mempool { known_utxos, .. } => known_utxos.clone(),
}
}
Validate transparent inputs and outputs in V5 transactions (#2302) * Add missing documentation Document methods to describe what they do and why. * Create an `AsyncChecks` type alias Make it simpler to write the `FuturesUnordered` type with boxed futures. This will also end up being used more when refactoring to return the checks so that the `call` method can wait on them. * Create `verify_transparent_inputs_and_outputs` Refactors the verification of the transparent inputs and outputs into a separate method. * Refactor transparent checks to use `call_all` Instead of pushing the verifications into a stream of unordered futures, use the `ServiceExt::call_all` method to build an equivalent stream after building a stream of requests. * Replace `CallAll` with `FuturesUnordered` Make it more consistent with the rest of the code, and make sure that the `len()` method is available to use for tracing. Co-authored-by: teor <teor@riseup.net> * Refactor to move wait for checks into a new method Allow the code snipped to be reused by other transaction version-specific check methods. * Verify transparent inputs in V5 transactions Use the script verifier to check the transparent inputs in a V5 transaction. * Check `has_inputs_and_outputs` for all versions Check if a transaction has inputs and outputs, independently of the transaction version. * Wait for checks in `call` method Refactor to move the repeated code into the `call` method. Now the validation methods return the set of asynchronous checks to wait for. * Add helper function to mock transparent transfers Creates a fake source UTXO, and then the input and output that represent spending that UTXO. The initial UTXO can be configured to have a script that either accepts or rejects any spend attempt. * Test if transparent V4 transaction is accepted Create a fake V4 transaction that includes a fake transparent transfer of funds. The transfer uses a script to allow any UTXO to spend it. * Test transaction V4 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Test if transparent V5 transaction is accepted Create a mock V5 transaction that includes a transparent transfer of funds. The transaction should be accepted by the verifier. * Test transaction V5 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Update `Request::upgrade` getter documentation Simplify it so that it won't become updated when #1683 is fixed. Co-authored-by: teor <teor@riseup.net>
2021-06-22 18:54:00 -07:00
/// The network upgrade to consider for the verification.
///
/// This is based on the block height from the request, and the supplied `network`.
Reject V5 transactions before NU5 activation (#2285) * Add a `Transaction::version` getter Returns the version of the transaction as a `u32`. * Add `Transaction::is_overwintered` helper method Returns if the `fOverwintered` flag should be set for the transaction's version. * Use new helpers to serialize transaction version Reduce the repeated code and make it less error-prone with future changes. * Add getter methods to `transaction::Request` type Refactor to move the type deconstruction code into the `Request` type. The main objective is to make it easier to split the call handler into methods that receive the request directly. * Refactor to create `verify_v4_transaction` helper Split the code specific to V4 transactions into a separate helper method. * Create `verify_v5_transaction` helper method Prepare a separate method to have the validation code. * Add `UnsupportedByNetworkUpgrade` error variant An error for when a transaction's version isn't supported by the network upgrade of the block it's included or for the current network upgrade if the transaction is for the mempool. * Verify a V5 transaction's network upgrade For now, only NU5 supports V5 transactions. * Test that V5 transaction is rejected on Canopy Create a fake V5 transaction and try to verify it using a block height from Canopy's activation. The verifier should reject the transaction with an error saying that the network upgrade does not support that transaction version. * Test if V5 tx. is accepted after NU5 activation Create a fake V5 transaction and pretend it is placed in a block that has a height after the NU5 activation. The test should succeed, but since the NU5 activation height has not been specified yet (neither for the testnet nor the mainnet), for now this test is marked as `should_panic`. * Add `TODO` comment to the code Add more detail to what's left to do, and link to the appropriate PRs. * Use `u32` to store transaction version Use a type consistent with how the version is specified. Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net>
2021-06-14 17:15:59 -07:00
pub fn upgrade(&self, network: Network) -> NetworkUpgrade {
match self {
Request::Block { height, .. } => NetworkUpgrade::current(network, *height),
Request::Mempool { upgrade, .. } => *upgrade,
}
}
}
impl<ZS> Service<Request> for Verifier<ZS>
where
ZS: Service<zs::Request, Response = zs::Response, Error = BoxError> + Send + Clone + 'static,
ZS::Future: Send + 'static,
{
type Response = transaction::Hash;
type Error = TransactionError;
type Future =
Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send + 'static>>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
// TODO: break up each chunk into its own method
fn call(&mut self, req: Request) -> Self::Future {
let is_mempool = match req {
Request::Block { .. } => false,
Request::Mempool { .. } => true,
};
if is_mempool {
// XXX determine exactly which rules apply to mempool transactions
unimplemented!();
}
Reject V5 transactions before NU5 activation (#2285) * Add a `Transaction::version` getter Returns the version of the transaction as a `u32`. * Add `Transaction::is_overwintered` helper method Returns if the `fOverwintered` flag should be set for the transaction's version. * Use new helpers to serialize transaction version Reduce the repeated code and make it less error-prone with future changes. * Add getter methods to `transaction::Request` type Refactor to move the type deconstruction code into the `Request` type. The main objective is to make it easier to split the call handler into methods that receive the request directly. * Refactor to create `verify_v4_transaction` helper Split the code specific to V4 transactions into a separate helper method. * Create `verify_v5_transaction` helper method Prepare a separate method to have the validation code. * Add `UnsupportedByNetworkUpgrade` error variant An error for when a transaction's version isn't supported by the network upgrade of the block it's included or for the current network upgrade if the transaction is for the mempool. * Verify a V5 transaction's network upgrade For now, only NU5 supports V5 transactions. * Test that V5 transaction is rejected on Canopy Create a fake V5 transaction and try to verify it using a block height from Canopy's activation. The verifier should reject the transaction with an error saying that the network upgrade does not support that transaction version. * Test if V5 tx. is accepted after NU5 activation Create a fake V5 transaction and pretend it is placed in a block that has a height after the NU5 activation. The test should succeed, but since the NU5 activation height has not been specified yet (neither for the testnet nor the mainnet), for now this test is marked as `should_panic`. * Add `TODO` comment to the code Add more detail to what's left to do, and link to the appropriate PRs. * Use `u32` to store transaction version Use a type consistent with how the version is specified. Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net>
2021-06-14 17:15:59 -07:00
let script_verifier = self.script_verifier.clone();
let network = self.network;
Reject V5 transactions before NU5 activation (#2285) * Add a `Transaction::version` getter Returns the version of the transaction as a `u32`. * Add `Transaction::is_overwintered` helper method Returns if the `fOverwintered` flag should be set for the transaction's version. * Use new helpers to serialize transaction version Reduce the repeated code and make it less error-prone with future changes. * Add getter methods to `transaction::Request` type Refactor to move the type deconstruction code into the `Request` type. The main objective is to make it easier to split the call handler into methods that receive the request directly. * Refactor to create `verify_v4_transaction` helper Split the code specific to V4 transactions into a separate helper method. * Create `verify_v5_transaction` helper method Prepare a separate method to have the validation code. * Add `UnsupportedByNetworkUpgrade` error variant An error for when a transaction's version isn't supported by the network upgrade of the block it's included or for the current network upgrade if the transaction is for the mempool. * Verify a V5 transaction's network upgrade For now, only NU5 supports V5 transactions. * Test that V5 transaction is rejected on Canopy Create a fake V5 transaction and try to verify it using a block height from Canopy's activation. The verifier should reject the transaction with an error saying that the network upgrade does not support that transaction version. * Test if V5 tx. is accepted after NU5 activation Create a fake V5 transaction and pretend it is placed in a block that has a height after the NU5 activation. The test should succeed, but since the NU5 activation height has not been specified yet (neither for the testnet nor the mainnet), for now this test is marked as `should_panic`. * Add `TODO` comment to the code Add more detail to what's left to do, and link to the appropriate PRs. * Use `u32` to store transaction version Use a type consistent with how the version is specified. Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net>
2021-06-14 17:15:59 -07:00
let tx = req.transaction();
let span = tracing::debug_span!("tx", hash = %tx.hash());
async move {
tracing::trace!(?tx);
Validate transparent inputs and outputs in V5 transactions (#2302) * Add missing documentation Document methods to describe what they do and why. * Create an `AsyncChecks` type alias Make it simpler to write the `FuturesUnordered` type with boxed futures. This will also end up being used more when refactoring to return the checks so that the `call` method can wait on them. * Create `verify_transparent_inputs_and_outputs` Refactors the verification of the transparent inputs and outputs into a separate method. * Refactor transparent checks to use `call_all` Instead of pushing the verifications into a stream of unordered futures, use the `ServiceExt::call_all` method to build an equivalent stream after building a stream of requests. * Replace `CallAll` with `FuturesUnordered` Make it more consistent with the rest of the code, and make sure that the `len()` method is available to use for tracing. Co-authored-by: teor <teor@riseup.net> * Refactor to move wait for checks into a new method Allow the code snipped to be reused by other transaction version-specific check methods. * Verify transparent inputs in V5 transactions Use the script verifier to check the transparent inputs in a V5 transaction. * Check `has_inputs_and_outputs` for all versions Check if a transaction has inputs and outputs, independently of the transaction version. * Wait for checks in `call` method Refactor to move the repeated code into the `call` method. Now the validation methods return the set of asynchronous checks to wait for. * Add helper function to mock transparent transfers Creates a fake source UTXO, and then the input and output that represent spending that UTXO. The initial UTXO can be configured to have a script that either accepts or rejects any spend attempt. * Test if transparent V4 transaction is accepted Create a fake V4 transaction that includes a fake transparent transfer of funds. The transfer uses a script to allow any UTXO to spend it. * Test transaction V4 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Test if transparent V5 transaction is accepted Create a mock V5 transaction that includes a transparent transfer of funds. The transaction should be accepted by the verifier. * Test transaction V5 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Update `Request::upgrade` getter documentation Simplify it so that it won't become updated when #1683 is fixed. Co-authored-by: teor <teor@riseup.net>
2021-06-22 18:54:00 -07:00
// Do basic checks first
check::has_inputs_and_outputs(&tx)?;
let async_checks = match tx.as_ref() {
Transaction::V1 { .. } | Transaction::V2 { .. } | Transaction::V3 { .. } => {
tracing::debug!(?tx, "got transaction with wrong version");
Validate transparent inputs and outputs in V5 transactions (#2302) * Add missing documentation Document methods to describe what they do and why. * Create an `AsyncChecks` type alias Make it simpler to write the `FuturesUnordered` type with boxed futures. This will also end up being used more when refactoring to return the checks so that the `call` method can wait on them. * Create `verify_transparent_inputs_and_outputs` Refactors the verification of the transparent inputs and outputs into a separate method. * Refactor transparent checks to use `call_all` Instead of pushing the verifications into a stream of unordered futures, use the `ServiceExt::call_all` method to build an equivalent stream after building a stream of requests. * Replace `CallAll` with `FuturesUnordered` Make it more consistent with the rest of the code, and make sure that the `len()` method is available to use for tracing. Co-authored-by: teor <teor@riseup.net> * Refactor to move wait for checks into a new method Allow the code snipped to be reused by other transaction version-specific check methods. * Verify transparent inputs in V5 transactions Use the script verifier to check the transparent inputs in a V5 transaction. * Check `has_inputs_and_outputs` for all versions Check if a transaction has inputs and outputs, independently of the transaction version. * Wait for checks in `call` method Refactor to move the repeated code into the `call` method. Now the validation methods return the set of asynchronous checks to wait for. * Add helper function to mock transparent transfers Creates a fake source UTXO, and then the input and output that represent spending that UTXO. The initial UTXO can be configured to have a script that either accepts or rejects any spend attempt. * Test if transparent V4 transaction is accepted Create a fake V4 transaction that includes a fake transparent transfer of funds. The transfer uses a script to allow any UTXO to spend it. * Test transaction V4 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Test if transparent V5 transaction is accepted Create a mock V5 transaction that includes a transparent transfer of funds. The transaction should be accepted by the verifier. * Test transaction V5 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Update `Request::upgrade` getter documentation Simplify it so that it won't become updated when #1683 is fixed. Co-authored-by: teor <teor@riseup.net>
2021-06-22 18:54:00 -07:00
return Err(TransactionError::WrongVersion);
}
Transaction::V4 {
inputs,
// outputs,
// lock_time,
// expiry_height,
joinsplit_data,
sapling_shielded_data,
..
} => {
Reject V5 transactions before NU5 activation (#2285) * Add a `Transaction::version` getter Returns the version of the transaction as a `u32`. * Add `Transaction::is_overwintered` helper method Returns if the `fOverwintered` flag should be set for the transaction's version. * Use new helpers to serialize transaction version Reduce the repeated code and make it less error-prone with future changes. * Add getter methods to `transaction::Request` type Refactor to move the type deconstruction code into the `Request` type. The main objective is to make it easier to split the call handler into methods that receive the request directly. * Refactor to create `verify_v4_transaction` helper Split the code specific to V4 transactions into a separate helper method. * Create `verify_v5_transaction` helper method Prepare a separate method to have the validation code. * Add `UnsupportedByNetworkUpgrade` error variant An error for when a transaction's version isn't supported by the network upgrade of the block it's included or for the current network upgrade if the transaction is for the mempool. * Verify a V5 transaction's network upgrade For now, only NU5 supports V5 transactions. * Test that V5 transaction is rejected on Canopy Create a fake V5 transaction and try to verify it using a block height from Canopy's activation. The verifier should reject the transaction with an error saying that the network upgrade does not support that transaction version. * Test if V5 tx. is accepted after NU5 activation Create a fake V5 transaction and pretend it is placed in a block that has a height after the NU5 activation. The test should succeed, but since the NU5 activation height has not been specified yet (neither for the testnet nor the mainnet), for now this test is marked as `should_panic`. * Add `TODO` comment to the code Add more detail to what's left to do, and link to the appropriate PRs. * Use `u32` to store transaction version Use a type consistent with how the version is specified. Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net>
2021-06-14 17:15:59 -07:00
Self::verify_v4_transaction(
req,
network,
script_verifier,
inputs,
joinsplit_data,
sapling_shielded_data,
)
Validate transparent inputs and outputs in V5 transactions (#2302) * Add missing documentation Document methods to describe what they do and why. * Create an `AsyncChecks` type alias Make it simpler to write the `FuturesUnordered` type with boxed futures. This will also end up being used more when refactoring to return the checks so that the `call` method can wait on them. * Create `verify_transparent_inputs_and_outputs` Refactors the verification of the transparent inputs and outputs into a separate method. * Refactor transparent checks to use `call_all` Instead of pushing the verifications into a stream of unordered futures, use the `ServiceExt::call_all` method to build an equivalent stream after building a stream of requests. * Replace `CallAll` with `FuturesUnordered` Make it more consistent with the rest of the code, and make sure that the `len()` method is available to use for tracing. Co-authored-by: teor <teor@riseup.net> * Refactor to move wait for checks into a new method Allow the code snipped to be reused by other transaction version-specific check methods. * Verify transparent inputs in V5 transactions Use the script verifier to check the transparent inputs in a V5 transaction. * Check `has_inputs_and_outputs` for all versions Check if a transaction has inputs and outputs, independently of the transaction version. * Wait for checks in `call` method Refactor to move the repeated code into the `call` method. Now the validation methods return the set of asynchronous checks to wait for. * Add helper function to mock transparent transfers Creates a fake source UTXO, and then the input and output that represent spending that UTXO. The initial UTXO can be configured to have a script that either accepts or rejects any spend attempt. * Test if transparent V4 transaction is accepted Create a fake V4 transaction that includes a fake transparent transfer of funds. The transfer uses a script to allow any UTXO to spend it. * Test transaction V4 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Test if transparent V5 transaction is accepted Create a mock V5 transaction that includes a transparent transfer of funds. The transaction should be accepted by the verifier. * Test transaction V5 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Update `Request::upgrade` getter documentation Simplify it so that it won't become updated when #1683 is fixed. Co-authored-by: teor <teor@riseup.net>
2021-06-22 18:54:00 -07:00
.await?
}
Validate transparent inputs and outputs in V5 transactions (#2302) * Add missing documentation Document methods to describe what they do and why. * Create an `AsyncChecks` type alias Make it simpler to write the `FuturesUnordered` type with boxed futures. This will also end up being used more when refactoring to return the checks so that the `call` method can wait on them. * Create `verify_transparent_inputs_and_outputs` Refactors the verification of the transparent inputs and outputs into a separate method. * Refactor transparent checks to use `call_all` Instead of pushing the verifications into a stream of unordered futures, use the `ServiceExt::call_all` method to build an equivalent stream after building a stream of requests. * Replace `CallAll` with `FuturesUnordered` Make it more consistent with the rest of the code, and make sure that the `len()` method is available to use for tracing. Co-authored-by: teor <teor@riseup.net> * Refactor to move wait for checks into a new method Allow the code snipped to be reused by other transaction version-specific check methods. * Verify transparent inputs in V5 transactions Use the script verifier to check the transparent inputs in a V5 transaction. * Check `has_inputs_and_outputs` for all versions Check if a transaction has inputs and outputs, independently of the transaction version. * Wait for checks in `call` method Refactor to move the repeated code into the `call` method. Now the validation methods return the set of asynchronous checks to wait for. * Add helper function to mock transparent transfers Creates a fake source UTXO, and then the input and output that represent spending that UTXO. The initial UTXO can be configured to have a script that either accepts or rejects any spend attempt. * Test if transparent V4 transaction is accepted Create a fake V4 transaction that includes a fake transparent transfer of funds. The transfer uses a script to allow any UTXO to spend it. * Test transaction V4 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Test if transparent V5 transaction is accepted Create a mock V5 transaction that includes a transparent transfer of funds. The transaction should be accepted by the verifier. * Test transaction V5 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Update `Request::upgrade` getter documentation Simplify it so that it won't become updated when #1683 is fixed. Co-authored-by: teor <teor@riseup.net>
2021-06-22 18:54:00 -07:00
Transaction::V5 { inputs, .. } => {
Self::verify_v5_transaction(req, network, script_verifier, inputs).await?
}
};
Self::wait_for_checks(async_checks).await?;
Ok(tx.hash())
}
.instrument(span)
.boxed()
}
}
Reject V5 transactions before NU5 activation (#2285) * Add a `Transaction::version` getter Returns the version of the transaction as a `u32`. * Add `Transaction::is_overwintered` helper method Returns if the `fOverwintered` flag should be set for the transaction's version. * Use new helpers to serialize transaction version Reduce the repeated code and make it less error-prone with future changes. * Add getter methods to `transaction::Request` type Refactor to move the type deconstruction code into the `Request` type. The main objective is to make it easier to split the call handler into methods that receive the request directly. * Refactor to create `verify_v4_transaction` helper Split the code specific to V4 transactions into a separate helper method. * Create `verify_v5_transaction` helper method Prepare a separate method to have the validation code. * Add `UnsupportedByNetworkUpgrade` error variant An error for when a transaction's version isn't supported by the network upgrade of the block it's included or for the current network upgrade if the transaction is for the mempool. * Verify a V5 transaction's network upgrade For now, only NU5 supports V5 transactions. * Test that V5 transaction is rejected on Canopy Create a fake V5 transaction and try to verify it using a block height from Canopy's activation. The verifier should reject the transaction with an error saying that the network upgrade does not support that transaction version. * Test if V5 tx. is accepted after NU5 activation Create a fake V5 transaction and pretend it is placed in a block that has a height after the NU5 activation. The test should succeed, but since the NU5 activation height has not been specified yet (neither for the testnet nor the mainnet), for now this test is marked as `should_panic`. * Add `TODO` comment to the code Add more detail to what's left to do, and link to the appropriate PRs. * Use `u32` to store transaction version Use a type consistent with how the version is specified. Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net>
2021-06-14 17:15:59 -07:00
impl<ZS> Verifier<ZS>
where
ZS: Service<zs::Request, Response = zs::Response, Error = BoxError> + Send + Clone + 'static,
ZS::Future: Send + 'static,
{
Validate transparent inputs and outputs in V5 transactions (#2302) * Add missing documentation Document methods to describe what they do and why. * Create an `AsyncChecks` type alias Make it simpler to write the `FuturesUnordered` type with boxed futures. This will also end up being used more when refactoring to return the checks so that the `call` method can wait on them. * Create `verify_transparent_inputs_and_outputs` Refactors the verification of the transparent inputs and outputs into a separate method. * Refactor transparent checks to use `call_all` Instead of pushing the verifications into a stream of unordered futures, use the `ServiceExt::call_all` method to build an equivalent stream after building a stream of requests. * Replace `CallAll` with `FuturesUnordered` Make it more consistent with the rest of the code, and make sure that the `len()` method is available to use for tracing. Co-authored-by: teor <teor@riseup.net> * Refactor to move wait for checks into a new method Allow the code snipped to be reused by other transaction version-specific check methods. * Verify transparent inputs in V5 transactions Use the script verifier to check the transparent inputs in a V5 transaction. * Check `has_inputs_and_outputs` for all versions Check if a transaction has inputs and outputs, independently of the transaction version. * Wait for checks in `call` method Refactor to move the repeated code into the `call` method. Now the validation methods return the set of asynchronous checks to wait for. * Add helper function to mock transparent transfers Creates a fake source UTXO, and then the input and output that represent spending that UTXO. The initial UTXO can be configured to have a script that either accepts or rejects any spend attempt. * Test if transparent V4 transaction is accepted Create a fake V4 transaction that includes a fake transparent transfer of funds. The transfer uses a script to allow any UTXO to spend it. * Test transaction V4 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Test if transparent V5 transaction is accepted Create a mock V5 transaction that includes a transparent transfer of funds. The transaction should be accepted by the verifier. * Test transaction V5 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Update `Request::upgrade` getter documentation Simplify it so that it won't become updated when #1683 is fixed. Co-authored-by: teor <teor@riseup.net>
2021-06-22 18:54:00 -07:00
/// Verify a V4 transaction.
///
/// Returns a set of asynchronous checks that must all succeed for the transaction to be
/// considered valid. These checks include:
///
/// - transparent transfers
/// - sprout shielded data
/// - sapling shielded data
///
/// The parameters of this method are:
///
/// - the `request` to verify (that contains the transaction and other metadata, see [`Request`]
/// for more information)
/// - the `network` to consider when verifying
/// - the `script_verifier` to use for verifying the transparent transfers
/// - the transparent `inputs` in the transaction
/// - the Sprout `joinsplit_data` shielded data in the transaction
/// - the `sapling_shielded_data` in the transaction
Reject V5 transactions before NU5 activation (#2285) * Add a `Transaction::version` getter Returns the version of the transaction as a `u32`. * Add `Transaction::is_overwintered` helper method Returns if the `fOverwintered` flag should be set for the transaction's version. * Use new helpers to serialize transaction version Reduce the repeated code and make it less error-prone with future changes. * Add getter methods to `transaction::Request` type Refactor to move the type deconstruction code into the `Request` type. The main objective is to make it easier to split the call handler into methods that receive the request directly. * Refactor to create `verify_v4_transaction` helper Split the code specific to V4 transactions into a separate helper method. * Create `verify_v5_transaction` helper method Prepare a separate method to have the validation code. * Add `UnsupportedByNetworkUpgrade` error variant An error for when a transaction's version isn't supported by the network upgrade of the block it's included or for the current network upgrade if the transaction is for the mempool. * Verify a V5 transaction's network upgrade For now, only NU5 supports V5 transactions. * Test that V5 transaction is rejected on Canopy Create a fake V5 transaction and try to verify it using a block height from Canopy's activation. The verifier should reject the transaction with an error saying that the network upgrade does not support that transaction version. * Test if V5 tx. is accepted after NU5 activation Create a fake V5 transaction and pretend it is placed in a block that has a height after the NU5 activation. The test should succeed, but since the NU5 activation height has not been specified yet (neither for the testnet nor the mainnet), for now this test is marked as `should_panic`. * Add `TODO` comment to the code Add more detail to what's left to do, and link to the appropriate PRs. * Use `u32` to store transaction version Use a type consistent with how the version is specified. Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net>
2021-06-14 17:15:59 -07:00
async fn verify_v4_transaction(
request: Request,
network: Network,
Validate transparent inputs and outputs in V5 transactions (#2302) * Add missing documentation Document methods to describe what they do and why. * Create an `AsyncChecks` type alias Make it simpler to write the `FuturesUnordered` type with boxed futures. This will also end up being used more when refactoring to return the checks so that the `call` method can wait on them. * Create `verify_transparent_inputs_and_outputs` Refactors the verification of the transparent inputs and outputs into a separate method. * Refactor transparent checks to use `call_all` Instead of pushing the verifications into a stream of unordered futures, use the `ServiceExt::call_all` method to build an equivalent stream after building a stream of requests. * Replace `CallAll` with `FuturesUnordered` Make it more consistent with the rest of the code, and make sure that the `len()` method is available to use for tracing. Co-authored-by: teor <teor@riseup.net> * Refactor to move wait for checks into a new method Allow the code snipped to be reused by other transaction version-specific check methods. * Verify transparent inputs in V5 transactions Use the script verifier to check the transparent inputs in a V5 transaction. * Check `has_inputs_and_outputs` for all versions Check if a transaction has inputs and outputs, independently of the transaction version. * Wait for checks in `call` method Refactor to move the repeated code into the `call` method. Now the validation methods return the set of asynchronous checks to wait for. * Add helper function to mock transparent transfers Creates a fake source UTXO, and then the input and output that represent spending that UTXO. The initial UTXO can be configured to have a script that either accepts or rejects any spend attempt. * Test if transparent V4 transaction is accepted Create a fake V4 transaction that includes a fake transparent transfer of funds. The transfer uses a script to allow any UTXO to spend it. * Test transaction V4 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Test if transparent V5 transaction is accepted Create a mock V5 transaction that includes a transparent transfer of funds. The transaction should be accepted by the verifier. * Test transaction V5 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Update `Request::upgrade` getter documentation Simplify it so that it won't become updated when #1683 is fixed. Co-authored-by: teor <teor@riseup.net>
2021-06-22 18:54:00 -07:00
script_verifier: script::Verifier<ZS>,
Reject V5 transactions before NU5 activation (#2285) * Add a `Transaction::version` getter Returns the version of the transaction as a `u32`. * Add `Transaction::is_overwintered` helper method Returns if the `fOverwintered` flag should be set for the transaction's version. * Use new helpers to serialize transaction version Reduce the repeated code and make it less error-prone with future changes. * Add getter methods to `transaction::Request` type Refactor to move the type deconstruction code into the `Request` type. The main objective is to make it easier to split the call handler into methods that receive the request directly. * Refactor to create `verify_v4_transaction` helper Split the code specific to V4 transactions into a separate helper method. * Create `verify_v5_transaction` helper method Prepare a separate method to have the validation code. * Add `UnsupportedByNetworkUpgrade` error variant An error for when a transaction's version isn't supported by the network upgrade of the block it's included or for the current network upgrade if the transaction is for the mempool. * Verify a V5 transaction's network upgrade For now, only NU5 supports V5 transactions. * Test that V5 transaction is rejected on Canopy Create a fake V5 transaction and try to verify it using a block height from Canopy's activation. The verifier should reject the transaction with an error saying that the network upgrade does not support that transaction version. * Test if V5 tx. is accepted after NU5 activation Create a fake V5 transaction and pretend it is placed in a block that has a height after the NU5 activation. The test should succeed, but since the NU5 activation height has not been specified yet (neither for the testnet nor the mainnet), for now this test is marked as `should_panic`. * Add `TODO` comment to the code Add more detail to what's left to do, and link to the appropriate PRs. * Use `u32` to store transaction version Use a type consistent with how the version is specified. Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net>
2021-06-14 17:15:59 -07:00
inputs: &[transparent::Input],
joinsplit_data: &Option<transaction::JoinSplitData<Groth16Proof>>,
sapling_shielded_data: &Option<sapling::ShieldedData<sapling::PerSpendAnchor>>,
Validate transparent inputs and outputs in V5 transactions (#2302) * Add missing documentation Document methods to describe what they do and why. * Create an `AsyncChecks` type alias Make it simpler to write the `FuturesUnordered` type with boxed futures. This will also end up being used more when refactoring to return the checks so that the `call` method can wait on them. * Create `verify_transparent_inputs_and_outputs` Refactors the verification of the transparent inputs and outputs into a separate method. * Refactor transparent checks to use `call_all` Instead of pushing the verifications into a stream of unordered futures, use the `ServiceExt::call_all` method to build an equivalent stream after building a stream of requests. * Replace `CallAll` with `FuturesUnordered` Make it more consistent with the rest of the code, and make sure that the `len()` method is available to use for tracing. Co-authored-by: teor <teor@riseup.net> * Refactor to move wait for checks into a new method Allow the code snipped to be reused by other transaction version-specific check methods. * Verify transparent inputs in V5 transactions Use the script verifier to check the transparent inputs in a V5 transaction. * Check `has_inputs_and_outputs` for all versions Check if a transaction has inputs and outputs, independently of the transaction version. * Wait for checks in `call` method Refactor to move the repeated code into the `call` method. Now the validation methods return the set of asynchronous checks to wait for. * Add helper function to mock transparent transfers Creates a fake source UTXO, and then the input and output that represent spending that UTXO. The initial UTXO can be configured to have a script that either accepts or rejects any spend attempt. * Test if transparent V4 transaction is accepted Create a fake V4 transaction that includes a fake transparent transfer of funds. The transfer uses a script to allow any UTXO to spend it. * Test transaction V4 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Test if transparent V5 transaction is accepted Create a mock V5 transaction that includes a transparent transfer of funds. The transaction should be accepted by the verifier. * Test transaction V5 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Update `Request::upgrade` getter documentation Simplify it so that it won't become updated when #1683 is fixed. Co-authored-by: teor <teor@riseup.net>
2021-06-22 18:54:00 -07:00
) -> Result<AsyncChecks, TransactionError> {
Reject V5 transactions before NU5 activation (#2285) * Add a `Transaction::version` getter Returns the version of the transaction as a `u32`. * Add `Transaction::is_overwintered` helper method Returns if the `fOverwintered` flag should be set for the transaction's version. * Use new helpers to serialize transaction version Reduce the repeated code and make it less error-prone with future changes. * Add getter methods to `transaction::Request` type Refactor to move the type deconstruction code into the `Request` type. The main objective is to make it easier to split the call handler into methods that receive the request directly. * Refactor to create `verify_v4_transaction` helper Split the code specific to V4 transactions into a separate helper method. * Create `verify_v5_transaction` helper method Prepare a separate method to have the validation code. * Add `UnsupportedByNetworkUpgrade` error variant An error for when a transaction's version isn't supported by the network upgrade of the block it's included or for the current network upgrade if the transaction is for the mempool. * Verify a V5 transaction's network upgrade For now, only NU5 supports V5 transactions. * Test that V5 transaction is rejected on Canopy Create a fake V5 transaction and try to verify it using a block height from Canopy's activation. The verifier should reject the transaction with an error saying that the network upgrade does not support that transaction version. * Test if V5 tx. is accepted after NU5 activation Create a fake V5 transaction and pretend it is placed in a block that has a height after the NU5 activation. The test should succeed, but since the NU5 activation height has not been specified yet (neither for the testnet nor the mainnet), for now this test is marked as `should_panic`. * Add `TODO` comment to the code Add more detail to what's left to do, and link to the appropriate PRs. * Use `u32` to store transaction version Use a type consistent with how the version is specified. Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net>
2021-06-14 17:15:59 -07:00
let mut spend_verifier = primitives::groth16::SPEND_VERIFIER.clone();
let mut output_verifier = primitives::groth16::OUTPUT_VERIFIER.clone();
let mut ed25519_verifier = primitives::ed25519::VERIFIER.clone();
let mut redjubjub_verifier = primitives::redjubjub::VERIFIER.clone();
// A set of asynchronous checks which must all succeed.
// We finish by waiting on these below.
Validate transparent inputs and outputs in V5 transactions (#2302) * Add missing documentation Document methods to describe what they do and why. * Create an `AsyncChecks` type alias Make it simpler to write the `FuturesUnordered` type with boxed futures. This will also end up being used more when refactoring to return the checks so that the `call` method can wait on them. * Create `verify_transparent_inputs_and_outputs` Refactors the verification of the transparent inputs and outputs into a separate method. * Refactor transparent checks to use `call_all` Instead of pushing the verifications into a stream of unordered futures, use the `ServiceExt::call_all` method to build an equivalent stream after building a stream of requests. * Replace `CallAll` with `FuturesUnordered` Make it more consistent with the rest of the code, and make sure that the `len()` method is available to use for tracing. Co-authored-by: teor <teor@riseup.net> * Refactor to move wait for checks into a new method Allow the code snipped to be reused by other transaction version-specific check methods. * Verify transparent inputs in V5 transactions Use the script verifier to check the transparent inputs in a V5 transaction. * Check `has_inputs_and_outputs` for all versions Check if a transaction has inputs and outputs, independently of the transaction version. * Wait for checks in `call` method Refactor to move the repeated code into the `call` method. Now the validation methods return the set of asynchronous checks to wait for. * Add helper function to mock transparent transfers Creates a fake source UTXO, and then the input and output that represent spending that UTXO. The initial UTXO can be configured to have a script that either accepts or rejects any spend attempt. * Test if transparent V4 transaction is accepted Create a fake V4 transaction that includes a fake transparent transfer of funds. The transfer uses a script to allow any UTXO to spend it. * Test transaction V4 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Test if transparent V5 transaction is accepted Create a mock V5 transaction that includes a transparent transfer of funds. The transaction should be accepted by the verifier. * Test transaction V5 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Update `Request::upgrade` getter documentation Simplify it so that it won't become updated when #1683 is fixed. Co-authored-by: teor <teor@riseup.net>
2021-06-22 18:54:00 -07:00
let mut async_checks = AsyncChecks::new();
Reject V5 transactions before NU5 activation (#2285) * Add a `Transaction::version` getter Returns the version of the transaction as a `u32`. * Add `Transaction::is_overwintered` helper method Returns if the `fOverwintered` flag should be set for the transaction's version. * Use new helpers to serialize transaction version Reduce the repeated code and make it less error-prone with future changes. * Add getter methods to `transaction::Request` type Refactor to move the type deconstruction code into the `Request` type. The main objective is to make it easier to split the call handler into methods that receive the request directly. * Refactor to create `verify_v4_transaction` helper Split the code specific to V4 transactions into a separate helper method. * Create `verify_v5_transaction` helper method Prepare a separate method to have the validation code. * Add `UnsupportedByNetworkUpgrade` error variant An error for when a transaction's version isn't supported by the network upgrade of the block it's included or for the current network upgrade if the transaction is for the mempool. * Verify a V5 transaction's network upgrade For now, only NU5 supports V5 transactions. * Test that V5 transaction is rejected on Canopy Create a fake V5 transaction and try to verify it using a block height from Canopy's activation. The verifier should reject the transaction with an error saying that the network upgrade does not support that transaction version. * Test if V5 tx. is accepted after NU5 activation Create a fake V5 transaction and pretend it is placed in a block that has a height after the NU5 activation. The test should succeed, but since the NU5 activation height has not been specified yet (neither for the testnet nor the mainnet), for now this test is marked as `should_panic`. * Add `TODO` comment to the code Add more detail to what's left to do, and link to the appropriate PRs. * Use `u32` to store transaction version Use a type consistent with how the version is specified. Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net>
2021-06-14 17:15:59 -07:00
let tx = request.transaction();
let upgrade = request.upgrade(network);
Validate transparent inputs and outputs in V5 transactions (#2302) * Add missing documentation Document methods to describe what they do and why. * Create an `AsyncChecks` type alias Make it simpler to write the `FuturesUnordered` type with boxed futures. This will also end up being used more when refactoring to return the checks so that the `call` method can wait on them. * Create `verify_transparent_inputs_and_outputs` Refactors the verification of the transparent inputs and outputs into a separate method. * Refactor transparent checks to use `call_all` Instead of pushing the verifications into a stream of unordered futures, use the `ServiceExt::call_all` method to build an equivalent stream after building a stream of requests. * Replace `CallAll` with `FuturesUnordered` Make it more consistent with the rest of the code, and make sure that the `len()` method is available to use for tracing. Co-authored-by: teor <teor@riseup.net> * Refactor to move wait for checks into a new method Allow the code snipped to be reused by other transaction version-specific check methods. * Verify transparent inputs in V5 transactions Use the script verifier to check the transparent inputs in a V5 transaction. * Check `has_inputs_and_outputs` for all versions Check if a transaction has inputs and outputs, independently of the transaction version. * Wait for checks in `call` method Refactor to move the repeated code into the `call` method. Now the validation methods return the set of asynchronous checks to wait for. * Add helper function to mock transparent transfers Creates a fake source UTXO, and then the input and output that represent spending that UTXO. The initial UTXO can be configured to have a script that either accepts or rejects any spend attempt. * Test if transparent V4 transaction is accepted Create a fake V4 transaction that includes a fake transparent transfer of funds. The transfer uses a script to allow any UTXO to spend it. * Test transaction V4 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Test if transparent V5 transaction is accepted Create a mock V5 transaction that includes a transparent transfer of funds. The transaction should be accepted by the verifier. * Test transaction V5 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Update `Request::upgrade` getter documentation Simplify it so that it won't become updated when #1683 is fixed. Co-authored-by: teor <teor@riseup.net>
2021-06-22 18:54:00 -07:00
// Add asynchronous checks of the transparent inputs and outputs
async_checks.extend(Self::verify_transparent_inputs_and_outputs(
&request,
network,
inputs,
script_verifier,
)?);
Reject V5 transactions before NU5 activation (#2285) * Add a `Transaction::version` getter Returns the version of the transaction as a `u32`. * Add `Transaction::is_overwintered` helper method Returns if the `fOverwintered` flag should be set for the transaction's version. * Use new helpers to serialize transaction version Reduce the repeated code and make it less error-prone with future changes. * Add getter methods to `transaction::Request` type Refactor to move the type deconstruction code into the `Request` type. The main objective is to make it easier to split the call handler into methods that receive the request directly. * Refactor to create `verify_v4_transaction` helper Split the code specific to V4 transactions into a separate helper method. * Create `verify_v5_transaction` helper method Prepare a separate method to have the validation code. * Add `UnsupportedByNetworkUpgrade` error variant An error for when a transaction's version isn't supported by the network upgrade of the block it's included or for the current network upgrade if the transaction is for the mempool. * Verify a V5 transaction's network upgrade For now, only NU5 supports V5 transactions. * Test that V5 transaction is rejected on Canopy Create a fake V5 transaction and try to verify it using a block height from Canopy's activation. The verifier should reject the transaction with an error saying that the network upgrade does not support that transaction version. * Test if V5 tx. is accepted after NU5 activation Create a fake V5 transaction and pretend it is placed in a block that has a height after the NU5 activation. The test should succeed, but since the NU5 activation height has not been specified yet (neither for the testnet nor the mainnet), for now this test is marked as `should_panic`. * Add `TODO` comment to the code Add more detail to what's left to do, and link to the appropriate PRs. * Use `u32` to store transaction version Use a type consistent with how the version is specified. Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net>
2021-06-14 17:15:59 -07:00
let shielded_sighash = tx.sighash(upgrade, HashType::ALL, None);
if let Some(joinsplit_data) = joinsplit_data {
// XXX create a method on JoinSplitData
// that prepares groth16::Items with the correct proofs
// and proof inputs, handling interstitial treestates
// correctly.
// Then, pass those items to self.joinsplit to verify them.
// Consensus rule: The joinSplitSig MUST represent a
// valid signature, under joinSplitPubKey, of the
// sighash.
//
// Queue the validation of the JoinSplit signature while
// adding the resulting future to our collection of
// async checks that (at a minimum) must pass for the
// transaction to verify.
//
// https://zips.z.cash/protocol/protocol.pdf#sproutnonmalleability
// https://zips.z.cash/protocol/protocol.pdf#txnencodingandconsensus
let rsp = ed25519_verifier.ready_and().await?.call(
(
joinsplit_data.pub_key,
joinsplit_data.sig,
&shielded_sighash,
)
.into(),
);
async_checks.push(rsp.boxed());
}
if let Some(sapling_shielded_data) = sapling_shielded_data {
for spend in sapling_shielded_data.spends_per_anchor() {
// Consensus rule: cv and rk MUST NOT be of small
// order, i.e. [h_J]cv MUST NOT be 𝒪_J and [h_J]rk
// MUST NOT be 𝒪_J.
//
// https://zips.z.cash/protocol/protocol.pdf#spenddesc
check::spend_cv_rk_not_small_order(&spend)?;
// Consensus rule: The proof π_ZKSpend MUST be valid
// given a primary input formed from the other
// fields except spendAuthSig.
//
// Queue the verification of the Groth16 spend proof
// for each Spend description while adding the
// resulting future to our collection of async
// checks that (at a minimum) must pass for the
// transaction to verify.
let spend_rsp = spend_verifier
.ready_and()
.await?
.call(primitives::groth16::ItemWrapper::from(&spend).into());
async_checks.push(spend_rsp.boxed());
// Consensus rule: The spend authorization signature
// MUST be a valid SpendAuthSig signature over
// SigHash using rk as the validating key.
//
// Queue the validation of the RedJubjub spend
// authorization signature for each Spend
// description while adding the resulting future to
// our collection of async checks that (at a
// minimum) must pass for the transaction to verify.
let rsp = redjubjub_verifier
.ready_and()
.await?
.call((spend.rk, spend.spend_auth_sig, &shielded_sighash).into());
async_checks.push(rsp.boxed());
}
for output in sapling_shielded_data.outputs() {
// Consensus rule: cv and wpk MUST NOT be of small
// order, i.e. [h_J]cv MUST NOT be 𝒪_J and [h_J]wpk
// MUST NOT be 𝒪_J.
//
// https://zips.z.cash/protocol/protocol.pdf#outputdesc
check::output_cv_epk_not_small_order(output)?;
// Consensus rule: The proof π_ZKOutput MUST be
// valid given a primary input formed from the other
// fields except C^enc and C^out.
//
// Queue the verification of the Groth16 output
// proof for each Output description while adding
// the resulting future to our collection of async
// checks that (at a minimum) must pass for the
// transaction to verify.
let output_rsp = output_verifier
.ready_and()
.await?
.call(primitives::groth16::ItemWrapper::from(output).into());
async_checks.push(output_rsp.boxed());
}
let bvk = sapling_shielded_data.binding_verification_key();
// TODO: enable async verification and remove this block - #1939
{
let item: zebra_chain::primitives::redjubjub::batch::Item =
(bvk, sapling_shielded_data.binding_sig, &shielded_sighash).into();
item.verify_single().unwrap_or_else(|binding_sig_error| {
let binding_sig_error = binding_sig_error.to_string();
tracing::warn!(%binding_sig_error, "ignoring");
metrics::counter!("zebra.error.sapling.binding",
1,
"kind" => binding_sig_error);
});
// Ignore errors until binding signatures are fixed
//.map_err(|e| BoxError::from(Box::new(e)))?;
}
let _rsp = redjubjub_verifier
.ready_and()
.await?
.call((bvk, sapling_shielded_data.binding_sig, &shielded_sighash).into())
.boxed();
// TODO: stop ignoring binding signature errors - #1939
// async_checks.push(rsp);
}
Validate transparent inputs and outputs in V5 transactions (#2302) * Add missing documentation Document methods to describe what they do and why. * Create an `AsyncChecks` type alias Make it simpler to write the `FuturesUnordered` type with boxed futures. This will also end up being used more when refactoring to return the checks so that the `call` method can wait on them. * Create `verify_transparent_inputs_and_outputs` Refactors the verification of the transparent inputs and outputs into a separate method. * Refactor transparent checks to use `call_all` Instead of pushing the verifications into a stream of unordered futures, use the `ServiceExt::call_all` method to build an equivalent stream after building a stream of requests. * Replace `CallAll` with `FuturesUnordered` Make it more consistent with the rest of the code, and make sure that the `len()` method is available to use for tracing. Co-authored-by: teor <teor@riseup.net> * Refactor to move wait for checks into a new method Allow the code snipped to be reused by other transaction version-specific check methods. * Verify transparent inputs in V5 transactions Use the script verifier to check the transparent inputs in a V5 transaction. * Check `has_inputs_and_outputs` for all versions Check if a transaction has inputs and outputs, independently of the transaction version. * Wait for checks in `call` method Refactor to move the repeated code into the `call` method. Now the validation methods return the set of asynchronous checks to wait for. * Add helper function to mock transparent transfers Creates a fake source UTXO, and then the input and output that represent spending that UTXO. The initial UTXO can be configured to have a script that either accepts or rejects any spend attempt. * Test if transparent V4 transaction is accepted Create a fake V4 transaction that includes a fake transparent transfer of funds. The transfer uses a script to allow any UTXO to spend it. * Test transaction V4 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Test if transparent V5 transaction is accepted Create a mock V5 transaction that includes a transparent transfer of funds. The transaction should be accepted by the verifier. * Test transaction V5 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Update `Request::upgrade` getter documentation Simplify it so that it won't become updated when #1683 is fixed. Co-authored-by: teor <teor@riseup.net>
2021-06-22 18:54:00 -07:00
Ok(async_checks)
Reject V5 transactions before NU5 activation (#2285) * Add a `Transaction::version` getter Returns the version of the transaction as a `u32`. * Add `Transaction::is_overwintered` helper method Returns if the `fOverwintered` flag should be set for the transaction's version. * Use new helpers to serialize transaction version Reduce the repeated code and make it less error-prone with future changes. * Add getter methods to `transaction::Request` type Refactor to move the type deconstruction code into the `Request` type. The main objective is to make it easier to split the call handler into methods that receive the request directly. * Refactor to create `verify_v4_transaction` helper Split the code specific to V4 transactions into a separate helper method. * Create `verify_v5_transaction` helper method Prepare a separate method to have the validation code. * Add `UnsupportedByNetworkUpgrade` error variant An error for when a transaction's version isn't supported by the network upgrade of the block it's included or for the current network upgrade if the transaction is for the mempool. * Verify a V5 transaction's network upgrade For now, only NU5 supports V5 transactions. * Test that V5 transaction is rejected on Canopy Create a fake V5 transaction and try to verify it using a block height from Canopy's activation. The verifier should reject the transaction with an error saying that the network upgrade does not support that transaction version. * Test if V5 tx. is accepted after NU5 activation Create a fake V5 transaction and pretend it is placed in a block that has a height after the NU5 activation. The test should succeed, but since the NU5 activation height has not been specified yet (neither for the testnet nor the mainnet), for now this test is marked as `should_panic`. * Add `TODO` comment to the code Add more detail to what's left to do, and link to the appropriate PRs. * Use `u32` to store transaction version Use a type consistent with how the version is specified. Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net>
2021-06-14 17:15:59 -07:00
}
Validate transparent inputs and outputs in V5 transactions (#2302) * Add missing documentation Document methods to describe what they do and why. * Create an `AsyncChecks` type alias Make it simpler to write the `FuturesUnordered` type with boxed futures. This will also end up being used more when refactoring to return the checks so that the `call` method can wait on them. * Create `verify_transparent_inputs_and_outputs` Refactors the verification of the transparent inputs and outputs into a separate method. * Refactor transparent checks to use `call_all` Instead of pushing the verifications into a stream of unordered futures, use the `ServiceExt::call_all` method to build an equivalent stream after building a stream of requests. * Replace `CallAll` with `FuturesUnordered` Make it more consistent with the rest of the code, and make sure that the `len()` method is available to use for tracing. Co-authored-by: teor <teor@riseup.net> * Refactor to move wait for checks into a new method Allow the code snipped to be reused by other transaction version-specific check methods. * Verify transparent inputs in V5 transactions Use the script verifier to check the transparent inputs in a V5 transaction. * Check `has_inputs_and_outputs` for all versions Check if a transaction has inputs and outputs, independently of the transaction version. * Wait for checks in `call` method Refactor to move the repeated code into the `call` method. Now the validation methods return the set of asynchronous checks to wait for. * Add helper function to mock transparent transfers Creates a fake source UTXO, and then the input and output that represent spending that UTXO. The initial UTXO can be configured to have a script that either accepts or rejects any spend attempt. * Test if transparent V4 transaction is accepted Create a fake V4 transaction that includes a fake transparent transfer of funds. The transfer uses a script to allow any UTXO to spend it. * Test transaction V4 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Test if transparent V5 transaction is accepted Create a mock V5 transaction that includes a transparent transfer of funds. The transaction should be accepted by the verifier. * Test transaction V5 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Update `Request::upgrade` getter documentation Simplify it so that it won't become updated when #1683 is fixed. Co-authored-by: teor <teor@riseup.net>
2021-06-22 18:54:00 -07:00
/// Verify a V5 transaction.
///
/// Returns a set of asynchronous checks that must all succeed for the transaction to be
/// considered valid. These checks include:
///
/// - transaction support by the considered network upgrade (see [`Request::upgrade`])
/// - transparent transfers
/// - sapling shielded data (TODO)
/// - orchard shielded data (TODO)
///
/// The parameters of this method are:
///
/// - the `request` to verify (that contains the transaction and other metadata, see [`Request`]
/// for more information)
/// - the `network` to consider when verifying
/// - the `script_verifier` to use for verifying the transparent transfers
/// - the transparent `inputs` in the transaction
Reject V5 transactions before NU5 activation (#2285) * Add a `Transaction::version` getter Returns the version of the transaction as a `u32`. * Add `Transaction::is_overwintered` helper method Returns if the `fOverwintered` flag should be set for the transaction's version. * Use new helpers to serialize transaction version Reduce the repeated code and make it less error-prone with future changes. * Add getter methods to `transaction::Request` type Refactor to move the type deconstruction code into the `Request` type. The main objective is to make it easier to split the call handler into methods that receive the request directly. * Refactor to create `verify_v4_transaction` helper Split the code specific to V4 transactions into a separate helper method. * Create `verify_v5_transaction` helper method Prepare a separate method to have the validation code. * Add `UnsupportedByNetworkUpgrade` error variant An error for when a transaction's version isn't supported by the network upgrade of the block it's included or for the current network upgrade if the transaction is for the mempool. * Verify a V5 transaction's network upgrade For now, only NU5 supports V5 transactions. * Test that V5 transaction is rejected on Canopy Create a fake V5 transaction and try to verify it using a block height from Canopy's activation. The verifier should reject the transaction with an error saying that the network upgrade does not support that transaction version. * Test if V5 tx. is accepted after NU5 activation Create a fake V5 transaction and pretend it is placed in a block that has a height after the NU5 activation. The test should succeed, but since the NU5 activation height has not been specified yet (neither for the testnet nor the mainnet), for now this test is marked as `should_panic`. * Add `TODO` comment to the code Add more detail to what's left to do, and link to the appropriate PRs. * Use `u32` to store transaction version Use a type consistent with how the version is specified. Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net>
2021-06-14 17:15:59 -07:00
async fn verify_v5_transaction(
request: Request,
network: Network,
Validate transparent inputs and outputs in V5 transactions (#2302) * Add missing documentation Document methods to describe what they do and why. * Create an `AsyncChecks` type alias Make it simpler to write the `FuturesUnordered` type with boxed futures. This will also end up being used more when refactoring to return the checks so that the `call` method can wait on them. * Create `verify_transparent_inputs_and_outputs` Refactors the verification of the transparent inputs and outputs into a separate method. * Refactor transparent checks to use `call_all` Instead of pushing the verifications into a stream of unordered futures, use the `ServiceExt::call_all` method to build an equivalent stream after building a stream of requests. * Replace `CallAll` with `FuturesUnordered` Make it more consistent with the rest of the code, and make sure that the `len()` method is available to use for tracing. Co-authored-by: teor <teor@riseup.net> * Refactor to move wait for checks into a new method Allow the code snipped to be reused by other transaction version-specific check methods. * Verify transparent inputs in V5 transactions Use the script verifier to check the transparent inputs in a V5 transaction. * Check `has_inputs_and_outputs` for all versions Check if a transaction has inputs and outputs, independently of the transaction version. * Wait for checks in `call` method Refactor to move the repeated code into the `call` method. Now the validation methods return the set of asynchronous checks to wait for. * Add helper function to mock transparent transfers Creates a fake source UTXO, and then the input and output that represent spending that UTXO. The initial UTXO can be configured to have a script that either accepts or rejects any spend attempt. * Test if transparent V4 transaction is accepted Create a fake V4 transaction that includes a fake transparent transfer of funds. The transfer uses a script to allow any UTXO to spend it. * Test transaction V4 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Test if transparent V5 transaction is accepted Create a mock V5 transaction that includes a transparent transfer of funds. The transaction should be accepted by the verifier. * Test transaction V5 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Update `Request::upgrade` getter documentation Simplify it so that it won't become updated when #1683 is fixed. Co-authored-by: teor <teor@riseup.net>
2021-06-22 18:54:00 -07:00
script_verifier: script::Verifier<ZS>,
inputs: &[transparent::Input],
) -> Result<AsyncChecks, TransactionError> {
Reject V5 transactions before NU5 activation (#2285) * Add a `Transaction::version` getter Returns the version of the transaction as a `u32`. * Add `Transaction::is_overwintered` helper method Returns if the `fOverwintered` flag should be set for the transaction's version. * Use new helpers to serialize transaction version Reduce the repeated code and make it less error-prone with future changes. * Add getter methods to `transaction::Request` type Refactor to move the type deconstruction code into the `Request` type. The main objective is to make it easier to split the call handler into methods that receive the request directly. * Refactor to create `verify_v4_transaction` helper Split the code specific to V4 transactions into a separate helper method. * Create `verify_v5_transaction` helper method Prepare a separate method to have the validation code. * Add `UnsupportedByNetworkUpgrade` error variant An error for when a transaction's version isn't supported by the network upgrade of the block it's included or for the current network upgrade if the transaction is for the mempool. * Verify a V5 transaction's network upgrade For now, only NU5 supports V5 transactions. * Test that V5 transaction is rejected on Canopy Create a fake V5 transaction and try to verify it using a block height from Canopy's activation. The verifier should reject the transaction with an error saying that the network upgrade does not support that transaction version. * Test if V5 tx. is accepted after NU5 activation Create a fake V5 transaction and pretend it is placed in a block that has a height after the NU5 activation. The test should succeed, but since the NU5 activation height has not been specified yet (neither for the testnet nor the mainnet), for now this test is marked as `should_panic`. * Add `TODO` comment to the code Add more detail to what's left to do, and link to the appropriate PRs. * Use `u32` to store transaction version Use a type consistent with how the version is specified. Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net>
2021-06-14 17:15:59 -07:00
Self::verify_v5_transaction_network_upgrade(
&request.transaction(),
request.upgrade(network),
)?;
Validate transparent inputs and outputs in V5 transactions (#2302) * Add missing documentation Document methods to describe what they do and why. * Create an `AsyncChecks` type alias Make it simpler to write the `FuturesUnordered` type with boxed futures. This will also end up being used more when refactoring to return the checks so that the `call` method can wait on them. * Create `verify_transparent_inputs_and_outputs` Refactors the verification of the transparent inputs and outputs into a separate method. * Refactor transparent checks to use `call_all` Instead of pushing the verifications into a stream of unordered futures, use the `ServiceExt::call_all` method to build an equivalent stream after building a stream of requests. * Replace `CallAll` with `FuturesUnordered` Make it more consistent with the rest of the code, and make sure that the `len()` method is available to use for tracing. Co-authored-by: teor <teor@riseup.net> * Refactor to move wait for checks into a new method Allow the code snipped to be reused by other transaction version-specific check methods. * Verify transparent inputs in V5 transactions Use the script verifier to check the transparent inputs in a V5 transaction. * Check `has_inputs_and_outputs` for all versions Check if a transaction has inputs and outputs, independently of the transaction version. * Wait for checks in `call` method Refactor to move the repeated code into the `call` method. Now the validation methods return the set of asynchronous checks to wait for. * Add helper function to mock transparent transfers Creates a fake source UTXO, and then the input and output that represent spending that UTXO. The initial UTXO can be configured to have a script that either accepts or rejects any spend attempt. * Test if transparent V4 transaction is accepted Create a fake V4 transaction that includes a fake transparent transfer of funds. The transfer uses a script to allow any UTXO to spend it. * Test transaction V4 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Test if transparent V5 transaction is accepted Create a mock V5 transaction that includes a transparent transfer of funds. The transaction should be accepted by the verifier. * Test transaction V5 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Update `Request::upgrade` getter documentation Simplify it so that it won't become updated when #1683 is fixed. Co-authored-by: teor <teor@riseup.net>
2021-06-22 18:54:00 -07:00
let _async_checks = Self::verify_transparent_inputs_and_outputs(
&request,
network,
inputs,
script_verifier,
)?;
Reject V5 transactions before NU5 activation (#2285) * Add a `Transaction::version` getter Returns the version of the transaction as a `u32`. * Add `Transaction::is_overwintered` helper method Returns if the `fOverwintered` flag should be set for the transaction's version. * Use new helpers to serialize transaction version Reduce the repeated code and make it less error-prone with future changes. * Add getter methods to `transaction::Request` type Refactor to move the type deconstruction code into the `Request` type. The main objective is to make it easier to split the call handler into methods that receive the request directly. * Refactor to create `verify_v4_transaction` helper Split the code specific to V4 transactions into a separate helper method. * Create `verify_v5_transaction` helper method Prepare a separate method to have the validation code. * Add `UnsupportedByNetworkUpgrade` error variant An error for when a transaction's version isn't supported by the network upgrade of the block it's included or for the current network upgrade if the transaction is for the mempool. * Verify a V5 transaction's network upgrade For now, only NU5 supports V5 transactions. * Test that V5 transaction is rejected on Canopy Create a fake V5 transaction and try to verify it using a block height from Canopy's activation. The verifier should reject the transaction with an error saying that the network upgrade does not support that transaction version. * Test if V5 tx. is accepted after NU5 activation Create a fake V5 transaction and pretend it is placed in a block that has a height after the NU5 activation. The test should succeed, but since the NU5 activation height has not been specified yet (neither for the testnet nor the mainnet), for now this test is marked as `should_panic`. * Add `TODO` comment to the code Add more detail to what's left to do, and link to the appropriate PRs. * Use `u32` to store transaction version Use a type consistent with how the version is specified. Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net>
2021-06-14 17:15:59 -07:00
// TODO:
// - verify sapling shielded pool (#1981)
// - verify orchard shielded pool (ZIP-224) (#2105)
// - ZIP-216 (#1798)
// - ZIP-244 (#1874)
unimplemented!("V5 transaction validation is not yet complete");
}
Validate transparent inputs and outputs in V5 transactions (#2302) * Add missing documentation Document methods to describe what they do and why. * Create an `AsyncChecks` type alias Make it simpler to write the `FuturesUnordered` type with boxed futures. This will also end up being used more when refactoring to return the checks so that the `call` method can wait on them. * Create `verify_transparent_inputs_and_outputs` Refactors the verification of the transparent inputs and outputs into a separate method. * Refactor transparent checks to use `call_all` Instead of pushing the verifications into a stream of unordered futures, use the `ServiceExt::call_all` method to build an equivalent stream after building a stream of requests. * Replace `CallAll` with `FuturesUnordered` Make it more consistent with the rest of the code, and make sure that the `len()` method is available to use for tracing. Co-authored-by: teor <teor@riseup.net> * Refactor to move wait for checks into a new method Allow the code snipped to be reused by other transaction version-specific check methods. * Verify transparent inputs in V5 transactions Use the script verifier to check the transparent inputs in a V5 transaction. * Check `has_inputs_and_outputs` for all versions Check if a transaction has inputs and outputs, independently of the transaction version. * Wait for checks in `call` method Refactor to move the repeated code into the `call` method. Now the validation methods return the set of asynchronous checks to wait for. * Add helper function to mock transparent transfers Creates a fake source UTXO, and then the input and output that represent spending that UTXO. The initial UTXO can be configured to have a script that either accepts or rejects any spend attempt. * Test if transparent V4 transaction is accepted Create a fake V4 transaction that includes a fake transparent transfer of funds. The transfer uses a script to allow any UTXO to spend it. * Test transaction V4 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Test if transparent V5 transaction is accepted Create a mock V5 transaction that includes a transparent transfer of funds. The transaction should be accepted by the verifier. * Test transaction V5 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Update `Request::upgrade` getter documentation Simplify it so that it won't become updated when #1683 is fixed. Co-authored-by: teor <teor@riseup.net>
2021-06-22 18:54:00 -07:00
/// Verifies if a V5 `transaction` is supported by `network_upgrade`.
Reject V5 transactions before NU5 activation (#2285) * Add a `Transaction::version` getter Returns the version of the transaction as a `u32`. * Add `Transaction::is_overwintered` helper method Returns if the `fOverwintered` flag should be set for the transaction's version. * Use new helpers to serialize transaction version Reduce the repeated code and make it less error-prone with future changes. * Add getter methods to `transaction::Request` type Refactor to move the type deconstruction code into the `Request` type. The main objective is to make it easier to split the call handler into methods that receive the request directly. * Refactor to create `verify_v4_transaction` helper Split the code specific to V4 transactions into a separate helper method. * Create `verify_v5_transaction` helper method Prepare a separate method to have the validation code. * Add `UnsupportedByNetworkUpgrade` error variant An error for when a transaction's version isn't supported by the network upgrade of the block it's included or for the current network upgrade if the transaction is for the mempool. * Verify a V5 transaction's network upgrade For now, only NU5 supports V5 transactions. * Test that V5 transaction is rejected on Canopy Create a fake V5 transaction and try to verify it using a block height from Canopy's activation. The verifier should reject the transaction with an error saying that the network upgrade does not support that transaction version. * Test if V5 tx. is accepted after NU5 activation Create a fake V5 transaction and pretend it is placed in a block that has a height after the NU5 activation. The test should succeed, but since the NU5 activation height has not been specified yet (neither for the testnet nor the mainnet), for now this test is marked as `should_panic`. * Add `TODO` comment to the code Add more detail to what's left to do, and link to the appropriate PRs. * Use `u32` to store transaction version Use a type consistent with how the version is specified. Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net>
2021-06-14 17:15:59 -07:00
fn verify_v5_transaction_network_upgrade(
transaction: &Transaction,
Validate transparent inputs and outputs in V5 transactions (#2302) * Add missing documentation Document methods to describe what they do and why. * Create an `AsyncChecks` type alias Make it simpler to write the `FuturesUnordered` type with boxed futures. This will also end up being used more when refactoring to return the checks so that the `call` method can wait on them. * Create `verify_transparent_inputs_and_outputs` Refactors the verification of the transparent inputs and outputs into a separate method. * Refactor transparent checks to use `call_all` Instead of pushing the verifications into a stream of unordered futures, use the `ServiceExt::call_all` method to build an equivalent stream after building a stream of requests. * Replace `CallAll` with `FuturesUnordered` Make it more consistent with the rest of the code, and make sure that the `len()` method is available to use for tracing. Co-authored-by: teor <teor@riseup.net> * Refactor to move wait for checks into a new method Allow the code snipped to be reused by other transaction version-specific check methods. * Verify transparent inputs in V5 transactions Use the script verifier to check the transparent inputs in a V5 transaction. * Check `has_inputs_and_outputs` for all versions Check if a transaction has inputs and outputs, independently of the transaction version. * Wait for checks in `call` method Refactor to move the repeated code into the `call` method. Now the validation methods return the set of asynchronous checks to wait for. * Add helper function to mock transparent transfers Creates a fake source UTXO, and then the input and output that represent spending that UTXO. The initial UTXO can be configured to have a script that either accepts or rejects any spend attempt. * Test if transparent V4 transaction is accepted Create a fake V4 transaction that includes a fake transparent transfer of funds. The transfer uses a script to allow any UTXO to spend it. * Test transaction V4 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Test if transparent V5 transaction is accepted Create a mock V5 transaction that includes a transparent transfer of funds. The transaction should be accepted by the verifier. * Test transaction V5 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Update `Request::upgrade` getter documentation Simplify it so that it won't become updated when #1683 is fixed. Co-authored-by: teor <teor@riseup.net>
2021-06-22 18:54:00 -07:00
network_upgrade: NetworkUpgrade,
Reject V5 transactions before NU5 activation (#2285) * Add a `Transaction::version` getter Returns the version of the transaction as a `u32`. * Add `Transaction::is_overwintered` helper method Returns if the `fOverwintered` flag should be set for the transaction's version. * Use new helpers to serialize transaction version Reduce the repeated code and make it less error-prone with future changes. * Add getter methods to `transaction::Request` type Refactor to move the type deconstruction code into the `Request` type. The main objective is to make it easier to split the call handler into methods that receive the request directly. * Refactor to create `verify_v4_transaction` helper Split the code specific to V4 transactions into a separate helper method. * Create `verify_v5_transaction` helper method Prepare a separate method to have the validation code. * Add `UnsupportedByNetworkUpgrade` error variant An error for when a transaction's version isn't supported by the network upgrade of the block it's included or for the current network upgrade if the transaction is for the mempool. * Verify a V5 transaction's network upgrade For now, only NU5 supports V5 transactions. * Test that V5 transaction is rejected on Canopy Create a fake V5 transaction and try to verify it using a block height from Canopy's activation. The verifier should reject the transaction with an error saying that the network upgrade does not support that transaction version. * Test if V5 tx. is accepted after NU5 activation Create a fake V5 transaction and pretend it is placed in a block that has a height after the NU5 activation. The test should succeed, but since the NU5 activation height has not been specified yet (neither for the testnet nor the mainnet), for now this test is marked as `should_panic`. * Add `TODO` comment to the code Add more detail to what's left to do, and link to the appropriate PRs. * Use `u32` to store transaction version Use a type consistent with how the version is specified. Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net>
2021-06-14 17:15:59 -07:00
) -> Result<(), TransactionError> {
Validate transparent inputs and outputs in V5 transactions (#2302) * Add missing documentation Document methods to describe what they do and why. * Create an `AsyncChecks` type alias Make it simpler to write the `FuturesUnordered` type with boxed futures. This will also end up being used more when refactoring to return the checks so that the `call` method can wait on them. * Create `verify_transparent_inputs_and_outputs` Refactors the verification of the transparent inputs and outputs into a separate method. * Refactor transparent checks to use `call_all` Instead of pushing the verifications into a stream of unordered futures, use the `ServiceExt::call_all` method to build an equivalent stream after building a stream of requests. * Replace `CallAll` with `FuturesUnordered` Make it more consistent with the rest of the code, and make sure that the `len()` method is available to use for tracing. Co-authored-by: teor <teor@riseup.net> * Refactor to move wait for checks into a new method Allow the code snipped to be reused by other transaction version-specific check methods. * Verify transparent inputs in V5 transactions Use the script verifier to check the transparent inputs in a V5 transaction. * Check `has_inputs_and_outputs` for all versions Check if a transaction has inputs and outputs, independently of the transaction version. * Wait for checks in `call` method Refactor to move the repeated code into the `call` method. Now the validation methods return the set of asynchronous checks to wait for. * Add helper function to mock transparent transfers Creates a fake source UTXO, and then the input and output that represent spending that UTXO. The initial UTXO can be configured to have a script that either accepts or rejects any spend attempt. * Test if transparent V4 transaction is accepted Create a fake V4 transaction that includes a fake transparent transfer of funds. The transfer uses a script to allow any UTXO to spend it. * Test transaction V4 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Test if transparent V5 transaction is accepted Create a mock V5 transaction that includes a transparent transfer of funds. The transaction should be accepted by the verifier. * Test transaction V5 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Update `Request::upgrade` getter documentation Simplify it so that it won't become updated when #1683 is fixed. Co-authored-by: teor <teor@riseup.net>
2021-06-22 18:54:00 -07:00
match network_upgrade {
Reject V5 transactions before NU5 activation (#2285) * Add a `Transaction::version` getter Returns the version of the transaction as a `u32`. * Add `Transaction::is_overwintered` helper method Returns if the `fOverwintered` flag should be set for the transaction's version. * Use new helpers to serialize transaction version Reduce the repeated code and make it less error-prone with future changes. * Add getter methods to `transaction::Request` type Refactor to move the type deconstruction code into the `Request` type. The main objective is to make it easier to split the call handler into methods that receive the request directly. * Refactor to create `verify_v4_transaction` helper Split the code specific to V4 transactions into a separate helper method. * Create `verify_v5_transaction` helper method Prepare a separate method to have the validation code. * Add `UnsupportedByNetworkUpgrade` error variant An error for when a transaction's version isn't supported by the network upgrade of the block it's included or for the current network upgrade if the transaction is for the mempool. * Verify a V5 transaction's network upgrade For now, only NU5 supports V5 transactions. * Test that V5 transaction is rejected on Canopy Create a fake V5 transaction and try to verify it using a block height from Canopy's activation. The verifier should reject the transaction with an error saying that the network upgrade does not support that transaction version. * Test if V5 tx. is accepted after NU5 activation Create a fake V5 transaction and pretend it is placed in a block that has a height after the NU5 activation. The test should succeed, but since the NU5 activation height has not been specified yet (neither for the testnet nor the mainnet), for now this test is marked as `should_panic`. * Add `TODO` comment to the code Add more detail to what's left to do, and link to the appropriate PRs. * Use `u32` to store transaction version Use a type consistent with how the version is specified. Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net>
2021-06-14 17:15:59 -07:00
// Supports V5 transactions
NetworkUpgrade::Nu5 => Ok(()),
// Does not support V5 transactions
NetworkUpgrade::Genesis
| NetworkUpgrade::BeforeOverwinter
| NetworkUpgrade::Overwinter
| NetworkUpgrade::Sapling
| NetworkUpgrade::Blossom
| NetworkUpgrade::Heartwood
| NetworkUpgrade::Canopy => Err(TransactionError::UnsupportedByNetworkUpgrade(
transaction.version(),
Validate transparent inputs and outputs in V5 transactions (#2302) * Add missing documentation Document methods to describe what they do and why. * Create an `AsyncChecks` type alias Make it simpler to write the `FuturesUnordered` type with boxed futures. This will also end up being used more when refactoring to return the checks so that the `call` method can wait on them. * Create `verify_transparent_inputs_and_outputs` Refactors the verification of the transparent inputs and outputs into a separate method. * Refactor transparent checks to use `call_all` Instead of pushing the verifications into a stream of unordered futures, use the `ServiceExt::call_all` method to build an equivalent stream after building a stream of requests. * Replace `CallAll` with `FuturesUnordered` Make it more consistent with the rest of the code, and make sure that the `len()` method is available to use for tracing. Co-authored-by: teor <teor@riseup.net> * Refactor to move wait for checks into a new method Allow the code snipped to be reused by other transaction version-specific check methods. * Verify transparent inputs in V5 transactions Use the script verifier to check the transparent inputs in a V5 transaction. * Check `has_inputs_and_outputs` for all versions Check if a transaction has inputs and outputs, independently of the transaction version. * Wait for checks in `call` method Refactor to move the repeated code into the `call` method. Now the validation methods return the set of asynchronous checks to wait for. * Add helper function to mock transparent transfers Creates a fake source UTXO, and then the input and output that represent spending that UTXO. The initial UTXO can be configured to have a script that either accepts or rejects any spend attempt. * Test if transparent V4 transaction is accepted Create a fake V4 transaction that includes a fake transparent transfer of funds. The transfer uses a script to allow any UTXO to spend it. * Test transaction V4 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Test if transparent V5 transaction is accepted Create a mock V5 transaction that includes a transparent transfer of funds. The transaction should be accepted by the verifier. * Test transaction V5 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Update `Request::upgrade` getter documentation Simplify it so that it won't become updated when #1683 is fixed. Co-authored-by: teor <teor@riseup.net>
2021-06-22 18:54:00 -07:00
network_upgrade,
Reject V5 transactions before NU5 activation (#2285) * Add a `Transaction::version` getter Returns the version of the transaction as a `u32`. * Add `Transaction::is_overwintered` helper method Returns if the `fOverwintered` flag should be set for the transaction's version. * Use new helpers to serialize transaction version Reduce the repeated code and make it less error-prone with future changes. * Add getter methods to `transaction::Request` type Refactor to move the type deconstruction code into the `Request` type. The main objective is to make it easier to split the call handler into methods that receive the request directly. * Refactor to create `verify_v4_transaction` helper Split the code specific to V4 transactions into a separate helper method. * Create `verify_v5_transaction` helper method Prepare a separate method to have the validation code. * Add `UnsupportedByNetworkUpgrade` error variant An error for when a transaction's version isn't supported by the network upgrade of the block it's included or for the current network upgrade if the transaction is for the mempool. * Verify a V5 transaction's network upgrade For now, only NU5 supports V5 transactions. * Test that V5 transaction is rejected on Canopy Create a fake V5 transaction and try to verify it using a block height from Canopy's activation. The verifier should reject the transaction with an error saying that the network upgrade does not support that transaction version. * Test if V5 tx. is accepted after NU5 activation Create a fake V5 transaction and pretend it is placed in a block that has a height after the NU5 activation. The test should succeed, but since the NU5 activation height has not been specified yet (neither for the testnet nor the mainnet), for now this test is marked as `should_panic`. * Add `TODO` comment to the code Add more detail to what's left to do, and link to the appropriate PRs. * Use `u32` to store transaction version Use a type consistent with how the version is specified. Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net>
2021-06-14 17:15:59 -07:00
)),
}
}
Validate transparent inputs and outputs in V5 transactions (#2302) * Add missing documentation Document methods to describe what they do and why. * Create an `AsyncChecks` type alias Make it simpler to write the `FuturesUnordered` type with boxed futures. This will also end up being used more when refactoring to return the checks so that the `call` method can wait on them. * Create `verify_transparent_inputs_and_outputs` Refactors the verification of the transparent inputs and outputs into a separate method. * Refactor transparent checks to use `call_all` Instead of pushing the verifications into a stream of unordered futures, use the `ServiceExt::call_all` method to build an equivalent stream after building a stream of requests. * Replace `CallAll` with `FuturesUnordered` Make it more consistent with the rest of the code, and make sure that the `len()` method is available to use for tracing. Co-authored-by: teor <teor@riseup.net> * Refactor to move wait for checks into a new method Allow the code snipped to be reused by other transaction version-specific check methods. * Verify transparent inputs in V5 transactions Use the script verifier to check the transparent inputs in a V5 transaction. * Check `has_inputs_and_outputs` for all versions Check if a transaction has inputs and outputs, independently of the transaction version. * Wait for checks in `call` method Refactor to move the repeated code into the `call` method. Now the validation methods return the set of asynchronous checks to wait for. * Add helper function to mock transparent transfers Creates a fake source UTXO, and then the input and output that represent spending that UTXO. The initial UTXO can be configured to have a script that either accepts or rejects any spend attempt. * Test if transparent V4 transaction is accepted Create a fake V4 transaction that includes a fake transparent transfer of funds. The transfer uses a script to allow any UTXO to spend it. * Test transaction V4 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Test if transparent V5 transaction is accepted Create a mock V5 transaction that includes a transparent transfer of funds. The transaction should be accepted by the verifier. * Test transaction V5 rejection based on script Create a fake transparent transfer where the source UTXO has a script that rejects spending. The script verifier should not accept this transaction. * Update `Request::upgrade` getter documentation Simplify it so that it won't become updated when #1683 is fixed. Co-authored-by: teor <teor@riseup.net>
2021-06-22 18:54:00 -07:00
/// Verifies if a transaction's transparent `inputs` are valid using the provided
/// `script_verifier`.
fn verify_transparent_inputs_and_outputs(
request: &Request,
network: Network,
inputs: &[transparent::Input],
script_verifier: script::Verifier<ZS>,
) -> Result<AsyncChecks, TransactionError> {
let transaction = request.transaction();
if transaction.is_coinbase() {
check::coinbase_tx_no_prevout_joinsplit_spend(&transaction)?;
Ok(AsyncChecks::new())
} else {
// feed all of the inputs to the script and shielded verifiers
// the script_verifier also checks transparent sighashes, using its own implementation
let cached_ffi_transaction = Arc::new(CachedFfiTransaction::new(transaction));
let known_utxos = request.known_utxos();
let upgrade = request.upgrade(network);
let script_checks = (0..inputs.len())
.into_iter()
.map(move |input_index| {
let request = script::Request {
upgrade,
known_utxos: known_utxos.clone(),
cached_ffi_transaction: cached_ffi_transaction.clone(),
input_index,
};
script_verifier.clone().oneshot(request).boxed()
})
.collect();
Ok(script_checks)
}
}
/// Await a set of checks that should all succeed.
///
/// If any of the checks fail, this method immediately returns the error and cancels all other
/// checks by dropping them.
async fn wait_for_checks(mut checks: AsyncChecks) -> Result<(), TransactionError> {
// Wait for all asynchronous checks to complete
// successfully, or fail verification if they error.
while let Some(check) = checks.next().await {
tracing::trace!(?check, remaining = checks.len());
check?;
}
Ok(())
}
Reject V5 transactions before NU5 activation (#2285) * Add a `Transaction::version` getter Returns the version of the transaction as a `u32`. * Add `Transaction::is_overwintered` helper method Returns if the `fOverwintered` flag should be set for the transaction's version. * Use new helpers to serialize transaction version Reduce the repeated code and make it less error-prone with future changes. * Add getter methods to `transaction::Request` type Refactor to move the type deconstruction code into the `Request` type. The main objective is to make it easier to split the call handler into methods that receive the request directly. * Refactor to create `verify_v4_transaction` helper Split the code specific to V4 transactions into a separate helper method. * Create `verify_v5_transaction` helper method Prepare a separate method to have the validation code. * Add `UnsupportedByNetworkUpgrade` error variant An error for when a transaction's version isn't supported by the network upgrade of the block it's included or for the current network upgrade if the transaction is for the mempool. * Verify a V5 transaction's network upgrade For now, only NU5 supports V5 transactions. * Test that V5 transaction is rejected on Canopy Create a fake V5 transaction and try to verify it using a block height from Canopy's activation. The verifier should reject the transaction with an error saying that the network upgrade does not support that transaction version. * Test if V5 tx. is accepted after NU5 activation Create a fake V5 transaction and pretend it is placed in a block that has a height after the NU5 activation. The test should succeed, but since the NU5 activation height has not been specified yet (neither for the testnet nor the mainnet), for now this test is marked as `should_panic`. * Add `TODO` comment to the code Add more detail to what's left to do, and link to the appropriate PRs. * Use `u32` to store transaction version Use a type consistent with how the version is specified. Co-authored-by: teor <teor@riseup.net> Co-authored-by: teor <teor@riseup.net>
2021-06-14 17:15:59 -07:00
}