From 3eb648df01e5d144b034fc5733522aef77494448 Mon Sep 17 00:00:00 2001 From: Martin Habovstiak Date: Sat, 4 Mar 2023 19:11:08 +0100 Subject: [PATCH] Add constants to `InputWeightPrediction` There are several common spends in Bitcoin that have known input weight predictions. It can be useful to have these as constants, so this change adds them. However, this only adds native segwit ones as the others are slowly fading away and might clutter the API. --- bitcoin/src/blockdata/transaction.rs | 52 ++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 792906c5..5d3af10b 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -1277,6 +1277,58 @@ pub struct InputWeightPrediction { } impl InputWeightPrediction { + /// Input weight prediction corresponding to spending of P2WPKH output with the largest possible + /// DER-encoded signature. + /// + /// If the input in your transaction uses P2WPKH you can use this instead of + /// [`InputWeightPrediction::new`]. + /// + /// This is useful when you **do not** use [signature grinding] and want to ensure you are not + /// under-paying. See [`ground_p2wpkh`](Self::ground_p2wpkh) if you do use signature grinding. + /// + /// [signature grinding]: https://bitcoin.stackexchange.com/questions/111660/what-is-signature-grinding + pub const P2WPKH_MAX: Self = InputWeightPrediction { script_size: 0, witness_size: 1 + 1 + 73 + 1 + 33 }; + + /// Input weight prediction corresponding to spending of taproot output using the key and + /// default sighash. + /// + /// If the input in your transaction uses Taproot key spend you can use this instead of + /// [`InputWeightPrediction::new`]. + pub const P2TR_KEY_DEFAULT_SIGHASH: Self = InputWeightPrediction { script_size: 0, witness_size: 1 + 1 + 64 }; + + /// Input weight prediction corresponding to spending of taproot output using the key and + /// **non**-default sighash. + /// + /// If the input in your transaction uses Taproot key spend you can use this instead of + /// [`InputWeightPrediction::new`]. + pub const P2TR_KEY_NON_DEFAULT_SIGHASH: Self = InputWeightPrediction { script_size: 0, witness_size: 1 + 1 + 65 }; + + /// Input weight prediction corresponding to spending of P2WPKH output using [signature + /// grinding]. + /// + /// If the input in your transaction uses P2WPKH and you use signature grinding you can use this + /// instead of [`InputWeightPrediction::new`]. See [`P2WPKH_MAX`](Self::P2WPKH_MAX) if you don't + /// use signature grinding. + /// + /// Note: `bytes_to_grind` is usually `1` because of exponential cost of higher values. + /// + /// # Panics + /// + /// The funcion panics in const context and debug builds if `bytes_to_grind` is higher than 62. + /// + /// [signature grinding]: https://bitcoin.stackexchange.com/questions/111660/what-is-signature-grinding + pub const fn ground_p2wpkh(bytes_to_grind: usize) -> Self { + // Written to trigger const/debug panic for unreasonably high values. + let der_signature_size = 10 + (62 - bytes_to_grind); + let witness_size = 1 // length of element count varint + + 1 // length of element size varint (max signature length is 73B) + + der_signature_size + + 1 // sighash flag + + 1 // length of element size varint + + 33; // length of (always-compressed) public key + InputWeightPrediction { script_size: 0, witness_size } + } + /// Computes the prediction for a single input. pub fn new(input_script_len: usize, witness_element_lengths: T) -> Self where T :IntoIterator, T::Item:Borrow,