diff --git a/zebra-consensus/src/transaction.rs b/zebra-consensus/src/transaction.rs index c13b9e66516..c9bf3030e94 100644 --- a/zebra-consensus/src/transaction.rs +++ b/zebra-consensus/src/transaction.rs @@ -909,26 +909,26 @@ where let mut async_checks = AsyncChecks::new(); if let Some(orchard_shielded_data) = orchard_shielded_data { + // # Consensus + // + // > The proof 𝜋 MUST be valid given a primary input (cv, rt^{Orchard}, + // > nf, rk, cm_x, enableSpends, enableOutputs) + // + // https://zips.z.cash/protocol/protocol.pdf#actiondesc + // + // Unlike Sapling, Orchard shielded transactions have a single + // aggregated Halo2 proof per transaction, even with multiple + // Actions in one transaction. So we queue it for verification + // only once instead of queuing it up for every Action description. + async_checks.push( + primitives::halo2::VERIFIER + .clone() + .oneshot(primitives::halo2::Item::from(orchard_shielded_data)), + ); + for authorized_action in orchard_shielded_data.actions.iter().cloned() { let (action, spend_auth_sig) = authorized_action.into_parts(); - // # Consensus - // - // > The proof 𝜋 MUST be valid given a primary input (cv, rt^{Orchard}, - // > nf, rk, cm_x, enableSpends, enableOutputs) - // - // https://zips.z.cash/protocol/protocol.pdf#actiondesc - // - // Queue the verification of the Halo2 proof for each Action - // description while adding the resulting future to our - // collection of async checks that (at a minimum) must pass for - // the transaction to verify. - async_checks.push( - primitives::halo2::VERIFIER - .clone() - .oneshot(primitives::halo2::Item::from(orchard_shielded_data)), - ); - // # Consensus // // > - Let SigHash be the SIGHASH transaction hash of this transaction, not