---
# System prepended metadata

title: rust-miniscript + bdk - planning module

---

# rust-miniscript + bdk - planning module

- Right now BDK has a policy module: when creating a transaction I can specify which policy I want to use to spend my utxos
  - or(and(A,B), C): either A+B or C by themselves
  - when I create the transaction, I decide if I want to spend with the A+B path, or if I want to spend with the C path
- UX is not great, specifying which policy to use can be difficult
- We want to replace the policy module with the planning module
- Replacing the policy module with this planning idea
- Instead of specifying the policy I want to use to spend, I specify the "assets" (keys, timelocks, hash preimages) I have/want to use, and the planning module wi
  - or(and(A,B),C), I tell the planning module that I own the keys A, B, C
    - The planning module will tell me to spend using the key C -> it's cheaper than using A+B
  - or(A, and(B, older(10))), I tell the planning module I only have B
    - The planning module will tell me I can't spend
  - or(A, and(B, older(10))), I tell the planning module I have B and I'm ok waiting 10 blocks
    - The planning module will tell me that I can spend using the B + older(10) policy
- Planning module is going to be used in three places:
  - 1: before creating the transaction, to figure out *if* I can spend certain coins
  - 2: during coin selection! What we do right now is, for each coin, we estimate its weight using `max_satisfaction_weight`, and that's quite wasteful
    - `or(A, and(B, C, D, E, F, G))` -> the `max_sat_weight` of this policy is spending with `B + C + ... + G`, and that's really expensive. If we just use `max_sat_weight` in the coin selection, when spending with `A` we're going to overshoot the fee for no reason.
    - We want to use the planning module to precisely estimate the coin's spending weight
  - 3: if I'm given a PSBT, and I know the Plan I want to use to spend it, I want to fill the PSBT with the metadata I need to spend
- PR: add the planning module: https://github.com/rust-bitcoin/rust-miniscript/pull/481

## Current API

Even though the planning module PR is still a work in progress, we already have a good idea of how the final API will look like.

```rust
pub struct Plan {
    /// This plan's witness template
    pub template: Vec<Placeholder<DefiniteDescriptorKey>>,
    /// The absolute timelock this plan uses
    pub absolute_timelock: Option<LockTime>,
    /// The relative timelock this plan uses
    pub relative_timelock: Option<Sequence>,
    // ...private fields...
}

/// Placeholder for some data in a [`Plan`]
pub enum Placeholder<Pk: MiniscriptKey> {
    /// Public key and its size
    Pubkey(Pk, usize),
    /// ECDSA signature given the raw pubkey
    EcdsaSigPk(Pk),
    /// Schnorr signature and its size
    SchnorrSig(Pk, SchnorrSigType, usize),
    /// SHA-256 preimage
    Sha256Preimage(Pk::Sha256),
    /// HASH256 preimage
    Hash256Preimage(Pk::Hash256),
    /// RIPEMD160 preimage
    Ripemd160Preimage(Pk::Ripemd160),
    /// HASH160 preimage
    Hash160Preimage(Pk::Hash160),
    /// Hash dissatisfaction (32 bytes of 0x00)
    HashDissatisfaction,
    /// OP_1
    PushOne,
    /// <empty item>
    PushZero,
    /// Taproot leaf script
    TapScript(Script),
    /// Taproot control block
    TapControlBlock(ControlBlock),
}
```

Users will call `descriptor.get_plan(assets)` on a descriptor, and obtain a `Plan`. The `Plan` contains the witness template, i.e., a sketch of how the witness will look like, with placeholders instead of actual keys and signatures. The plan will also contain the absolute and relative timelock needed for spending.

Important to note, timelock are assets, and will be included in the solution only if they were specified as assets. For example, given the policy `and(A, and(B, relative_timelock1))`, no plan will be generated from the assets `[B]`, and an error will be returned instead; if the assets provided are `[B, relative_timelock2]`, with `relative_ttimelock2 > relative_timelock1`, then a plan will be generated, with `absolute_timelock = None` and `relative_timelock = Some(relative_timelock1)`