consensus: add NU plumbing to block,tx,script verifiers
Closes #1367 by propagating the network upgrade through the service requests.
This commit is contained in:
parent
2e0ed94b22
commit
61b3286085
|
@ -25,7 +25,6 @@ use tracing::Instrument;
|
|||
use zebra_chain::{
|
||||
block::{self, Block},
|
||||
parameters::Network,
|
||||
parameters::NetworkUpgrade,
|
||||
transparent,
|
||||
work::equihash,
|
||||
};
|
||||
|
@ -83,9 +82,8 @@ where
|
|||
S::Future: Send + 'static,
|
||||
{
|
||||
pub fn new(network: Network, state_service: S) -> Self {
|
||||
let branch = NetworkUpgrade::Sapling.branch_id().unwrap();
|
||||
let script_verifier = script::Verifier::new(state_service.clone(), branch);
|
||||
let transaction_verifier = transaction::Verifier::new(script_verifier);
|
||||
let transaction_verifier =
|
||||
transaction::Verifier::new(network, script::Verifier::new(state_service.clone()));
|
||||
|
||||
Self {
|
||||
network,
|
||||
|
@ -176,6 +174,7 @@ where
|
|||
.call(transaction::Request::Block {
|
||||
transaction: transaction.clone(),
|
||||
known_utxos: known_utxos.clone(),
|
||||
height,
|
||||
});
|
||||
async_checks.push(rsp);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::{collections::HashMap, future::Future, pin::Pin, sync::Arc};
|
|||
|
||||
use tracing::Instrument;
|
||||
|
||||
use zebra_chain::{parameters::ConsensusBranchId, transaction::Transaction, transparent};
|
||||
use zebra_chain::{parameters::NetworkUpgrade, transaction::Transaction, transparent};
|
||||
use zebra_state::Utxo;
|
||||
|
||||
use crate::BoxError;
|
||||
|
@ -21,27 +21,34 @@ use crate::BoxError;
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct Verifier<ZS> {
|
||||
state: ZS,
|
||||
branch: ConsensusBranchId,
|
||||
}
|
||||
|
||||
impl<ZS> Verifier<ZS> {
|
||||
pub fn new(state: ZS, branch: ConsensusBranchId) -> Self {
|
||||
Self { state, branch }
|
||||
pub fn new(state: ZS) -> Self {
|
||||
Self { state }
|
||||
}
|
||||
}
|
||||
|
||||
/// A script verification request.
|
||||
///
|
||||
/// Ideally, this would supply only an `Outpoint` and the unlock script,
|
||||
/// rather than the entire `Transaction`, but we call a C++
|
||||
/// implementation, and its FFI requires the entire transaction.
|
||||
/// At some future point, we could investigate reducing the size of the
|
||||
/// request.
|
||||
#[derive(Debug)]
|
||||
pub struct Request {
|
||||
/// Ideally, this would supply only an `Outpoint` and the unlock script,
|
||||
/// rather than the entire `Transaction`, but we call a C++
|
||||
/// implementation, and its FFI requires the entire transaction.
|
||||
///
|
||||
/// This causes quadratic script verification behavior, so
|
||||
/// at some future point, we need to reform this data.
|
||||
pub transaction: Arc<Transaction>,
|
||||
pub input_index: usize,
|
||||
/// A set of additional UTXOs known in the context of this verification request.
|
||||
///
|
||||
/// This allows specifying additional UTXOs that are not already known to the chain state.
|
||||
pub known_utxos: Arc<HashMap<transparent::OutPoint, Utxo>>,
|
||||
/// The network upgrade active in the context of this verification request.
|
||||
///
|
||||
/// Because the consensus branch ID changes with each network upgrade,
|
||||
/// it has to be specified on a per-request basis.
|
||||
pub upgrade: NetworkUpgrade,
|
||||
}
|
||||
|
||||
impl<ZS> tower::Service<Request> for Verifier<ZS>
|
||||
|
@ -68,13 +75,16 @@ where
|
|||
transaction,
|
||||
input_index,
|
||||
known_utxos,
|
||||
upgrade,
|
||||
} = req;
|
||||
let input = &transaction.inputs()[input_index];
|
||||
let branch_id = upgrade
|
||||
.branch_id()
|
||||
.expect("post-Sapling NUs have a consensus branch ID");
|
||||
|
||||
match input {
|
||||
transparent::Input::PrevOut { outpoint, .. } => {
|
||||
let outpoint = *outpoint;
|
||||
let branch_id = self.branch;
|
||||
|
||||
let span = tracing::trace_span!("script", ?outpoint);
|
||||
let query =
|
||||
|
|
|
@ -14,7 +14,8 @@ use tower::{Service, ServiceExt};
|
|||
use tracing::Instrument;
|
||||
|
||||
use zebra_chain::{
|
||||
parameters::NetworkUpgrade,
|
||||
block,
|
||||
parameters::{Network, NetworkUpgrade},
|
||||
transaction::{self, HashType, Transaction},
|
||||
transparent,
|
||||
};
|
||||
|
@ -28,6 +29,7 @@ mod check;
|
|||
/// Asynchronous transaction verification.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Verifier<ZS> {
|
||||
network: Network,
|
||||
script_verifier: script::Verifier<ZS>,
|
||||
// spend_verifier: groth16::Verifier,
|
||||
// output_verifier: groth16::Verifier,
|
||||
|
@ -40,8 +42,11 @@ where
|
|||
ZS::Future: Send + 'static,
|
||||
{
|
||||
// XXX: how should this struct be constructed?
|
||||
pub fn new(script_verifier: script::Verifier<ZS>) -> Self {
|
||||
Self { script_verifier }
|
||||
pub fn new(network: Network, script_verifier: script::Verifier<ZS>) -> Self {
|
||||
Self {
|
||||
network,
|
||||
script_verifier,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,15 +59,22 @@ where
|
|||
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>>,
|
||||
/// The active NU in the context of this verification.
|
||||
upgrade: NetworkUpgrade,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -91,15 +103,20 @@ where
|
|||
unimplemented!();
|
||||
}
|
||||
|
||||
let (tx, known_utxos) = match req {
|
||||
let (tx, known_utxos, upgrade) = match req {
|
||||
Request::Block {
|
||||
transaction,
|
||||
known_utxos,
|
||||
} => (transaction, known_utxos),
|
||||
height,
|
||||
} => {
|
||||
let upgrade = NetworkUpgrade::current(self.network, height);
|
||||
(transaction, known_utxos, upgrade)
|
||||
}
|
||||
Request::Mempool {
|
||||
transaction,
|
||||
known_utxos,
|
||||
} => (transaction, known_utxos),
|
||||
upgrade,
|
||||
} => (transaction, known_utxos, upgrade),
|
||||
};
|
||||
|
||||
let mut redjubjub_verifier = crate::primitives::redjubjub::VERIFIER.clone();
|
||||
|
@ -135,6 +152,7 @@ where
|
|||
// feed all of the inputs to the script verifier
|
||||
for input_index in 0..inputs.len() {
|
||||
let rsp = script_verifier.ready_and().await?.call(script::Request {
|
||||
upgrade,
|
||||
known_utxos: known_utxos.clone(),
|
||||
transaction: tx.clone(),
|
||||
input_index,
|
||||
|
@ -146,10 +164,11 @@ where
|
|||
|
||||
check::has_inputs_and_outputs(&tx)?;
|
||||
|
||||
// TODO: rework this code
|
||||
let sighash = tx.sighash(
|
||||
NetworkUpgrade::Sapling, // TODO: pass this in
|
||||
HashType::ALL, // TODO: check these
|
||||
None, // TODO: check these
|
||||
upgrade,
|
||||
HashType::ALL, // TODO: check these
|
||||
None, // TODO: check these
|
||||
);
|
||||
|
||||
if let Some(joinsplit_data) = joinsplit_data {
|
||||
|
|
Loading…
Reference in New Issue