- 
                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
TxBuildercurrently residing inbdk_wallet.TxParamsstruct.Rewriting the
TxBuilderand decoupling it frombdk_walletallows us to:bdk_wallet.bdk_wallet v2.0to 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,InputGrouptypes (and maybe more). Bothbdk_chainandbdk_walletwould 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_chainandbdk_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):
Options when they should return custom error enums with variants. It is helpful to know why something failed.tests/synopsis.rsshould be moves to aexamplesfolder. TheWallettype should be contained inexamples/common/mod.rsso 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.