-
Notifications
You must be signed in to change notification settings - Fork 387
Add support for custom sorting and deprecate BIP69 #556
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,11 +36,14 @@ | |
//! # Ok::<(), bdk::Error>(()) | ||
//! ``` | ||
|
||
use std::cmp::Ordering; | ||
use std::collections::BTreeMap; | ||
use std::collections::HashSet; | ||
use std::default::Default; | ||
use std::marker::PhantomData; | ||
use std::sync::Arc; | ||
|
||
use bitcoin::blockdata::transaction::{TxIn, TxOut}; | ||
use bitcoin::util::psbt::{self, PartiallySignedTransaction as Psbt}; | ||
use bitcoin::{OutPoint, Script, SigHashType, Transaction}; | ||
|
||
|
@@ -646,14 +649,22 @@ impl<'a, B, D: BatchDatabase> TxBuilder<'a, B, D, DefaultCoinSelectionAlgorithm, | |
} | ||
|
||
/// Ordering of the transaction's inputs and outputs | ||
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)] | ||
#[derive(Clone)] | ||
pub enum TxOrdering { | ||
/// Randomized (default) | ||
Shuffle, | ||
/// Unchanged | ||
Untouched, | ||
/// BIP69 / Lexicographic | ||
#[deprecated = "BIP69 does not improve privacy as was the intention of the BIP"] | ||
Bip69Lexicographic, | ||
/// Provide custom comparison functions for sorting | ||
Custom { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we may have to add some sort of "state" here, something that the two functions could look at to know what to do essentially. It doesn't have to be mutable, that would mess a lot of this up. If we don't wanna add generic types we could maybe add a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CC @LLFourn who proposed sorting with a shared secret. I think you would not be able to do that, unless you introduce this state. I'm not sure what happens if you try borrowing from local variables in the two There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @fadedcoder can you write a doc comment or a test which maybe demos how to use a secret to hash the input/output to produce the key? Given the awkward
Just There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For some reason I always instinctively think that So yeah, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah sure, I'll add some tests or examples soon! |
||
/// Transaction inputs sort function | ||
input_sort: Arc<dyn Fn(&TxIn, &TxIn) -> Ordering>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very minor nit, but this confused me for a second: I would just import For a second I confused |
||
/// Transaction outputs sort function | ||
output_sort: Arc<dyn Fn(&TxOut, &TxOut) -> Ordering>, | ||
}, | ||
} | ||
|
||
impl Default for TxOrdering { | ||
|
@@ -662,6 +673,18 @@ impl Default for TxOrdering { | |
} | ||
} | ||
|
||
impl std::fmt::Debug for TxOrdering { | ||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | ||
match self { | ||
TxOrdering::Shuffle => write!(f, "Randomized"), | ||
TxOrdering::Untouched => write!(f, "Unchanged"), | ||
#[allow(deprecated)] | ||
TxOrdering::Bip69Lexicographic => write!(f, "BIP69 / Lexicographic"), | ||
TxOrdering::Custom { .. } => write!(f, "Custom"), | ||
} | ||
} | ||
} | ||
|
||
impl TxOrdering { | ||
/// Sort transaction inputs and outputs by [`TxOrdering`] variant | ||
pub fn sort_tx(&self, tx: &mut Transaction) { | ||
|
@@ -679,13 +702,21 @@ impl TxOrdering { | |
|
||
tx.output.shuffle(&mut rng); | ||
} | ||
#[allow(deprecated)] | ||
TxOrdering::Bip69Lexicographic => { | ||
tx.input.sort_unstable_by_key(|txin| { | ||
(txin.previous_output.txid, txin.previous_output.vout) | ||
}); | ||
tx.output | ||
.sort_unstable_by_key(|txout| (txout.value, txout.script_pubkey.clone())); | ||
} | ||
TxOrdering::Custom { | ||
input_sort, | ||
output_sort, | ||
} => { | ||
tx.input.sort_unstable_by(|a, b| input_sort(a, b)); | ||
tx.output.sort_unstable_by(|a, b| output_sort(a, b)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 I think you want |
||
} | ||
} | ||
} | ||
} | ||
|
@@ -769,7 +800,7 @@ mod test { | |
|
||
#[test] | ||
fn test_output_ordering_default_shuffle() { | ||
assert_eq!(TxOrdering::default(), TxOrdering::Shuffle); | ||
assert!(std::matches!(TxOrdering::default(), TxOrdering::Shuffle)); | ||
} | ||
|
||
#[test] | ||
|
@@ -800,6 +831,7 @@ mod test { | |
let original_tx = ordering_test_tx!(); | ||
let mut tx = original_tx; | ||
|
||
#[allow(deprecated)] | ||
TxOrdering::Bip69Lexicographic.sort_tx(&mut tx); | ||
|
||
assert_eq!( | ||
|
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 don't know if we can, but if possible I would add a link to the discussion here on github. Maybe you could make a multiline warning, first line stays the same, and in a new line something like "To know more read the discussion at: ...".
Similar to what the rust compiler does when you have an error.
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.
@afilini Can you give me an example in the rust lang? I can just look at their source code and implement the same way.
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 meant something like:
I like that "note: see issue ..." at the end