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::{ use zebra_chain::{
block::{self, Block}, block::{self, Block},
parameters::Network, parameters::Network,
parameters::NetworkUpgrade,
transparent, transparent,
work::equihash, work::equihash,
}; };
@ -83,9 +82,8 @@ where
S::Future: Send + 'static, S::Future: Send + 'static,
{ {
pub fn new(network: Network, state_service: S) -> Self { pub fn new(network: Network, state_service: S) -> Self {
let branch = NetworkUpgrade::Sapling.branch_id().unwrap(); let transaction_verifier =
let script_verifier = script::Verifier::new(state_service.clone(), branch); transaction::Verifier::new(network, script::Verifier::new(state_service.clone()));
let transaction_verifier = transaction::Verifier::new(script_verifier);
Self { Self {
network, network,
@ -176,6 +174,7 @@ where
.call(transaction::Request::Block { .call(transaction::Request::Block {
transaction: transaction.clone(), transaction: transaction.clone(),
known_utxos: known_utxos.clone(), known_utxos: known_utxos.clone(),
height,
}); });
async_checks.push(rsp); async_checks.push(rsp);
} }

View File

@ -2,7 +2,7 @@ use std::{collections::HashMap, future::Future, pin::Pin, sync::Arc};
use tracing::Instrument; use tracing::Instrument;
use zebra_chain::{parameters::ConsensusBranchId, transaction::Transaction, transparent}; use zebra_chain::{parameters::NetworkUpgrade, transaction::Transaction, transparent};
use zebra_state::Utxo; use zebra_state::Utxo;
use crate::BoxError; use crate::BoxError;
@ -21,27 +21,34 @@ use crate::BoxError;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Verifier<ZS> { pub struct Verifier<ZS> {
state: ZS, state: ZS,
branch: ConsensusBranchId,
} }
impl<ZS> Verifier<ZS> { impl<ZS> Verifier<ZS> {
pub fn new(state: ZS, branch: ConsensusBranchId) -> Self { pub fn new(state: ZS) -> Self {
Self { state, branch } Self { state }
} }
} }
/// A script verification request. /// A script verification request.
/// #[derive(Debug)]
pub struct Request {
/// Ideally, this would supply only an `Outpoint` and the unlock script, /// Ideally, this would supply only an `Outpoint` and the unlock script,
/// rather than the entire `Transaction`, but we call a C++ /// rather than the entire `Transaction`, but we call a C++
/// implementation, and its FFI requires the entire transaction. /// implementation, and its FFI requires the entire transaction.
/// At some future point, we could investigate reducing the size of the ///
/// request. /// This causes quadratic script verification behavior, so
#[derive(Debug)] /// at some future point, we need to reform this data.
pub struct Request {
pub transaction: Arc<Transaction>, pub transaction: Arc<Transaction>,
pub input_index: usize, 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>>, 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> impl<ZS> tower::Service<Request> for Verifier<ZS>
@ -68,13 +75,16 @@ where
transaction, transaction,
input_index, input_index,
known_utxos, known_utxos,
upgrade,
} = req; } = req;
let input = &transaction.inputs()[input_index]; let input = &transaction.inputs()[input_index];
let branch_id = upgrade
.branch_id()
.expect("post-Sapling NUs have a consensus branch ID");
match input { match input {
transparent::Input::PrevOut { outpoint, .. } => { transparent::Input::PrevOut { outpoint, .. } => {
let outpoint = *outpoint; let outpoint = *outpoint;
let branch_id = self.branch;
let span = tracing::trace_span!("script", ?outpoint); let span = tracing::trace_span!("script", ?outpoint);
let query = let query =

View File

@ -14,7 +14,8 @@ use tower::{Service, ServiceExt};
use tracing::Instrument; use tracing::Instrument;
use zebra_chain::{ use zebra_chain::{
parameters::NetworkUpgrade, block,
parameters::{Network, NetworkUpgrade},
transaction::{self, HashType, Transaction}, transaction::{self, HashType, Transaction},
transparent, transparent,
}; };
@ -28,6 +29,7 @@ mod check;
/// Asynchronous transaction verification. /// Asynchronous transaction verification.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Verifier<ZS> { pub struct Verifier<ZS> {
network: Network,
script_verifier: script::Verifier<ZS>, script_verifier: script::Verifier<ZS>,
// spend_verifier: groth16::Verifier, // spend_verifier: groth16::Verifier,
// output_verifier: groth16::Verifier, // output_verifier: groth16::Verifier,
@ -40,8 +42,11 @@ where
ZS::Future: Send + 'static, ZS::Future: Send + 'static,
{ {
// XXX: how should this struct be constructed? // XXX: how should this struct be constructed?
pub fn new(script_verifier: script::Verifier<ZS>) -> Self { pub fn new(network: Network, script_verifier: script::Verifier<ZS>) -> Self {
Self { script_verifier } Self {
network,
script_verifier,
}
} }
} }
@ -54,15 +59,22 @@ where
pub enum Request { pub enum Request {
/// Verify the supplied transaction as part of a block. /// Verify the supplied transaction as part of a block.
Block { Block {
/// The transaction itself.
transaction: Arc<Transaction>, transaction: Arc<Transaction>,
/// Additional UTXOs which are known at the time of verification. /// Additional UTXOs which are known at the time of verification.
known_utxos: Arc<HashMap<transparent::OutPoint, zs::Utxo>>, 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. /// Verify the supplied transaction as part of the mempool.
Mempool { Mempool {
/// The transaction itself.
transaction: Arc<Transaction>, transaction: Arc<Transaction>,
/// Additional UTXOs which are known at the time of verification. /// Additional UTXOs which are known at the time of verification.
known_utxos: Arc<HashMap<transparent::OutPoint, zs::Utxo>>, 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!(); unimplemented!();
} }
let (tx, known_utxos) = match req { let (tx, known_utxos, upgrade) = match req {
Request::Block { Request::Block {
transaction, transaction,
known_utxos, known_utxos,
} => (transaction, known_utxos), height,
} => {
let upgrade = NetworkUpgrade::current(self.network, height);
(transaction, known_utxos, upgrade)
}
Request::Mempool { Request::Mempool {
transaction, transaction,
known_utxos, known_utxos,
} => (transaction, known_utxos), upgrade,
} => (transaction, known_utxos, upgrade),
}; };
let mut redjubjub_verifier = crate::primitives::redjubjub::VERIFIER.clone(); let mut redjubjub_verifier = crate::primitives::redjubjub::VERIFIER.clone();
@ -135,6 +152,7 @@ where
// feed all of the inputs to the script verifier // feed all of the inputs to the script verifier
for input_index in 0..inputs.len() { for input_index in 0..inputs.len() {
let rsp = script_verifier.ready_and().await?.call(script::Request { let rsp = script_verifier.ready_and().await?.call(script::Request {
upgrade,
known_utxos: known_utxos.clone(), known_utxos: known_utxos.clone(),
transaction: tx.clone(), transaction: tx.clone(),
input_index, input_index,
@ -146,8 +164,9 @@ where
check::has_inputs_and_outputs(&tx)?; check::has_inputs_and_outputs(&tx)?;
// TODO: rework this code
let sighash = tx.sighash( let sighash = tx.sighash(
NetworkUpgrade::Sapling, // TODO: pass this in upgrade,
HashType::ALL, // TODO: check these HashType::ALL, // TODO: check these
None, // TODO: check these None, // TODO: check these
); );