-
Notifications
You must be signed in to change notification settings - Fork 45
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
Add TxBuilder APIs #611
Add TxBuilder APIs #611
Changes from 3 commits
c6cbfb9
cfc0308
99adbf7
465dbeb
d0bec77
ee80d5d
4f702eb
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 |
---|---|---|
@@ -1,20 +1,23 @@ | ||
use crate::bitcoin::Psbt; | ||
use crate::error::CreateTxError; | ||
use crate::types::ScriptAmount; | ||
use crate::types::{LockTime, ScriptAmount}; | ||
use crate::wallet::Wallet; | ||
|
||
use bdk_wallet::KeychainKind; | ||
use bitcoin_ffi::{Amount, FeeRate, Script}; | ||
|
||
use bdk_wallet::bitcoin::absolute::LockTime as BdkLockTime; | ||
use bdk_wallet::bitcoin::amount::Amount as BdkAmount; | ||
use bdk_wallet::bitcoin::script::PushBytesBuf; | ||
use bdk_wallet::bitcoin::Psbt as BdkPsbt; | ||
use bdk_wallet::bitcoin::ScriptBuf as BdkScriptBuf; | ||
use bdk_wallet::bitcoin::{OutPoint, Sequence, Txid}; | ||
use bdk_wallet::ChangeSpendPolicy; | ||
use bdk_wallet::KeychainKind; | ||
|
||
use std::collections::BTreeMap; | ||
use std::collections::HashMap; | ||
use std::collections::HashSet; | ||
use std::convert::{TryFrom, TryInto}; | ||
use std::str::FromStr; | ||
use std::sync::Arc; | ||
|
||
|
@@ -33,6 +36,9 @@ pub struct TxBuilder { | |
pub(crate) drain_wallet: bool, | ||
pub(crate) drain_to: Option<BdkScriptBuf>, | ||
pub(crate) sequence: Option<u32>, | ||
pub(crate) data: Vec<u8>, | ||
pub(crate) current_height: Option<u32>, | ||
pub(crate) locktime: Option<LockTime>, | ||
} | ||
|
||
impl TxBuilder { | ||
|
@@ -51,6 +57,9 @@ impl TxBuilder { | |
drain_wallet: false, | ||
drain_to: None, | ||
sequence: None, | ||
data: Vec::new(), | ||
current_height: None, | ||
locktime: None, | ||
} | ||
} | ||
|
||
|
@@ -193,6 +202,27 @@ impl TxBuilder { | |
}) | ||
} | ||
|
||
pub(crate) fn add_data(&self, data: Vec<u8>) -> Arc<Self> { | ||
Arc::new(TxBuilder { | ||
data, | ||
..self.clone() | ||
}) | ||
} | ||
|
||
pub(crate) fn current_height(&self, height: u32) -> Arc<Self> { | ||
Arc::new(TxBuilder { | ||
current_height: Some(height), | ||
..self.clone() | ||
}) | ||
} | ||
|
||
pub(crate) fn nlocktime(&self, locktime: LockTime) -> Arc<Self> { | ||
Arc::new(TxBuilder { | ||
locktime: Some(locktime), | ||
..self.clone() | ||
}) | ||
} | ||
|
||
Comment on lines
+223
to
+229
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. looks great, wrote a test and passed ✅ |
||
pub(crate) fn finish(&self, wallet: &Arc<Wallet>) -> Result<Arc<Psbt>, CreateTxError> { | ||
// TODO: I had to change the wallet here to be mutable. Why is that now required with the 1.0 API? | ||
let mut wallet = wallet.get_wallet(); | ||
|
@@ -237,6 +267,18 @@ impl TxBuilder { | |
if let Some(sequence) = self.sequence { | ||
tx_builder.set_exact_sequence(Sequence(sequence)); | ||
} | ||
if !&self.data.is_empty() { | ||
let push_bytes = PushBytesBuf::try_from(self.data.clone())?; | ||
tx_builder.add_data(&push_bytes); | ||
} | ||
Comment on lines
+288
to
+291
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'm reviewing these commit by commit as recommended, and for this
and I couldn't get
in the Thoughts? I could totally be missing something though. Also let me know if adding the specific implementation of my tests is helpful too. 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. Personally, I don't think 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.
Def agree with this 100%. I just happened to be running into an issue with it when I was coming up with test to test what happened when I gave it data exceeding that limit. But maybe I wrote my test incorrectly, will double back and look at it again 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. There is no check on the Rust side and currently it will allow for invalid OP_RETURN data 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. Looking back at my test the other thing that played into the way I wrote it was how I approached non-standard transactions. 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.
Thanks for this! I didn't see it before I wrote:
I'm actually really interested in where we land on this conversation even if for the time being overall we end up at this place you mentioned rob:
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 enforcing standardness will come with bitcoindevkit/bdk#1726. I agree we should not have logic handling standardness here, and leave it to bdk_wallet (or rust-bitcoin when your patch is merged @rob, however that shakes out). This was already a (somewhat) faulty API in the 0.32.0 release, and IMO people using it will just have to know how it works if they want to build relayable transactions (just like it was in bdk_wallet <= beta.5). The fix in beta 6 or the final 1.0 release will enforce standardness. |
||
if let Some(height) = self.current_height { | ||
tx_builder.current_height(height); | ||
} | ||
// let bdk_locktime = locktime.try_into().map_err(CreateTxError::LockTimeConversionError)?; | ||
if let Some(locktime) = &self.locktime { | ||
let bdk_locktime: BdkLockTime = locktime.try_into()?; | ||
tx_builder.nlocktime(bdk_locktime); | ||
} | ||
|
||
let psbt = tx_builder.finish().map_err(CreateTxError::from)?; | ||
|
||
|
@@ -249,14 +291,18 @@ pub(crate) struct BumpFeeTxBuilder { | |
pub(crate) txid: String, | ||
pub(crate) fee_rate: Arc<FeeRate>, | ||
pub(crate) sequence: Option<u32>, | ||
pub(crate) current_height: Option<u32>, | ||
pub(crate) locktime: Option<LockTime>, | ||
} | ||
|
||
impl BumpFeeTxBuilder { | ||
pub(crate) fn new(txid: String, fee_rate: Arc<FeeRate>) -> Self { | ||
Self { | ||
BumpFeeTxBuilder { | ||
txid, | ||
fee_rate, | ||
sequence: None, | ||
current_height: None, | ||
locktime: None, | ||
} | ||
} | ||
|
||
|
@@ -267,6 +313,20 @@ impl BumpFeeTxBuilder { | |
}) | ||
} | ||
|
||
pub(crate) fn current_height(&self, height: u32) -> Arc<Self> { | ||
Arc::new(BumpFeeTxBuilder { | ||
current_height: Some(height), | ||
..self.clone() | ||
}) | ||
} | ||
|
||
pub(crate) fn nlocktime(&self, locktime: LockTime) -> Arc<Self> { | ||
Arc::new(BumpFeeTxBuilder { | ||
locktime: Some(locktime), | ||
..self.clone() | ||
}) | ||
} | ||
|
||
pub(crate) fn finish(&self, wallet: &Arc<Wallet>) -> Result<Arc<Psbt>, CreateTxError> { | ||
let txid = Txid::from_str(self.txid.as_str()).map_err(|_| CreateTxError::UnknownUtxo { | ||
outpoint: self.txid.clone(), | ||
|
@@ -277,6 +337,13 @@ impl BumpFeeTxBuilder { | |
if let Some(sequence) = self.sequence { | ||
tx_builder.set_exact_sequence(Sequence(sequence)); | ||
} | ||
if let Some(height) = self.current_height { | ||
tx_builder.current_height(height); | ||
} | ||
if let Some(locktime) = &self.locktime { | ||
let bdk_locktime: BdkLockTime = locktime.try_into()?; | ||
tx_builder.nlocktime(bdk_locktime); | ||
} | ||
|
||
let psbt: BdkPsbt = tx_builder.finish()?; | ||
|
||
|
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.
reviewing commit by commit, this looks good, I wrote a test for it and it passed ✅
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.
You sir are building good tests. Do you want to maybe add them as a commit to this PR? I'd merge that for sure.