Problem
The Finalizer cannot be serialized and persisted to storage. This prevents a common and important workflow: handing off a transaction for signing to an external party and finalizing it later.
When signing is delegated to an external signer (hardware wallet, air-gapped device, remote co-signer, or another service), an arbitrary amount of time may pass between PSBT creation and the return of the signed PSBT. The process that built the transaction — and the Finalizer it produced — may not stay alive across that gap. It could be a short-lived request handler, a CLI invocation that exits, or a wallet that is shut down between sessions.
The PSBT itself is already persistable (BIP174 is a serialization format), so the unsigned/partially-signed transaction can be saved and handed off freely. The Finalizer, however, cannot follow it. This means the only way to finalize a PSBT with bdk-tx is to keep the original in-memory Finalizer alive from creation through finalization, which is incompatible with any persistence boundary between those two steps.
Why this matters
- External signers — the defining use case. The wallet builds and persists the PSBT, sends it off, and exits. When the signed PSBT comes back (minutes, hours, or days later), there is no way to reconstruct the
Finalizer needed to complete it.
- Offline / air-gapped flows — PSBT goes out to cold storage and comes back signed; the online side has no surviving finalization state.
- Crash recovery / restarts — a wallet restarted mid-flow loses the ability to finalize PSBTs that were already created and signed.
Root cause
Finalizer holds a HashMap<OutPoint, Plan> (src/finalizer.rs), where Plan is miniscript::plan::Plan. That type:
- does not implement
serde::Serialize / Deserialize,
- has no public constructor (its
template and descriptor fields are pub(crate)), and
- cannot be rebuilt from its public accessors.
As a result, there is no supported way to serialize a Finalizer, nor to reconstruct an equivalent one from saved data, after the originating process is gone.
Scope
This issue is intentionally limited to stating the problem. It does not propose a solution; design options (and their trade-offs around forward-compatibility, miniscript coupling, and API surface) should be discussed separately.
Problem
The
Finalizercannot be serialized and persisted to storage. This prevents a common and important workflow: handing off a transaction for signing to an external party and finalizing it later.When signing is delegated to an external signer (hardware wallet, air-gapped device, remote co-signer, or another service), an arbitrary amount of time may pass between PSBT creation and the return of the signed PSBT. The process that built the transaction — and the
Finalizerit produced — may not stay alive across that gap. It could be a short-lived request handler, a CLI invocation that exits, or a wallet that is shut down between sessions.The PSBT itself is already persistable (BIP174 is a serialization format), so the unsigned/partially-signed transaction can be saved and handed off freely. The
Finalizer, however, cannot follow it. This means the only way to finalize a PSBT with bdk-tx is to keep the original in-memoryFinalizeralive from creation through finalization, which is incompatible with any persistence boundary between those two steps.Why this matters
Finalizerneeded to complete it.Root cause
Finalizerholds aHashMap<OutPoint, Plan>(src/finalizer.rs), wherePlanisminiscript::plan::Plan. That type:serde::Serialize/Deserialize,templateanddescriptorfields arepub(crate)), andAs a result, there is no supported way to serialize a
Finalizer, nor to reconstruct an equivalent one from saved data, after the originating process is gone.Scope
This issue is intentionally limited to stating the problem. It does not propose a solution; design options (and their trade-offs around forward-compatibility, miniscript coupling, and API surface) should be discussed separately.