Merge #148: descriptors: add a method to get the size of a spending input
eebc96c4d53f0f6a86d5ddf4267b3d4a45aa7e3f descriptors: add a method to get the size of a spending input (Antoine Poinsot)
Pull request description:
ACKs for top commit:
edouardparis:
utACK eebc96c4d53f0f6a86d5ddf4267b3d4a45aa7e3f
Tree-SHA512: 6d94d7eccfed1d828633f7942072c7b044339c1df7add1df209bba6409131aa138f8cf83a36691df88af237943dcc45c3b1e050745143ab663a6c9c13c83176a
This commit is contained in:
commit
38e342c8cd
@ -17,6 +17,15 @@ use std::{collections::BTreeMap, convert::TryFrom, error, fmt, str, sync};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
const WITNESS_FACTOR: usize = 4;
|
||||
|
||||
// Convert a size in weight units to a size in virtual bytes, rounding up.
|
||||
fn wu_to_vb(vb: usize) -> usize {
|
||||
(vb + WITNESS_FACTOR - 1)
|
||||
.checked_div(WITNESS_FACTOR)
|
||||
.expect("Non 0")
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DescCreationError {
|
||||
InsaneTimelock(u32),
|
||||
@ -504,6 +513,20 @@ impl InheritanceDescriptor {
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/// Get the maximum size in WU of a satisfaction for this descriptor.
|
||||
pub fn max_sat_weight(&self) -> usize {
|
||||
self.0
|
||||
.max_satisfaction_weight()
|
||||
.expect("Cannot fail for P2WSH")
|
||||
}
|
||||
|
||||
/// Get the maximum size in virtual bytes of the whole input in a transaction spending
|
||||
/// a coin with this Script.
|
||||
pub fn spender_input_size(&self) -> usize {
|
||||
// txid + vout + nSequence + empty scriptSig + witness
|
||||
32 + 4 + 4 + 1 + wu_to_vb(self.max_sat_weight())
|
||||
}
|
||||
}
|
||||
|
||||
/// Map of a raw public key to the xpub used to derive it and its derivation path
|
||||
@ -620,5 +643,47 @@ mod tests {
|
||||
assert_eq!(desc.timelock_value(), 0xffff);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inheritance_descriptor_sat_size() {
|
||||
let secp = secp256k1::Secp256k1::verification_only();
|
||||
let desc = MultipathDescriptor::from_str("wsh(or_d(pk([92162c45]tpubD6NzVbkrYhZ4WzTf9SsD6h7AH7oQEippXK2KP8qvhMMqFoNeN5YFVi7vRyeRSDGtgd2bPyMxUNmHui8t5yCgszxPPxMafu1VVzDpg9aruYW/<0;1>/*),and_v(v:pkh(tpubD6NzVbkrYhZ4Wdgu2yfdmrce5g4fiH1ZLmKhewsnNKupbi4sxjH1ZVAorkBLWSkhsjhg8kiq8C4BrBjMy3SjAKDyDdbuvUa1ToAHbiR98js/<0;1>/*),older(2))))#uact7s3g").unwrap();
|
||||
let receive_desc = desc.receive_descriptor();
|
||||
let change_desc = desc.change_descriptor();
|
||||
|
||||
// Receive and change are the same descriptor.
|
||||
assert_eq!(receive_desc.max_sat_weight(), change_desc.max_sat_weight());
|
||||
assert_eq!(
|
||||
receive_desc.spender_input_size(),
|
||||
change_desc.spender_input_size()
|
||||
);
|
||||
|
||||
// Derived or not the expected maximum satisfaction size should be the same for
|
||||
// the same descriptor.
|
||||
assert_eq!(
|
||||
receive_desc.derive(999.into(), &secp).max_sat_weight(),
|
||||
change_desc.derive(999.into(), &secp).max_sat_weight()
|
||||
);
|
||||
|
||||
// Maximum input size is (txid + vout + scriptsig + nSequence + max_sat).
|
||||
// Where max_sat is:
|
||||
// - Push the witness stack size
|
||||
// - Push the script
|
||||
// - Push an empty vector for using the recovery path
|
||||
// - Push the recovery key
|
||||
// - Push a signature for the recovery key
|
||||
// NOTE: The specific value is asserted because this was tested against a regtest
|
||||
// transaction.
|
||||
let stack = vec![vec![0; 68], vec![0; 0], vec![0; 33], vec![0; 72]];
|
||||
let witness_size = bitcoin::VarInt(stack.len() as u64).len()
|
||||
+ stack
|
||||
.iter()
|
||||
.map(|item| bitcoin::VarInt(stack.len() as u64).len() + item.len())
|
||||
.sum::<usize>();
|
||||
assert_eq!(
|
||||
receive_desc.spender_input_size(),
|
||||
32 + 4 + 1 + 4 + wu_to_vb(witness_size),
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: test error conditions of deserialization.
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user