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:
Henry de Valence 2020-11-24 12:30:58 -08:00 committed by teor
parent 2e0ed94b22
commit 61b3286085
3 changed files with 52 additions and 24 deletions

View File

@ -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);
}

View File

@ -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 =

View File

@ -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 {