feat: introduce TxTemplate as an intermediate stage#73
Draft
evanlinjin wants to merge 8 commits into
Draft
Conversation
* move no-std rand functions to `no_std_rand.rs` * move AFS types to `afs.rs` * Add `fisher_yates_shuffle` function that shuffles list elements
`Selection.inputs` / `Selection.outputs` are now private; access through `inputs()` / `outputs()`. Mutation goes through `InputMut`, returned by `input_mut(outpoint)` and `inputs_mut()`. `InputMut` derefs to `&Input` and only exposes `set_sequence`, preventing whole-input replacement that would silently break coin-selection invariants.
Adds `sort_inputs_by`, `shuffle_inputs`, `sort_outputs_by`, `shuffle_outputs` on `Selection`. Covers BIP-69 ordering (via sort_by) and chain-analysis shuffling without exposing raw mutable slots that would let callers replace inputs/outputs and silently break coin-selection invariants.
`SelectorError::LockTypeMismatch` now rejects candidate inputs with mixed absolute-timelock units up front, in `Selector::new`. `CreatePsbtError::LockTypeMismatch` is removed and `accumulate_max_locktime` becomes infallible (with a `debug_assert!` guarding the upstream invariant). Catches the failure at the earliest point and lets PSBT creation assume the invariant.
Co-authored-by: Noah Joeris <noahjoeris@gmail.com>
Member
Author
|
This is fully AI generated and not ready for review. |
8b53dee to
27084ae
Compare
Pure rename — same struct, same methods, same parameters. No behaviour change. The next commit adds the resolved tx-shape fields (version, lock_time, fallback_sequence), the corresponding setters, and the PSBT/AFS pipeline that consumes them. Selection -> TxTemplate Selection::new -> TxTemplate::from_parts (still pub(crate)) IntoSelectionError -> IntoTxTemplateError InputCandidates::into_selection -> into_tx_template Selector::try_finalize() -> Option<TxTemplate> Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes bitcoindevkit#57. TxTemplate now owns the resolved tx-shape fields and the methods that mutate them. The selector hands you a TxTemplate already configured with sensible defaults; everything else is method calls on it. New fields on TxTemplate: - version (default V2) - lock_time (= max(input CLTV) or ZERO) - fallback_sequence (default ENABLE_RBF_NO_LOCKTIME) New setters with validation: - set_version -> SetVersionError::RelativeTimelockRequiresV2 - set_locktime -> SetLockTimeError::{BelowInputCltv, UnitMismatch} - set_fallback_sequence The PSBT/AFS pipeline is restructured around these fields: - PsbtParams -> PsbtBuildParams (PSBT-only knobs; version/locktime /AFS removed) - CreatePsbtError -> BuildPsbtError - create_psbt(params) -> (Psbt, Finalizer) (was just Psbt) - anti-fee-sniping moves off PsbtParams::anti_fee_sniping into TxTemplate::apply_anti_fee_sniping(tip, &mut rng), a separate chainable step that composes the public set_locktime / Input::set_sequence - to_unsigned_tx() materializes the tx for non-PSBT signing flows Chain ergonomics: sort_inputs_by / shuffle_inputs (etc.) now consume self and return Self. into_finalizer is dropped — Finalizer comes from create_psbt or from Finalizer::new for callers that want it standalone. What was previously silent is now an explicit error: - min_locktime of the wrong unit was silently ignored - min_locktime below an input's CLTV was silently clamped up Both now error via SetLockTimeError. Setting v < 2 with a relative- timelock input errors via SetVersionError. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
create_psbt no longer needs an RNG (AFS — the only consumer — takes its own rng explicitly), so the create_psbt_with_rng wrapper and its thread_rng() call were dead weight. Collapses both into a single create_psbt(self, params) and moves rand to dev-dependencies. The library now depends only on rand_core (for the RngCore trait) + miniscript + bdk_coin_select. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
27084ae to
e9c2962
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #57. Refactors
Selectioninto a richer tx-shape type calledTxTemplate. The pipeline becomes:TxTemplateis the single workspace for how the transaction is shaped — version, locktime, fallback sequence, per-input sequence overrides, ordering, anti-fee-sniping, and final emission. AFS is no longer privileged: it's a pure caller of public methods (set_locktime,Input::set_sequence).New templates start with sensible defaults (version = v2, lock_time = max input CLTV (or
ZERO), fallback_sequence =ENABLE_RBF_NO_LOCKTIME). All overrides are methods:set_version,set_locktime,set_fallback_sequence,apply_anti_fee_sniping,shuffle_inputs,sort_outputs_by,input_mut, etc.Migration
SelectionTxTemplateSelector::try_finalize() -> Option<Selection>Selector::try_finalize() -> Option<TxTemplate>InputCandidates::into_selection(algo, params)InputCandidates::into_tx_template(algo, params) -> Result<TxTemplate, _>IntoSelectionErrorIntoTxTemplateErrorPsbtParamsPsbtBuildParams(emission-only)PsbtParams::versionTxTemplate::set_version(v) -> Result<_>(rejectsv < 2if any input has a relative timelock)PsbtParams::min_locktimeTxTemplate::set_locktime(lt) -> Result<_>(validates same-unit + ≥-CLTV)PsbtParams::anti_fee_sniping: Option<Height>TxTemplate::apply_anti_fee_sniping(tip, &mut rng) -> Result<_>selection.create_psbt(p)?tx_template.create_psbt(PsbtBuildParams::default())?returning(Psbt, Finalizer)selection.shuffle_inputs(&mut rng)(&mut self)tx_template.shuffle_inputs(&mut rng)(consuming, returnsSelf)selection.sort_inputs_by(...)tx_template.sort_inputs_by(...)selection.input_mut(op)/inputs_mut()tx_template.input_mut(op)/inputs_mut()ENABLE_RBF_NO_LOCKTIME)TxTemplate::set_fallback_sequence(s); default unchangedBehaviour changes worth flagging:
min_locktimeof the wrong unit was silently ignored; below-CLTV was silently clamped up. Nowset_locktimereturnsSetLockTimeError::UnitMismatch/SetLockTimeError::BelowInputCltv. Trying to setv1with a relative-timelock input returnsSetVersionError::RelativeTimelockRequiresV2.Sequence::ENABLE_RBF_NO_LOCKTIMEfallback is now configurable viaset_fallback_sequence.rand. Onlyrand_core(for theRngCoretrait). Production dep tree:miniscript,bdk_coin_select,rand_core.Out of scope
no_stdfeature. Blocked onbdk_coin_selectupstream: fix: add conditional FloatExt import for no_std builds coin-select#37 (FloatExt import fix) is merged but no0.4.2release exists yet. Follow-up once a release lands.TxTemplate::create_psbt_v2()method — same construction logic, different emit step.Notes for reviewers
apply_anti_fee_snipingcallsset_locktime/Input::set_sequencevia the public path and.expect()s the results. The expects hold by construction:afs_locktime >= current(both height-based, since AFS early-rejects time-based), soset_locktime's unit + ≥-CLTV checks always pass.set_sequencecannot fail the CSV/CLTV-disable check.TxTemplate::from_parts(the constructor used bySelector::try_finalize) ispub(crate). External users construct viaSelector/InputCandidates. If hand-rolledTxTemplatebecomes a common ask, exposing this is a one-line change.Commits (3)
TxTemplateas a state betweenSelectionandPsbt#57.Test plan