fix: rm duplicate bdk_tmp_plan
module
This commit is contained in:
parent
af705da1a8
commit
315e7e0b4b
@ -1,13 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "bdk_tmp_plan"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
bdk_chain = { path = "../../../crates/chain", version = "0.3.1", features = ["miniscript"] }
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["std"]
|
|
||||||
std = []
|
|
@ -1,3 +0,0 @@
|
|||||||
# Temporary planning module
|
|
||||||
|
|
||||||
A temporary place to hold the planning module until https://github.com/rust-bitcoin/rust-miniscript/pull/481 is merged and released
|
|
@ -1,436 +0,0 @@
|
|||||||
#![allow(unused)]
|
|
||||||
#![allow(missing_docs)]
|
|
||||||
//! A spending plan or *plan* for short is a representation of a particular spending path on a
|
|
||||||
//! descriptor. This allows us to analayze a choice of spending path without producing any
|
|
||||||
//! signatures or other witness data for it.
|
|
||||||
//!
|
|
||||||
//! To make a plan you provide the descriptor with "assets" like which keys you are able to use, hash
|
|
||||||
//! pre-images you have access to, the current block height etc.
|
|
||||||
//!
|
|
||||||
//! Once you've got a plan it can tell you its expected satisfaction weight which can be useful for
|
|
||||||
//! doing coin selection. Furthermore it provides which subset of those keys and hash pre-images you
|
|
||||||
//! will actually need as well as what locktime or sequence number you need to set.
|
|
||||||
//!
|
|
||||||
//! Once you've obstained signatures, hash pre-images etc required by the plan, it can create a
|
|
||||||
//! witness/script_sig for the input.
|
|
||||||
use bdk_chain::{bitcoin, collections::*, miniscript};
|
|
||||||
use bitcoin::{
|
|
||||||
blockdata::{locktime::LockTime, transaction::Sequence},
|
|
||||||
hashes::{hash160, ripemd160, sha256},
|
|
||||||
secp256k1::Secp256k1,
|
|
||||||
util::{
|
|
||||||
address::WitnessVersion,
|
|
||||||
bip32::{DerivationPath, Fingerprint, KeySource},
|
|
||||||
taproot::{LeafVersion, TapBranchHash, TapLeafHash},
|
|
||||||
},
|
|
||||||
EcdsaSig, SchnorrSig, Script, TxIn, Witness,
|
|
||||||
};
|
|
||||||
use miniscript::{
|
|
||||||
descriptor::{InnerXKey, Tr},
|
|
||||||
hash256, DefiniteDescriptorKey, Descriptor, DescriptorPublicKey, ScriptContext, ToPublicKey,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub(crate) fn varint_len(v: usize) -> usize {
|
|
||||||
bitcoin::VarInt(v as u64).len() as usize
|
|
||||||
}
|
|
||||||
|
|
||||||
mod plan_impls;
|
|
||||||
mod requirements;
|
|
||||||
mod template;
|
|
||||||
pub use requirements::*;
|
|
||||||
pub use template::PlanKey;
|
|
||||||
use template::TemplateItem;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
enum TrSpend {
|
|
||||||
KeySpend,
|
|
||||||
LeafSpend {
|
|
||||||
script: Script,
|
|
||||||
leaf_version: LeafVersion,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
enum Target {
|
|
||||||
Legacy,
|
|
||||||
Segwitv0 {
|
|
||||||
script_code: Script,
|
|
||||||
},
|
|
||||||
Segwitv1 {
|
|
||||||
tr: Tr<DefiniteDescriptorKey>,
|
|
||||||
tr_plan: TrSpend,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Target {}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
/// A plan represents a particular spending path for a descriptor.
|
|
||||||
///
|
|
||||||
/// See the module level documentation for more info.
|
|
||||||
pub struct Plan<AK> {
|
|
||||||
template: Vec<TemplateItem<AK>>,
|
|
||||||
target: Target,
|
|
||||||
set_locktime: Option<LockTime>,
|
|
||||||
set_sequence: Option<Sequence>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Target {
|
|
||||||
fn default() -> Self {
|
|
||||||
Target::Legacy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
|
||||||
/// Signatures and hash pre-images that can be used to complete a plan.
|
|
||||||
pub struct SatisfactionMaterial {
|
|
||||||
/// Schnorr signautres under their keys
|
|
||||||
pub schnorr_sigs: BTreeMap<DefiniteDescriptorKey, SchnorrSig>,
|
|
||||||
/// ECDSA signatures under their keys
|
|
||||||
pub ecdsa_sigs: BTreeMap<DefiniteDescriptorKey, EcdsaSig>,
|
|
||||||
/// SHA256 pre-images under their images
|
|
||||||
pub sha256_preimages: BTreeMap<sha256::Hash, Vec<u8>>,
|
|
||||||
/// hash160 pre-images under their images
|
|
||||||
pub hash160_preimages: BTreeMap<hash160::Hash, Vec<u8>>,
|
|
||||||
/// hash256 pre-images under their images
|
|
||||||
pub hash256_preimages: BTreeMap<hash256::Hash, Vec<u8>>,
|
|
||||||
/// ripemd160 pre-images under their images
|
|
||||||
pub ripemd160_preimages: BTreeMap<ripemd160::Hash, Vec<u8>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Ak> Plan<Ak>
|
|
||||||
where
|
|
||||||
Ak: Clone,
|
|
||||||
{
|
|
||||||
/// The expected satisfaction weight for the plan if it is completed.
|
|
||||||
pub fn expected_weight(&self) -> usize {
|
|
||||||
let script_sig_size = match self.target {
|
|
||||||
Target::Legacy => unimplemented!(), // self
|
|
||||||
// .template
|
|
||||||
// .iter()
|
|
||||||
// .map(|step| {
|
|
||||||
// let size = step.expected_size();
|
|
||||||
// size + push_opcode_size(size)
|
|
||||||
// })
|
|
||||||
// .sum()
|
|
||||||
Target::Segwitv0 { .. } | Target::Segwitv1 { .. } => 1,
|
|
||||||
};
|
|
||||||
let witness_elem_sizes: Option<Vec<usize>> = match &self.target {
|
|
||||||
Target::Legacy => None,
|
|
||||||
Target::Segwitv0 { .. } => Some(
|
|
||||||
self.template
|
|
||||||
.iter()
|
|
||||||
.map(|step| step.expected_size())
|
|
||||||
.collect(),
|
|
||||||
),
|
|
||||||
Target::Segwitv1 { tr, tr_plan } => {
|
|
||||||
let mut witness_elems = self
|
|
||||||
.template
|
|
||||||
.iter()
|
|
||||||
.map(|step| step.expected_size())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
if let TrSpend::LeafSpend {
|
|
||||||
script,
|
|
||||||
leaf_version,
|
|
||||||
} = tr_plan
|
|
||||||
{
|
|
||||||
let control_block = tr
|
|
||||||
.spend_info()
|
|
||||||
.control_block(&(script.clone(), *leaf_version))
|
|
||||||
.expect("must exist");
|
|
||||||
witness_elems.push(script.len());
|
|
||||||
witness_elems.push(control_block.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(witness_elems)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let witness_size: usize = match witness_elem_sizes {
|
|
||||||
Some(elems) => {
|
|
||||||
varint_len(elems.len())
|
|
||||||
+ elems
|
|
||||||
.into_iter()
|
|
||||||
.map(|elem| varint_len(elem) + elem)
|
|
||||||
.sum::<usize>()
|
|
||||||
}
|
|
||||||
None => 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
script_sig_size * 4 + witness_size
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn requirements(&self) -> Requirements<Ak> {
|
|
||||||
match self.try_complete(&SatisfactionMaterial::default()) {
|
|
||||||
PlanState::Complete { .. } => Requirements::default(),
|
|
||||||
PlanState::Incomplete(requirements) => requirements,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_complete(&self, auth_data: &SatisfactionMaterial) -> PlanState<Ak> {
|
|
||||||
let unsatisfied_items = self
|
|
||||||
.template
|
|
||||||
.iter()
|
|
||||||
.filter(|step| match step {
|
|
||||||
TemplateItem::Sign(key) => {
|
|
||||||
!auth_data.schnorr_sigs.contains_key(&key.descriptor_key)
|
|
||||||
}
|
|
||||||
TemplateItem::Hash160(image) => !auth_data.hash160_preimages.contains_key(image),
|
|
||||||
TemplateItem::Hash256(image) => !auth_data.hash256_preimages.contains_key(image),
|
|
||||||
TemplateItem::Sha256(image) => !auth_data.sha256_preimages.contains_key(image),
|
|
||||||
TemplateItem::Ripemd160(image) => {
|
|
||||||
!auth_data.ripemd160_preimages.contains_key(image)
|
|
||||||
}
|
|
||||||
TemplateItem::Pk { .. } | TemplateItem::One | TemplateItem::Zero => false,
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
if unsatisfied_items.is_empty() {
|
|
||||||
let mut witness = self
|
|
||||||
.template
|
|
||||||
.iter()
|
|
||||||
.flat_map(|step| step.to_witness_stack(&auth_data))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
match &self.target {
|
|
||||||
Target::Segwitv0 { .. } => todo!(),
|
|
||||||
Target::Legacy => todo!(),
|
|
||||||
Target::Segwitv1 {
|
|
||||||
tr_plan: TrSpend::KeySpend,
|
|
||||||
..
|
|
||||||
} => PlanState::Complete {
|
|
||||||
final_script_sig: None,
|
|
||||||
final_script_witness: Some(Witness::from_vec(witness)),
|
|
||||||
},
|
|
||||||
Target::Segwitv1 {
|
|
||||||
tr,
|
|
||||||
tr_plan:
|
|
||||||
TrSpend::LeafSpend {
|
|
||||||
script,
|
|
||||||
leaf_version,
|
|
||||||
},
|
|
||||||
} => {
|
|
||||||
let spend_info = tr.spend_info();
|
|
||||||
let control_block = spend_info
|
|
||||||
.control_block(&(script.clone(), *leaf_version))
|
|
||||||
.expect("must exist");
|
|
||||||
witness.push(script.clone().into_bytes());
|
|
||||||
witness.push(control_block.serialize());
|
|
||||||
|
|
||||||
PlanState::Complete {
|
|
||||||
final_script_sig: None,
|
|
||||||
final_script_witness: Some(Witness::from_vec(witness)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let mut requirements = Requirements::default();
|
|
||||||
|
|
||||||
match &self.target {
|
|
||||||
Target::Legacy => {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
Target::Segwitv0 { .. } => {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
Target::Segwitv1 { tr, tr_plan } => {
|
|
||||||
let spend_info = tr.spend_info();
|
|
||||||
match tr_plan {
|
|
||||||
TrSpend::KeySpend => match &self.template[..] {
|
|
||||||
[TemplateItem::Sign(ref plan_key)] => {
|
|
||||||
requirements.signatures = RequiredSignatures::TapKey {
|
|
||||||
merkle_root: spend_info.merkle_root(),
|
|
||||||
plan_key: plan_key.clone(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
_ => unreachable!("tapkey spend will always have only one sign step"),
|
|
||||||
},
|
|
||||||
TrSpend::LeafSpend {
|
|
||||||
script,
|
|
||||||
leaf_version,
|
|
||||||
} => {
|
|
||||||
let leaf_hash = TapLeafHash::from_script(&script, *leaf_version);
|
|
||||||
requirements.signatures = RequiredSignatures::TapScript {
|
|
||||||
leaf_hash,
|
|
||||||
plan_keys: vec![],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let required_signatures = match requirements.signatures {
|
|
||||||
RequiredSignatures::Legacy { .. } => todo!(),
|
|
||||||
RequiredSignatures::Segwitv0 { .. } => todo!(),
|
|
||||||
RequiredSignatures::TapKey { .. } => return PlanState::Incomplete(requirements),
|
|
||||||
RequiredSignatures::TapScript {
|
|
||||||
plan_keys: ref mut keys,
|
|
||||||
..
|
|
||||||
} => keys,
|
|
||||||
};
|
|
||||||
|
|
||||||
for step in unsatisfied_items {
|
|
||||||
match step {
|
|
||||||
TemplateItem::Sign(plan_key) => {
|
|
||||||
required_signatures.push(plan_key.clone());
|
|
||||||
}
|
|
||||||
TemplateItem::Hash160(image) => {
|
|
||||||
requirements.hash160_images.insert(image.clone());
|
|
||||||
}
|
|
||||||
TemplateItem::Hash256(image) => {
|
|
||||||
requirements.hash256_images.insert(image.clone());
|
|
||||||
}
|
|
||||||
TemplateItem::Sha256(image) => {
|
|
||||||
requirements.sha256_images.insert(image.clone());
|
|
||||||
}
|
|
||||||
TemplateItem::Ripemd160(image) => {
|
|
||||||
requirements.ripemd160_images.insert(image.clone());
|
|
||||||
}
|
|
||||||
TemplateItem::Pk { .. } | TemplateItem::One | TemplateItem::Zero => { /* no requirements */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PlanState::Incomplete(requirements)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Witness version for the plan
|
|
||||||
pub fn witness_version(&self) -> Option<WitnessVersion> {
|
|
||||||
match self.target {
|
|
||||||
Target::Legacy => None,
|
|
||||||
Target::Segwitv0 { .. } => Some(WitnessVersion::V0),
|
|
||||||
Target::Segwitv1 { .. } => Some(WitnessVersion::V1),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The minimum required locktime height or time on the transaction using the plan.
|
|
||||||
pub fn required_locktime(&self) -> Option<LockTime> {
|
|
||||||
self.set_locktime.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The minimum required sequence (height or time) on the input to satisfy the plan
|
|
||||||
pub fn required_sequence(&self) -> Option<Sequence> {
|
|
||||||
self.set_sequence.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The minmum required transaction version required on the transaction using the plan.
|
|
||||||
pub fn min_version(&self) -> Option<u32> {
|
|
||||||
if let Some(_) = self.set_sequence {
|
|
||||||
Some(2)
|
|
||||||
} else {
|
|
||||||
Some(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The returned value from [`Plan::try_complete`].
|
|
||||||
pub enum PlanState<Ak> {
|
|
||||||
/// The plan is complete
|
|
||||||
Complete {
|
|
||||||
/// The script sig that should be set on the input
|
|
||||||
final_script_sig: Option<Script>,
|
|
||||||
/// The witness that should be set on the input
|
|
||||||
final_script_witness: Option<Witness>,
|
|
||||||
},
|
|
||||||
Incomplete(Requirements<Ak>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct Assets<K> {
|
|
||||||
pub keys: Vec<K>,
|
|
||||||
pub txo_age: Option<Sequence>,
|
|
||||||
pub max_locktime: Option<LockTime>,
|
|
||||||
pub sha256: Vec<sha256::Hash>,
|
|
||||||
pub hash256: Vec<hash256::Hash>,
|
|
||||||
pub ripemd160: Vec<ripemd160::Hash>,
|
|
||||||
pub hash160: Vec<hash160::Hash>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<K> Default for Assets<K> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
keys: Default::default(),
|
|
||||||
txo_age: Default::default(),
|
|
||||||
max_locktime: Default::default(),
|
|
||||||
sha256: Default::default(),
|
|
||||||
hash256: Default::default(),
|
|
||||||
ripemd160: Default::default(),
|
|
||||||
hash160: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait CanDerive {
|
|
||||||
fn can_derive(&self, key: &DefiniteDescriptorKey) -> Option<DerivationPath>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CanDerive for KeySource {
|
|
||||||
fn can_derive(&self, key: &DefiniteDescriptorKey) -> Option<DerivationPath> {
|
|
||||||
match DescriptorPublicKey::from(key.clone()) {
|
|
||||||
DescriptorPublicKey::Single(single_pub) => {
|
|
||||||
path_to_child(self, single_pub.origin.as_ref()?, None)
|
|
||||||
}
|
|
||||||
DescriptorPublicKey::XPub(dxk) => {
|
|
||||||
let origin = dxk.origin.clone().unwrap_or_else(|| {
|
|
||||||
let secp = Secp256k1::signing_only();
|
|
||||||
(dxk.xkey.xkey_fingerprint(&secp), DerivationPath::master())
|
|
||||||
});
|
|
||||||
|
|
||||||
path_to_child(self, &origin, Some(&dxk.derivation_path))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CanDerive for DescriptorPublicKey {
|
|
||||||
fn can_derive(&self, key: &DefiniteDescriptorKey) -> Option<DerivationPath> {
|
|
||||||
match (self, DescriptorPublicKey::from(key.clone())) {
|
|
||||||
(parent, child) if parent == &child => Some(DerivationPath::master()),
|
|
||||||
(DescriptorPublicKey::XPub(parent), _) => {
|
|
||||||
let origin = parent.origin.clone().unwrap_or_else(|| {
|
|
||||||
let secp = Secp256k1::signing_only();
|
|
||||||
(
|
|
||||||
parent.xkey.xkey_fingerprint(&secp),
|
|
||||||
DerivationPath::master(),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
KeySource::from(origin).can_derive(key)
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn path_to_child(
|
|
||||||
parent: &KeySource,
|
|
||||||
child_origin: &(Fingerprint, DerivationPath),
|
|
||||||
child_derivation: Option<&DerivationPath>,
|
|
||||||
) -> Option<DerivationPath> {
|
|
||||||
if parent.0 == child_origin.0 {
|
|
||||||
let mut remaining_derivation =
|
|
||||||
DerivationPath::from(child_origin.1[..].strip_prefix(&parent.1[..])?);
|
|
||||||
remaining_derivation =
|
|
||||||
remaining_derivation.extend(child_derivation.unwrap_or(&DerivationPath::master()));
|
|
||||||
Some(remaining_derivation)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn plan_satisfaction<Ak>(
|
|
||||||
desc: &Descriptor<DefiniteDescriptorKey>,
|
|
||||||
assets: &Assets<Ak>,
|
|
||||||
) -> Option<Plan<Ak>>
|
|
||||||
where
|
|
||||||
Ak: CanDerive + Clone,
|
|
||||||
{
|
|
||||||
match desc {
|
|
||||||
Descriptor::Bare(_) => todo!(),
|
|
||||||
Descriptor::Pkh(_) => todo!(),
|
|
||||||
Descriptor::Wpkh(_) => todo!(),
|
|
||||||
Descriptor::Sh(_) => todo!(),
|
|
||||||
Descriptor::Wsh(_) => todo!(),
|
|
||||||
Descriptor::Tr(tr) => crate::plan_impls::plan_satisfaction_tr(tr, assets),
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,323 +0,0 @@
|
|||||||
use bdk_chain::{bitcoin, miniscript};
|
|
||||||
use bitcoin::locktime::{Height, Time};
|
|
||||||
use miniscript::Terminal;
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
impl<Ak> TermPlan<Ak> {
|
|
||||||
fn combine(self, other: Self) -> Option<Self> {
|
|
||||||
let min_locktime = {
|
|
||||||
match (self.min_locktime, other.min_locktime) {
|
|
||||||
(Some(lhs), Some(rhs)) => {
|
|
||||||
if lhs.is_same_unit(rhs) {
|
|
||||||
Some(if lhs.to_consensus_u32() > rhs.to_consensus_u32() {
|
|
||||||
lhs
|
|
||||||
} else {
|
|
||||||
rhs
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => self.min_locktime.or(other.min_locktime),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let min_sequence = {
|
|
||||||
match (self.min_sequence, other.min_sequence) {
|
|
||||||
(Some(lhs), Some(rhs)) => {
|
|
||||||
if lhs.is_height_locked() == rhs.is_height_locked() {
|
|
||||||
Some(if lhs.to_consensus_u32() > rhs.to_consensus_u32() {
|
|
||||||
lhs
|
|
||||||
} else {
|
|
||||||
rhs
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => self.min_sequence.or(other.min_sequence),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut template = self.template;
|
|
||||||
template.extend(other.template);
|
|
||||||
|
|
||||||
Some(Self {
|
|
||||||
min_locktime,
|
|
||||||
min_sequence,
|
|
||||||
template,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn expected_size(&self) -> usize {
|
|
||||||
self.template.iter().map(|step| step.expected_size()).sum()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// impl crate::descriptor::Pkh<DefiniteDescriptorKey> {
|
|
||||||
// pub(crate) fn plan_satisfaction<Ak>(&self, assets: &Assets<Ak>) -> Option<Plan<Ak>>
|
|
||||||
// where
|
|
||||||
// Ak: CanDerive + Clone,
|
|
||||||
// {
|
|
||||||
// let (asset_key, derivation_hint) = assets.keys.iter().find_map(|asset_key| {
|
|
||||||
// let derivation_hint = asset_key.can_derive(self.as_inner())?;
|
|
||||||
// Some((asset_key, derivation_hint))
|
|
||||||
// })?;
|
|
||||||
|
|
||||||
// Some(Plan {
|
|
||||||
// template: vec![TemplateItem::Sign(PlanKey {
|
|
||||||
// asset_key: asset_key.clone(),
|
|
||||||
// descriptor_key: self.as_inner().clone(),
|
|
||||||
// derivation_hint,
|
|
||||||
// })],
|
|
||||||
// target: Target::Legacy,
|
|
||||||
// set_locktime: None,
|
|
||||||
// set_sequence: None,
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl crate::descriptor::Wpkh<DefiniteDescriptorKey> {
|
|
||||||
// pub(crate) fn plan_satisfaction<Ak>(&self, assets: &Assets<Ak>) -> Option<Plan<Ak>>
|
|
||||||
// where
|
|
||||||
// Ak: CanDerive + Clone,
|
|
||||||
// {
|
|
||||||
// let (asset_key, derivation_hint) = assets.keys.iter().find_map(|asset_key| {
|
|
||||||
// let derivation_hint = asset_key.can_derive(self.as_inner())?;
|
|
||||||
// Some((asset_key, derivation_hint))
|
|
||||||
// })?;
|
|
||||||
|
|
||||||
// Some(Plan {
|
|
||||||
// template: vec![TemplateItem::Sign(PlanKey {
|
|
||||||
// asset_key: asset_key.clone(),
|
|
||||||
// descriptor_key: self.as_inner().clone(),
|
|
||||||
// derivation_hint,
|
|
||||||
// })],
|
|
||||||
// target: Target::Segwitv0,
|
|
||||||
// set_locktime: None,
|
|
||||||
// set_sequence: None,
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub(crate) fn plan_satisfaction_tr<Ak>(
|
|
||||||
tr: &miniscript::descriptor::Tr<DefiniteDescriptorKey>,
|
|
||||||
assets: &Assets<Ak>,
|
|
||||||
) -> Option<Plan<Ak>>
|
|
||||||
where
|
|
||||||
Ak: CanDerive + Clone,
|
|
||||||
{
|
|
||||||
let key_path_spend = assets.keys.iter().find_map(|asset_key| {
|
|
||||||
let derivation_hint = asset_key.can_derive(tr.internal_key())?;
|
|
||||||
Some((asset_key, derivation_hint))
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some((asset_key, derivation_hint)) = key_path_spend {
|
|
||||||
return Some(Plan {
|
|
||||||
template: vec![TemplateItem::Sign(PlanKey {
|
|
||||||
asset_key: asset_key.clone(),
|
|
||||||
descriptor_key: tr.internal_key().clone(),
|
|
||||||
derivation_hint,
|
|
||||||
})],
|
|
||||||
target: Target::Segwitv1 {
|
|
||||||
tr: tr.clone(),
|
|
||||||
tr_plan: TrSpend::KeySpend,
|
|
||||||
},
|
|
||||||
set_locktime: None,
|
|
||||||
set_sequence: None,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut plans = tr
|
|
||||||
.iter_scripts()
|
|
||||||
.filter_map(|(_, ms)| Some((ms, (plan_steps(&ms.node, assets)?))))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
plans.sort_by_cached_key(|(_, plan)| plan.expected_size());
|
|
||||||
|
|
||||||
let (script, best_plan) = plans.into_iter().next()?;
|
|
||||||
|
|
||||||
Some(Plan {
|
|
||||||
target: Target::Segwitv1 {
|
|
||||||
tr: tr.clone(),
|
|
||||||
tr_plan: TrSpend::LeafSpend {
|
|
||||||
script: script.encode(),
|
|
||||||
leaf_version: LeafVersion::TapScript,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
set_locktime: best_plan.min_locktime.clone(),
|
|
||||||
set_sequence: best_plan.min_sequence.clone(),
|
|
||||||
template: best_plan.template,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct TermPlan<Ak> {
|
|
||||||
pub min_locktime: Option<LockTime>,
|
|
||||||
pub min_sequence: Option<Sequence>,
|
|
||||||
pub template: Vec<TemplateItem<Ak>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Ak> TermPlan<Ak> {
|
|
||||||
fn new(template: Vec<TemplateItem<Ak>>) -> Self {
|
|
||||||
TermPlan {
|
|
||||||
template,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Ak> Default for TermPlan<Ak> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
min_locktime: Default::default(),
|
|
||||||
min_sequence: Default::default(),
|
|
||||||
template: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn plan_steps<Ak: Clone + CanDerive, Ctx: ScriptContext>(
|
|
||||||
term: &Terminal<DefiniteDescriptorKey, Ctx>,
|
|
||||||
assets: &Assets<Ak>,
|
|
||||||
) -> Option<TermPlan<Ak>> {
|
|
||||||
match term {
|
|
||||||
Terminal::True => Some(TermPlan::new(vec![])),
|
|
||||||
Terminal::False => return None,
|
|
||||||
Terminal::PkH(key) => {
|
|
||||||
let (asset_key, derivation_hint) = assets
|
|
||||||
.keys
|
|
||||||
.iter()
|
|
||||||
.find_map(|asset_key| Some((asset_key, asset_key.can_derive(key)?)))?;
|
|
||||||
Some(TermPlan::new(vec![
|
|
||||||
TemplateItem::Sign(PlanKey {
|
|
||||||
asset_key: asset_key.clone(),
|
|
||||||
derivation_hint,
|
|
||||||
descriptor_key: key.clone(),
|
|
||||||
}),
|
|
||||||
TemplateItem::Pk { key: key.clone() },
|
|
||||||
]))
|
|
||||||
}
|
|
||||||
Terminal::PkK(key) => {
|
|
||||||
let (asset_key, derivation_hint) = assets
|
|
||||||
.keys
|
|
||||||
.iter()
|
|
||||||
.find_map(|asset_key| Some((asset_key, asset_key.can_derive(key)?)))?;
|
|
||||||
Some(TermPlan::new(vec![TemplateItem::Sign(PlanKey {
|
|
||||||
asset_key: asset_key.clone(),
|
|
||||||
derivation_hint,
|
|
||||||
descriptor_key: key.clone(),
|
|
||||||
})]))
|
|
||||||
}
|
|
||||||
Terminal::RawPkH(_pk_hash) => {
|
|
||||||
/* TODO */
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Terminal::After(locktime) => {
|
|
||||||
let max_locktime = assets.max_locktime?;
|
|
||||||
let locktime = LockTime::from(locktime);
|
|
||||||
let (height, time) = match max_locktime {
|
|
||||||
LockTime::Blocks(height) => (height, Time::from_consensus(0).unwrap()),
|
|
||||||
LockTime::Seconds(seconds) => (Height::from_consensus(0).unwrap(), seconds),
|
|
||||||
};
|
|
||||||
if max_locktime.is_satisfied_by(height, time) {
|
|
||||||
Some(TermPlan {
|
|
||||||
min_locktime: Some(locktime),
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Terminal::Older(older) => {
|
|
||||||
// FIXME: older should be a height or time not a sequence.
|
|
||||||
let max_sequence = assets.txo_age?;
|
|
||||||
//TODO: this whole thing is probably wrong but upstream should provide a way of
|
|
||||||
// doing it properly.
|
|
||||||
if max_sequence.is_height_locked() == older.is_height_locked() {
|
|
||||||
if max_sequence.to_consensus_u32() >= older.to_consensus_u32() {
|
|
||||||
Some(TermPlan {
|
|
||||||
min_sequence: Some(*older),
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Terminal::Sha256(image) => {
|
|
||||||
if assets.sha256.contains(&image) {
|
|
||||||
Some(TermPlan::new(vec![TemplateItem::Sha256(image.clone())]))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Terminal::Hash256(image) => {
|
|
||||||
if assets.hash256.contains(image) {
|
|
||||||
Some(TermPlan::new(vec![TemplateItem::Hash256(image.clone())]))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Terminal::Ripemd160(image) => {
|
|
||||||
if assets.ripemd160.contains(&image) {
|
|
||||||
Some(TermPlan::new(vec![TemplateItem::Ripemd160(image.clone())]))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Terminal::Hash160(image) => {
|
|
||||||
if assets.hash160.contains(&image) {
|
|
||||||
Some(TermPlan::new(vec![TemplateItem::Hash160(image.clone())]))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Terminal::Alt(ms)
|
|
||||||
| Terminal::Swap(ms)
|
|
||||||
| Terminal::Check(ms)
|
|
||||||
| Terminal::Verify(ms)
|
|
||||||
| Terminal::NonZero(ms)
|
|
||||||
| Terminal::ZeroNotEqual(ms) => plan_steps(&ms.node, assets),
|
|
||||||
Terminal::DupIf(ms) => {
|
|
||||||
let mut plan = plan_steps(&ms.node, assets)?;
|
|
||||||
plan.template.push(TemplateItem::One);
|
|
||||||
Some(plan)
|
|
||||||
}
|
|
||||||
Terminal::AndV(l, r) | Terminal::AndB(l, r) => {
|
|
||||||
let lhs = plan_steps(&l.node, assets)?;
|
|
||||||
let rhs = plan_steps(&r.node, assets)?;
|
|
||||||
lhs.combine(rhs)
|
|
||||||
}
|
|
||||||
Terminal::AndOr(_, _, _) => todo!(),
|
|
||||||
Terminal::OrB(_, _) => todo!(),
|
|
||||||
Terminal::OrD(_, _) => todo!(),
|
|
||||||
Terminal::OrC(_, _) => todo!(),
|
|
||||||
Terminal::OrI(lhs, rhs) => {
|
|
||||||
let lplan = plan_steps(&lhs.node, assets).map(|mut plan| {
|
|
||||||
plan.template.push(TemplateItem::One);
|
|
||||||
plan
|
|
||||||
});
|
|
||||||
let rplan = plan_steps(&rhs.node, assets).map(|mut plan| {
|
|
||||||
plan.template.push(TemplateItem::Zero);
|
|
||||||
plan
|
|
||||||
});
|
|
||||||
match (lplan, rplan) {
|
|
||||||
(Some(lplan), Some(rplan)) => {
|
|
||||||
if lplan.expected_size() <= rplan.expected_size() {
|
|
||||||
Some(lplan)
|
|
||||||
} else {
|
|
||||||
Some(rplan)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(lplan, rplan) => lplan.or(rplan),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Terminal::Thresh(_, _) => todo!(),
|
|
||||||
Terminal::Multi(_, _) => todo!(),
|
|
||||||
Terminal::MultiA(_, _) => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,218 +0,0 @@
|
|||||||
use bdk_chain::{bitcoin, collections::*, miniscript};
|
|
||||||
use core::ops::Deref;
|
|
||||||
|
|
||||||
use bitcoin::{
|
|
||||||
hashes::{hash160, ripemd160, sha256},
|
|
||||||
psbt::Prevouts,
|
|
||||||
secp256k1::{KeyPair, Message, PublicKey, Signing, Verification},
|
|
||||||
util::{bip32, sighash, sighash::SighashCache, taproot},
|
|
||||||
EcdsaSighashType, SchnorrSighashType, Transaction, TxOut, XOnlyPublicKey,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
use miniscript::{
|
|
||||||
descriptor::{DescriptorSecretKey, KeyMap},
|
|
||||||
hash256,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
/// Signatures and hash pre-images that must be provided to complete the plan.
|
|
||||||
pub struct Requirements<Ak> {
|
|
||||||
/// required signatures
|
|
||||||
pub signatures: RequiredSignatures<Ak>,
|
|
||||||
/// required sha256 pre-images
|
|
||||||
pub sha256_images: HashSet<sha256::Hash>,
|
|
||||||
/// required hash160 pre-images
|
|
||||||
pub hash160_images: HashSet<hash160::Hash>,
|
|
||||||
/// required hash256 pre-images
|
|
||||||
pub hash256_images: HashSet<hash256::Hash>,
|
|
||||||
/// required ripemd160 pre-images
|
|
||||||
pub ripemd160_images: HashSet<ripemd160::Hash>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Ak> Default for RequiredSignatures<Ak> {
|
|
||||||
fn default() -> Self {
|
|
||||||
RequiredSignatures::Legacy {
|
|
||||||
keys: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Ak> Default for Requirements<Ak> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
signatures: Default::default(),
|
|
||||||
sha256_images: Default::default(),
|
|
||||||
hash160_images: Default::default(),
|
|
||||||
hash256_images: Default::default(),
|
|
||||||
ripemd160_images: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Ak> Requirements<Ak> {
|
|
||||||
/// Whether any hash pre-images are required in the plan
|
|
||||||
pub fn requires_hash_preimages(&self) -> bool {
|
|
||||||
!(self.sha256_images.is_empty()
|
|
||||||
&& self.hash160_images.is_empty()
|
|
||||||
&& self.hash256_images.is_empty()
|
|
||||||
&& self.ripemd160_images.is_empty())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The signatures required to complete the plan
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum RequiredSignatures<Ak> {
|
|
||||||
/// Legacy ECDSA signatures are required
|
|
||||||
Legacy { keys: Vec<PlanKey<Ak>> },
|
|
||||||
/// Segwitv0 ECDSA signatures are required
|
|
||||||
Segwitv0 { keys: Vec<PlanKey<Ak>> },
|
|
||||||
/// A Taproot key spend signature is required
|
|
||||||
TapKey {
|
|
||||||
/// the internal key
|
|
||||||
plan_key: PlanKey<Ak>,
|
|
||||||
/// The merkle root of the taproot output
|
|
||||||
merkle_root: Option<TapBranchHash>,
|
|
||||||
},
|
|
||||||
/// Taproot script path signatures are required
|
|
||||||
TapScript {
|
|
||||||
/// The leaf hash of the script being used
|
|
||||||
leaf_hash: TapLeafHash,
|
|
||||||
/// The keys in the script that require signatures
|
|
||||||
plan_keys: Vec<PlanKey<Ak>>,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum SigningError {
|
|
||||||
SigHashError(sighash::Error),
|
|
||||||
DerivationError(bip32::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<sighash::Error> for SigningError {
|
|
||||||
fn from(e: sighash::Error) -> Self {
|
|
||||||
Self::SigHashError(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl core::fmt::Display for SigningError {
|
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
||||||
match self {
|
|
||||||
SigningError::SigHashError(e) => e.fmt(f),
|
|
||||||
SigningError::DerivationError(e) => e.fmt(f),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<bip32::Error> for SigningError {
|
|
||||||
fn from(e: bip32::Error) -> Self {
|
|
||||||
Self::DerivationError(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
impl std::error::Error for SigningError {}
|
|
||||||
|
|
||||||
impl RequiredSignatures<DescriptorPublicKey> {
|
|
||||||
pub fn sign_with_keymap<T: Deref<Target = Transaction>>(
|
|
||||||
&self,
|
|
||||||
input_index: usize,
|
|
||||||
keymap: &KeyMap,
|
|
||||||
prevouts: &Prevouts<'_, impl core::borrow::Borrow<TxOut>>,
|
|
||||||
schnorr_sighashty: Option<SchnorrSighashType>,
|
|
||||||
_ecdsa_sighashty: Option<EcdsaSighashType>,
|
|
||||||
sighash_cache: &mut SighashCache<T>,
|
|
||||||
auth_data: &mut SatisfactionMaterial,
|
|
||||||
secp: &Secp256k1<impl Signing + Verification>,
|
|
||||||
) -> Result<bool, SigningError> {
|
|
||||||
match self {
|
|
||||||
RequiredSignatures::Legacy { .. } | RequiredSignatures::Segwitv0 { .. } => todo!(),
|
|
||||||
RequiredSignatures::TapKey {
|
|
||||||
plan_key,
|
|
||||||
merkle_root,
|
|
||||||
} => {
|
|
||||||
let schnorr_sighashty = schnorr_sighashty.unwrap_or(SchnorrSighashType::Default);
|
|
||||||
let sighash = sighash_cache.taproot_key_spend_signature_hash(
|
|
||||||
input_index,
|
|
||||||
prevouts,
|
|
||||||
schnorr_sighashty,
|
|
||||||
)?;
|
|
||||||
let secret_key = match keymap.get(&plan_key.asset_key) {
|
|
||||||
Some(secret_key) => secret_key,
|
|
||||||
None => return Ok(false),
|
|
||||||
};
|
|
||||||
let secret_key = match secret_key {
|
|
||||||
DescriptorSecretKey::Single(single) => single.key.inner,
|
|
||||||
DescriptorSecretKey::XPrv(xprv) => {
|
|
||||||
xprv.xkey
|
|
||||||
.derive_priv(&secp, &plan_key.derivation_hint)?
|
|
||||||
.private_key
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let pubkey = PublicKey::from_secret_key(&secp, &secret_key);
|
|
||||||
let x_only_pubkey = XOnlyPublicKey::from(pubkey);
|
|
||||||
|
|
||||||
let tweak =
|
|
||||||
taproot::TapTweakHash::from_key_and_tweak(x_only_pubkey, merkle_root.clone());
|
|
||||||
let keypair = KeyPair::from_secret_key(&secp, &secret_key.clone())
|
|
||||||
.add_xonly_tweak(&secp, &tweak.to_scalar())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let msg = Message::from_slice(sighash.as_ref()).expect("Sighashes are 32 bytes");
|
|
||||||
let sig = secp.sign_schnorr_no_aux_rand(&msg, &keypair);
|
|
||||||
|
|
||||||
let bitcoin_sig = SchnorrSig {
|
|
||||||
sig,
|
|
||||||
hash_ty: schnorr_sighashty,
|
|
||||||
};
|
|
||||||
|
|
||||||
auth_data
|
|
||||||
.schnorr_sigs
|
|
||||||
.insert(plan_key.descriptor_key.clone(), bitcoin_sig);
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
RequiredSignatures::TapScript {
|
|
||||||
leaf_hash,
|
|
||||||
plan_keys,
|
|
||||||
} => {
|
|
||||||
let sighash_type = schnorr_sighashty.unwrap_or(SchnorrSighashType::Default);
|
|
||||||
let sighash = sighash_cache.taproot_script_spend_signature_hash(
|
|
||||||
input_index,
|
|
||||||
prevouts,
|
|
||||||
*leaf_hash,
|
|
||||||
sighash_type,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let mut modified = false;
|
|
||||||
|
|
||||||
for plan_key in plan_keys {
|
|
||||||
if let Some(secret_key) = keymap.get(&plan_key.asset_key) {
|
|
||||||
let secret_key = match secret_key {
|
|
||||||
DescriptorSecretKey::Single(single) => single.key.inner,
|
|
||||||
DescriptorSecretKey::XPrv(xprv) => {
|
|
||||||
xprv.xkey
|
|
||||||
.derive_priv(&secp, &plan_key.derivation_hint)?
|
|
||||||
.private_key
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let keypair = KeyPair::from_secret_key(&secp, &secret_key.clone());
|
|
||||||
let msg =
|
|
||||||
Message::from_slice(sighash.as_ref()).expect("Sighashes are 32 bytes");
|
|
||||||
let sig = secp.sign_schnorr_no_aux_rand(&msg, &keypair);
|
|
||||||
let bitcoin_sig = SchnorrSig {
|
|
||||||
sig,
|
|
||||||
hash_ty: sighash_type,
|
|
||||||
};
|
|
||||||
|
|
||||||
auth_data
|
|
||||||
.schnorr_sigs
|
|
||||||
.insert(plan_key.descriptor_key.clone(), bitcoin_sig);
|
|
||||||
modified = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(modified)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,76 +0,0 @@
|
|||||||
use bdk_chain::{bitcoin, miniscript};
|
|
||||||
use bitcoin::{
|
|
||||||
hashes::{hash160, ripemd160, sha256},
|
|
||||||
util::bip32::DerivationPath,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
use crate::{hash256, varint_len, DefiniteDescriptorKey};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub(crate) enum TemplateItem<Ak> {
|
|
||||||
Sign(PlanKey<Ak>),
|
|
||||||
Pk { key: DefiniteDescriptorKey },
|
|
||||||
One,
|
|
||||||
Zero,
|
|
||||||
Sha256(sha256::Hash),
|
|
||||||
Hash256(hash256::Hash),
|
|
||||||
Ripemd160(ripemd160::Hash),
|
|
||||||
Hash160(hash160::Hash),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A plan key contains the asset key originally provided along with key in the descriptor it
|
|
||||||
/// purports to be able to derive for along with a "hint" on how to derive it.
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct PlanKey<Ak> {
|
|
||||||
/// The key the planner will sign with
|
|
||||||
pub asset_key: Ak,
|
|
||||||
/// A hint from how to get from the asset key to the concrete key we need to sign with.
|
|
||||||
pub derivation_hint: DerivationPath,
|
|
||||||
/// The key that was in the descriptor that we are satisfying with the signature from the asset
|
|
||||||
/// key.
|
|
||||||
pub descriptor_key: DefiniteDescriptorKey,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Ak> TemplateItem<Ak> {
|
|
||||||
pub fn expected_size(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
TemplateItem::Sign { .. } => 64, /*size of sig TODO: take into consideration sighash falg*/
|
|
||||||
TemplateItem::Pk { .. } => 32,
|
|
||||||
TemplateItem::One => varint_len(1),
|
|
||||||
TemplateItem::Zero => 0, /* zero means an empty witness element */
|
|
||||||
// I'm not sure if it should be 32 here (it's a 20 byte hash) but that's what other
|
|
||||||
// parts of the code were doing.
|
|
||||||
TemplateItem::Hash160(_) | TemplateItem::Ripemd160(_) => 32,
|
|
||||||
TemplateItem::Sha256(_) | TemplateItem::Hash256(_) => 32,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// this can only be called if we are sure that auth_data has what we need
|
|
||||||
pub(super) fn to_witness_stack(&self, auth_data: &SatisfactionMaterial) -> Vec<Vec<u8>> {
|
|
||||||
match self {
|
|
||||||
TemplateItem::Sign(plan_key) => {
|
|
||||||
vec![auth_data
|
|
||||||
.schnorr_sigs
|
|
||||||
.get(&plan_key.descriptor_key)
|
|
||||||
.unwrap()
|
|
||||||
.to_vec()]
|
|
||||||
}
|
|
||||||
TemplateItem::One => vec![vec![1]],
|
|
||||||
TemplateItem::Zero => vec![vec![]],
|
|
||||||
TemplateItem::Sha256(image) => {
|
|
||||||
vec![auth_data.sha256_preimages.get(image).unwrap().to_vec()]
|
|
||||||
}
|
|
||||||
TemplateItem::Hash160(image) => {
|
|
||||||
vec![auth_data.hash160_preimages.get(image).unwrap().to_vec()]
|
|
||||||
}
|
|
||||||
TemplateItem::Ripemd160(image) => {
|
|
||||||
vec![auth_data.ripemd160_preimages.get(image).unwrap().to_vec()]
|
|
||||||
}
|
|
||||||
TemplateItem::Hash256(image) => {
|
|
||||||
vec![auth_data.hash256_preimages.get(image).unwrap().to_vec()]
|
|
||||||
}
|
|
||||||
TemplateItem::Pk { key } => vec![key.to_public_key().to_bytes()],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user