ZIP-213: Explain how Zebra validates shielded coinbase outputs like other shielded outputs (#2382)
* Describe how a ZIP-213 rule is implemented in the transaction verifier * Move the only coinbase-specific check outside the ZIP-213 block This change isn't required to implement the ZIP-213 rule, but it makes it easier to identify the specific checks for coinbase transactions. * Add a note about coinbase in the mempool Co-authored-by: Deirdre Connolly <durumcrustulum@gmail.com>
This commit is contained in:
parent
22f2f06bad
commit
df7075e962
|
@ -87,6 +87,8 @@ pub enum Request {
|
||||||
height: block::Height,
|
height: block::Height,
|
||||||
},
|
},
|
||||||
/// Verify the supplied transaction as part of the mempool.
|
/// Verify the supplied transaction as part of the mempool.
|
||||||
|
///
|
||||||
|
/// Note: coinbase transactions are invalid in the mempool
|
||||||
Mempool {
|
Mempool {
|
||||||
/// The transaction itself.
|
/// The transaction itself.
|
||||||
transaction: Arc<Transaction>,
|
transaction: Arc<Transaction>,
|
||||||
|
@ -163,6 +165,19 @@ where
|
||||||
// Do basic checks first
|
// Do basic checks first
|
||||||
check::has_inputs_and_outputs(&tx)?;
|
check::has_inputs_and_outputs(&tx)?;
|
||||||
|
|
||||||
|
if tx.is_coinbase() {
|
||||||
|
check::coinbase_tx_no_prevout_joinsplit_spend(&tx)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// "The consensus rules applied to valueBalance, vShieldedOutput, and bindingSig
|
||||||
|
// in non-coinbase transactions MUST also be applied to coinbase transactions."
|
||||||
|
//
|
||||||
|
// This rule is implicitly implemented during Sapling and Orchard verification,
|
||||||
|
// because they do not distinguish between coinbase and non-coinbase transactions.
|
||||||
|
//
|
||||||
|
// Note: this rule originally applied to Sapling, but we assume it also applies to Orchard.
|
||||||
|
//
|
||||||
|
// https://zips.z.cash/zip-0213#specification
|
||||||
let async_checks = match tx.as_ref() {
|
let async_checks = match tx.as_ref() {
|
||||||
Transaction::V1 { .. } | Transaction::V2 { .. } | Transaction::V3 { .. } => {
|
Transaction::V1 { .. } | Transaction::V2 { .. } | Transaction::V3 { .. } => {
|
||||||
tracing::debug!(?tx, "got transaction with wrong version");
|
tracing::debug!(?tx, "got transaction with wrong version");
|
||||||
|
@ -460,11 +475,6 @@ where
|
||||||
) -> Result<AsyncChecks, TransactionError> {
|
) -> Result<AsyncChecks, TransactionError> {
|
||||||
let transaction = request.transaction();
|
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
|
// feed all of the inputs to the script and shielded verifiers
|
||||||
// the script_verifier also checks transparent sighashes, using its own implementation
|
// the script_verifier also checks transparent sighashes, using its own implementation
|
||||||
let cached_ffi_transaction = Arc::new(CachedFfiTransaction::new(transaction));
|
let cached_ffi_transaction = Arc::new(CachedFfiTransaction::new(transaction));
|
||||||
|
@ -487,7 +497,6 @@ where
|
||||||
|
|
||||||
Ok(script_checks)
|
Ok(script_checks)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Await a set of checks that should all succeed.
|
/// Await a set of checks that should all succeed.
|
||||||
///
|
///
|
||||||
|
|
Loading…
Reference in New Issue