From 9f9e3a53338c1087f00c1b5690cdb769752bd4f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BF=97=E5=AE=87?= Date: Sun, 17 May 2026 08:03:01 +0000 Subject: [PATCH] 12.x: plan: add Plan::tap_sighash_default accessor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backport of #949 (target: release-13.x) to the 12.x line. Exposes the existing per-Schnorr-placeholder size assumption — recorded when the plan was built from `TaprootCanSign::sighash_default` — as a single `Option` on the Plan. Callers constructing a PSBT can use this to populate `PSBT_IN_SIGHASH_TYPE` consistently with the witness-size assumption baked into `Plan::satisfaction_weight`. --- src/plan.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/plan.rs b/src/plan.rs index 4c4dca9db..74cef2619 100644 --- a/src/plan.rs +++ b/src/plan.rs @@ -240,6 +240,44 @@ impl Plan { /// the script sig weight and the witness weight) pub fn satisfaction_weight(&self) -> usize { self.witness_size() + self.scriptsig_size() * 4 } + /// Returns whether the witness was sized assuming `SIGHASH_DEFAULT` — the 64-byte + /// Taproot signature encoding. + /// + /// * `Some(true)` — every Schnorr placeholder in this plan is sized for a 64-byte + /// signature; the witness assumes `SIGHASH_DEFAULT`. + /// * `Some(false)` — every Schnorr placeholder is sized for a 65-byte signature; + /// the witness assumes any non-Default Taproot sighash flag. + /// * `None` — this plan has no Schnorr placeholders (e.g. non-Taproot plans, where + /// signature size is invariant under the sighash flag), or its Schnorr placeholders + /// have differing sizes — a mixed plan that cannot be expressed by a single uniform + /// sighash policy per BIP-174. + /// + /// This mirrors the `sighash_default` flag recorded on each + /// [`TaprootCanSign`] when the plan was built. Callers constructing a PSBT + /// can use this to populate `PSBT_IN_SIGHASH_TYPE` consistently with the + /// witness-size assumption baked into [`Plan::satisfaction_weight`]. + pub fn tap_sighash_default(&self) -> Option { + let mut acc: Option = None; + for placeholder in &self.template { + let size = match placeholder { + Placeholder::SchnorrSigPk(_, _, size) => *size, + Placeholder::SchnorrSigPkHash(_, _, size) => *size, + _ => continue, + }; + let is_default = match size { + 64 => true, + 65 => false, + _ => return None, + }; + match acc { + None => acc = Some(is_default), + Some(prev) if prev != is_default => return None, + _ => {} + } + } + acc + } + /// The size in bytes of the script sig that satisfies this plan pub fn scriptsig_size(&self) -> usize { match (self.descriptor.desc_type().segwit_version(), self.descriptor.desc_type()) {