-
Notifications
You must be signed in to change notification settings - Fork 8
The new TxBuilder
#1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The new TxBuilder
#1
Conversation
f7bbc03
to
3e1290b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've been looking at the following sources to try to get the whole idea behind this:
- bitcoindevkit/bdk#899
- TxBuilder redesign
I think we should try to minimize the inter dependency as much as possible (bdk_chain
and bdk_coin_select
). Maybe we are thinking too close to the previous TxBuilder
design, where the transaction constrains were specified and all the building process was done downstream in the same context.
I see no problem in leaving some parts undefined, stating some assumptions about the inputs, like whether they have already been selected, and working under those assumptions.
Right now I think this repo should try to complete steps 4, 5 and 6 of bitcoindevkit/bdk#899 and maybe move input grouping and filtering (step 1) to a separate project, or leave it here but work on them separately. Without touching coin selection here and just adding examples as tests/synopsis.rs
in the right places (bdk_wallet
) to show how these different modules integrate together.
src/create_selection.rs
Outdated
.add(pks) | ||
.add(additional_assets); | ||
|
||
tx_graph |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this be removed in favor of outsourcing it to bdk_chain
and just receiving the data as some parameter? Thinking in removing the bdk_chain
dependency here.
In terms of the dependency tree, I'm thinking of putting the In terms of separating out the coin selection and psbt creation into separate crates... I'll need to give it more thought. |
src/input_candidates.rs
Outdated
let mut pks = vec![]; | ||
for desc in descriptors.values() { | ||
desc.for_each_key(|k| { | ||
pks.extend(k.clone().into_single_keys()); | ||
true | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned in @ValuedMammal's HackMD, sometimes the caller may not have all keys available for spending from. What is the right API so that it is not tedious to fill in available assets?
a83abdd
to
0f4b6c9
Compare
e24482e
to
991a770
Compare
**Remove `PsbtUpdater` & `Builder`** These was no need for these to be separated. The builder pattern was nice but not needed at this stage. **Remove `DataProvider`** Instead of creating a separate struct for passing in data for inputs/outputs. We can just have the data within our inputs/outputs. **Introduce `Input` and `Output` types** The `Input` type is what is passed through all stages of tx-building. From canonicalization, grouping/filtering, coin-selection and finally used to create the psbt. The `Output` type is used to describe a psbt output. It either is one that we own (in which, we have the descriptor), or one we do not (in which case, we just have a spk).
* Added `CoinControl` which handles our canonical set, filtering and grouping. * Added `InputCandidates` which contains inputs available for coin selection, with the ability to mark inputs as "must select". * Added `tests/synopsis` to see what it will look like with everything put together. * Changed `Input` so that it can be constructed from a PSBT Input. Also added more helper methods so that data such as "is spendable now" can be obtained from the input. * Added `Selection` which represents the final coin selection result. * Added `Selector` which contains the `bdk_coin_select::CoinSelector`. This allows flexible selections. * Added `RbfSet` to contain RBF logic. * Updated `tests/synopsis.rs` to show mempool-policy-conforming tx-cancellation.
`CanonicalUnspents` is our "single source of truth" and all UTXOs added to the selector should really pass through it to ensure we don't create transactions that double-spend themselves. Also replaced `Input::from_finalized_psbt_input` with `from_psbt_input` for more flexibility. The responsibility of grouping and filtering input candidates have been moved to `InputCandidates` (instead of the now-removed `CoinControl` struct). The downside of this is that it makes it more invloved to interface with `bdk_chain` or `bdk_wallet`. Adding methods on `KeychainTxOutIndex` will help.
991a770
to
9bdd0b1
Compare
src/selector.rs
Outdated
/// Do branch-and-bound selection with `LowestFee` metric. | ||
pub fn select_for_lowest_fee( | ||
&mut self, | ||
longterm_feerate: FeeRate, | ||
max_bnb_rounds: usize, | ||
) -> Result<Ordf32, NoBnbSolution> { | ||
self.inner.run_bnb( | ||
LowestFee { | ||
target: self.target, | ||
long_term_feerate: cs_feerate(longterm_feerate), | ||
change_policy: self.change_policy, | ||
}, | ||
max_bnb_rounds, | ||
) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this and have select_with_algorithm
where algorithm
is a closure.
Having a payjoin example here will be nice. Refer to: bitcoindevkit/bdk#913 (comment) |
While reviewing the PR, I noticed that Signer struct wrapper over the Currently What do you think @evanlinjin ? |
@KnowWhoami brings up a good point. In fact our implementation really boils down to an implementation of |
tests/synopsis.rs
Outdated
.after(absolute::LockTime::from_height(tip.height).expect("must be valid height")) | ||
.add({ | ||
let mut pks = vec![]; | ||
for (_, desc) in index.keychains() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
for (_, desc) in index.keychains() { | |
for (_, desc) in self.graph.index.keychains() { |
Since the above created index
variable is used once -> so it's better to write self.graph.index
at the caller site..
6b92cdd
to
4b2ff5d
Compare
- Moved `synopsis.rs` to examples dir - Added `examples/common.rs` to contain the example wallet - Update README to link to the examples
Change functions that return Option to return a Result instead which makes for better error handling. Added - `FromPsbtInputError` - `CoinbaseMismatch` - `CannotMeetTarget` - `SelectorError` - `GetForeignUnspentError` - `ExtractReplacementsError`
Include the check for `final_script_sig` when evaluating whether the input is finalized.
4b2ff5d
to
0e4a4a6
Compare
I realized that in 386bdae pin-msrv.sh was not given executable permissions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 0e4a4a6
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self-ACK c806d5e
Rationale
There were many problems with the design of the old
TxBuilder
currently residing inbdk_wallet
.TxParams
struct.Rewriting the
TxBuilder
and decoupling it frombdk_wallet
allows us to:bdk_wallet
.bdk_wallet v2.0
to ship these fixes/improvements.Proposed Repository Layout
I propose turning this repo into a Cargo workspace, containing the following crates:
bdk_tx_core
- This will contain the coreInput
,InputGroup
types (and maybe more). Bothbdk_chain
andbdk_wallet
would only need to output these types to interoperate with the rest of the tx-building crates. These types are expected to be relatively stable, with most changes being non-breaking.bdk_tx
- Handles the coin selection + psbt creation/signing/finalization. @nymius suggested splitting coin selection into its own crate, but I'm not fully convinced that's necessary (for now).bdk_coin_select
- It would be convenient to move this crate into the workspace for easier development.bdk_coin_control
- ContainsCoinControl
. This is the only crate in the workspace that depends onbdk_chain
andbdk_core
. It handles canonicalization and ensures the caller does not provide a bad set of input candidates (cc. @stevenroose).Where to Start Reviewing?
Start with
tests/synopsis.rs
- For now, it's more of an example than a test.It includes:
These examples demonstrate how the various types in the library interact across the different stages of transaction building.
How can I help?
The main architecture/flow is complete.
However, there are still a whole bunch of TODOs scattered over the codebase and should be done before merging. These TODOs be summarized as follows (these should be done before merging):
Option
s when they should return custom error enums with variants. It is helpful to know why something failed.tests/synopsis.rs
should be moves to aexamples
folder. TheWallet
type should be contained inexamples/common/mod.rs
so that it can be shared across examples. chore: Add examples directory evanlinjin/bdk-tx#5This is enough to get a merge and get users to start using/testing.
To help:
evanlinjin/bdk-tx
).How long would it take for this to be stable?
Without any hold-backs, and multiple contributors, I think 2 months is a reasonable time.