[wallet] Add RBF and custom versions in TxBuilder
This commit is contained in:
parent
0665c9e854
commit
85090a28eb
@ -135,9 +135,36 @@ where
|
|||||||
policy.get_requirements(builder.policy_path.as_ref().unwrap_or(&BTreeMap::new()))?;
|
policy.get_requirements(builder.policy_path.as_ref().unwrap_or(&BTreeMap::new()))?;
|
||||||
debug!("requirements: {:?}", requirements);
|
debug!("requirements: {:?}", requirements);
|
||||||
|
|
||||||
|
let version = match builder.version {
|
||||||
|
tx_builder::Version(0) => return Err(Error::Generic("Invalid version `0`".into())),
|
||||||
|
tx_builder::Version(1) if requirements.csv.is_some() => {
|
||||||
|
return Err(Error::Generic(
|
||||||
|
"TxBuilder requested version `1`, but at least `2` is needed to use OP_CSV"
|
||||||
|
.into(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
tx_builder::Version(x) => x,
|
||||||
|
};
|
||||||
|
|
||||||
|
let lock_time = match builder.locktime {
|
||||||
|
None => requirements.timelock.unwrap_or(0),
|
||||||
|
Some(x) if requirements.timelock.is_none() => x,
|
||||||
|
Some(x) if requirements.timelock.unwrap() <= x => x,
|
||||||
|
Some(x) => return Err(Error::Generic(format!("TxBuilder requested timelock of `{}`, but at least `{}` is required to spend from this script", x, requirements.timelock.unwrap())))
|
||||||
|
};
|
||||||
|
|
||||||
|
let n_sequence = match (builder.rbf, requirements.csv) {
|
||||||
|
(None, Some(csv)) => csv,
|
||||||
|
(Some(rbf), Some(csv)) if rbf < csv => return Err(Error::Generic(format!("Cannot enable RBF with nSequence `{}`, since at least `{}` is required to spend with OP_CSV", rbf, csv))),
|
||||||
|
(None, _) if requirements.timelock.is_some() => 0xFFFFFFFE,
|
||||||
|
(Some(rbf), _) if rbf >= 0xFFFFFFFE => return Err(Error::Generic("Cannot enable RBF with anumber >= 0xFFFFFFFE".into())),
|
||||||
|
(Some(rbf), _) => rbf,
|
||||||
|
(None, _) => 0xFFFFFFFF,
|
||||||
|
};
|
||||||
|
|
||||||
let mut tx = Transaction {
|
let mut tx = Transaction {
|
||||||
version: 2,
|
version,
|
||||||
lock_time: requirements.timelock.unwrap_or(0),
|
lock_time,
|
||||||
input: vec![],
|
input: vec![],
|
||||||
output: vec![],
|
output: vec![],
|
||||||
};
|
};
|
||||||
@ -206,11 +233,6 @@ where
|
|||||||
)?;
|
)?;
|
||||||
let (mut txin, prev_script_pubkeys): (Vec<_>, Vec<_>) = txin.into_iter().unzip();
|
let (mut txin, prev_script_pubkeys): (Vec<_>, Vec<_>) = txin.into_iter().unzip();
|
||||||
|
|
||||||
let n_sequence = match requirements.csv {
|
|
||||||
Some(csv) => csv,
|
|
||||||
_ if requirements.timelock.is_some() => 0xFFFFFFFE,
|
|
||||||
_ => 0xFFFFFFFF,
|
|
||||||
};
|
|
||||||
txin.iter_mut().for_each(|i| i.sequence = n_sequence);
|
txin.iter_mut().for_each(|i| i.sequence = n_sequence);
|
||||||
tx.input = txin;
|
tx.input = txin;
|
||||||
|
|
||||||
|
@ -18,6 +18,8 @@ pub struct TxBuilder<Cs: CoinSelectionAlgorithm> {
|
|||||||
pub(crate) sighash: Option<SigHashType>,
|
pub(crate) sighash: Option<SigHashType>,
|
||||||
pub(crate) ordering: TxOrdering,
|
pub(crate) ordering: TxOrdering,
|
||||||
pub(crate) locktime: Option<u32>,
|
pub(crate) locktime: Option<u32>,
|
||||||
|
pub(crate) rbf: Option<u32>,
|
||||||
|
pub(crate) version: Version,
|
||||||
pub(crate) coin_selection: Cs,
|
pub(crate) coin_selection: Cs,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,6 +94,20 @@ impl<Cs: CoinSelectionAlgorithm> TxBuilder<Cs> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn enable_rbf(self) -> Self {
|
||||||
|
self.enable_rbf_with_sequence(0xFFFFFFFD)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enable_rbf_with_sequence(mut self, nsequence: u32) -> Self {
|
||||||
|
self.rbf = Some(nsequence);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn version(mut self, version: u32) -> Self {
|
||||||
|
self.version = Version(version);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn coin_selection<P: CoinSelectionAlgorithm>(self, coin_selection: P) -> TxBuilder<P> {
|
pub fn coin_selection<P: CoinSelectionAlgorithm>(self, coin_selection: P) -> TxBuilder<P> {
|
||||||
TxBuilder {
|
TxBuilder {
|
||||||
addressees: self.addressees,
|
addressees: self.addressees,
|
||||||
@ -103,6 +119,8 @@ impl<Cs: CoinSelectionAlgorithm> TxBuilder<Cs> {
|
|||||||
sighash: self.sighash,
|
sighash: self.sighash,
|
||||||
ordering: self.ordering,
|
ordering: self.ordering,
|
||||||
locktime: self.locktime,
|
locktime: self.locktime,
|
||||||
|
rbf: self.rbf,
|
||||||
|
version: self.version,
|
||||||
coin_selection,
|
coin_selection,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,6 +166,16 @@ impl TxOrdering {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper type that wraps u32 and has a default value of 1
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct Version(pub(crate) u32);
|
||||||
|
|
||||||
|
impl Default for Version {
|
||||||
|
fn default() -> Self {
|
||||||
|
Version(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
const ORDERING_TEST_TX: &'static str = "0200000003c26f3eb7932f7acddc5ddd26602b77e7516079b03090a16e2c2f54\
|
const ORDERING_TEST_TX: &'static str = "0200000003c26f3eb7932f7acddc5ddd26602b77e7516079b03090a16e2c2f54\
|
||||||
|
Loading…
x
Reference in New Issue
Block a user