diff --git a/Cargo.toml b/Cargo.toml index 150e41d2e..104557b7c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,17 +15,17 @@ compiler = [] trace = [] unstable = [] default = [] -use-serde = ["serde", "bitcoin/use-serde"] +use-serde = ["serde", "bitcoin/serde"] rand = ["bitcoin/rand"] [dependencies] -bitcoin = "0.28.0" +bitcoin = { git = "https://github.com/tcharding/rust-bitcoin", branch = "05-17-timelock" } serde = { version = "1.0", optional = true} [dev-dependencies] bitcoind = {version = "0.26.1", features=["22_0"]} actual-rand = { package = "rand", version = "0.8.4"} -bitcoin = { version = "0.28", features = ["rand"]} +bitcoin = { git = "https://github.com/tcharding/rust-bitcoin", branch = "05-17-timelock", features = ["rand"] } [[example]] name = "htlc" diff --git a/examples/sign_multisig.rs b/examples/sign_multisig.rs index 5c58bf5d2..a6d7b0cf1 100644 --- a/examples/sign_multisig.rs +++ b/examples/sign_multisig.rs @@ -18,7 +18,7 @@ use std::collections::HashMap; use std::str::FromStr; use bitcoin::blockdata::witness::Witness; -use bitcoin::secp256k1; +use bitcoin::{secp256k1, LockTime}; fn main() { let mut tx = spending_transaction(); @@ -91,7 +91,7 @@ fn main() { fn spending_transaction() -> bitcoin::Transaction { bitcoin::Transaction { version: 2, - lock_time: 0, + lock_time: LockTime::from(0), input: vec![bitcoin::TxIn { previous_output: Default::default(), script_sig: bitcoin::Script::new(), diff --git a/examples/verify_tx.rs b/examples/verify_tx.rs index dd8cc75ff..bc842e514 100644 --- a/examples/verify_tx.rs +++ b/examples/verify_tx.rs @@ -16,6 +16,7 @@ use std::str::FromStr; +use bitcoin::LockTime; use bitcoin::consensus::Decodable; use bitcoin::secp256k1::{self, Secp256k1}; use bitcoin::util::sighash; @@ -33,7 +34,7 @@ fn main() { &spk_input_1, &tx.input[0].script_sig, &tx.input[0].witness, - 0, + LockTime::from(0), 0, ) .unwrap(); diff --git a/src/descriptor/tr.rs b/src/descriptor/tr.rs index 9b063cff1..23db573e2 100644 --- a/src/descriptor/tr.rs +++ b/src/descriptor/tr.rs @@ -262,6 +262,7 @@ impl Tr { TaprootBuilderError::EmptyTree => { unreachable!("Taptree is a well formed tree with atleast 1 element") } + _ => panic!("Unknown error, non_exhaustive catch all"), }, } }; diff --git a/src/interpreter/error.rs b/src/interpreter/error.rs index f4e840f9c..313512355 100644 --- a/src/interpreter/error.rs +++ b/src/interpreter/error.rs @@ -26,6 +26,8 @@ use super::BitcoinKey; pub enum Error { /// Could not satisfy, absolute locktime not met AbsoluteLocktimeNotMet(u32), + /// Could not satisfy, lock time values are different units + AbsoluteLocktimeComparisonInvalid(u32, u32), /// Cannot Infer a taproot descriptor /// Key spends cannot infer the internal key of the descriptor /// Inferring script spends is possible, but is hidden nodes are currently @@ -188,6 +190,7 @@ impl fmt::Display for Error { Error::VerifyFailed => { f.write_str("Expected Satisfied Boolean at stack top for VERIFY") } + _ => f.write_str("Unknown error, non_exhaustive catch all"), } } } @@ -234,6 +237,7 @@ impl error::Error for Error { Secp(e) => Some(e), SchnorrSig(e) => Some(e), SighashError(e) => Some(e), + _ => None // non_exhaustive catch all. } } } diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 20a9fc52b..5a31d28b5 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -26,7 +26,7 @@ use std::str::FromStr; use bitcoin::blockdata::witness::Witness; use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d}; use bitcoin::util::{sighash, taproot}; -use bitcoin::{self, secp256k1, TxOut}; +use bitcoin::{self, secp256k1, TxOut, LockTime}; use crate::miniscript::context::NoChecks; use crate::miniscript::ScriptContext; @@ -48,7 +48,7 @@ pub struct Interpreter<'txin> { /// For non-Taproot spends, the scriptCode; for Taproot script-spends, this /// is the leaf script; for key-spends it is `None`. script_code: Option, - age: u32, + age: LockTime, height: u32, } @@ -169,7 +169,7 @@ impl<'txin> Interpreter<'txin> { spk: &bitcoin::Script, script_sig: &'txin bitcoin::Script, witness: &'txin Witness, - age: u32, + age: LockTime, height: u32, ) -> Result { let (inner, stack, script_code) = inner::from_txdata(spk, script_sig, witness)?; @@ -492,7 +492,7 @@ pub enum SatisfiedConstraint { ///Absolute Timelock for CLTV. AbsoluteTimelock { /// The value of Absolute timelock - time: u32, + time: LockTime, }, } @@ -527,7 +527,7 @@ pub struct Iter<'intp, 'txin: 'intp> { public_key: Option<&'intp BitcoinKey>, state: Vec>, stack: Stack<'txin>, - age: u32, + age: LockTime, height: u32, has_errored: bool, } @@ -1130,7 +1130,7 @@ mod tests { n_evaluated: 0, n_satisfied: 0, }], - age: 1002, + age: LockTime::from(1002), height: 1002, has_errored: false, } @@ -1197,7 +1197,7 @@ mod tests { let after_satisfied: Result, Error> = constraints.collect(); assert_eq!( after_satisfied.unwrap(), - vec![SatisfiedConstraint::AbsoluteTimelock { time: 1000 }] + vec![SatisfiedConstraint::AbsoluteTimelock { time: LockTime::from(1000) }] ); //Check Older diff --git a/src/interpreter/stack.rs b/src/interpreter/stack.rs index a31d56e3f..cd4d821b2 100644 --- a/src/interpreter/stack.rs +++ b/src/interpreter/stack.rs @@ -17,6 +17,7 @@ use bitcoin; use bitcoin::blockdata::{opcodes, script}; use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash}; +use bitcoin::{locktime, LockTime}; use super::error::PkEvalErrInner; use super::{ @@ -230,14 +231,16 @@ impl<'txin> Stack<'txin> { /// booleans pub(super) fn evaluate_after( &mut self, - n: &u32, - age: u32, + n: &LockTime, + age: LockTime, ) -> Option> { - if age >= *n { - self.push(Element::Satisfied); - Some(Ok(SatisfiedConstraint::AbsoluteTimelock { time: *n })) - } else { - Some(Err(Error::AbsoluteLocktimeNotMet(*n))) + match locktime::is_satisfied(*n, age) { + Ok(true) => { + self.push(Element::Satisfied); + Some(Ok(SatisfiedConstraint::AbsoluteTimelock { time: *n })) + }, + Ok(false) => Some(Err(Error::AbsoluteLocktimeNotMet(n.to_u32()))), + Err(_) => Some(Err(Error::AbsoluteLocktimeComparisonInvalid(n.to_u32(), age.to_u32()))), } } diff --git a/src/lib.rs b/src/lib.rs index e2aa7973a..65a7e7e63 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -104,7 +104,6 @@ pub mod interpreter; pub mod miniscript; pub mod policy; pub mod psbt; -pub mod timelock; mod util; diff --git a/src/miniscript/astelem.rs b/src/miniscript/astelem.rs index ea5c2d30c..d8ce1cc23 100644 --- a/src/miniscript/astelem.rs +++ b/src/miniscript/astelem.rs @@ -23,6 +23,7 @@ use std::str::FromStr; use std::sync::Arc; use std::{fmt, str}; +use bitcoin::LockTime; use bitcoin::blockdata::{opcodes, script}; use bitcoin::hashes::hex::FromHex; use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash}; @@ -491,7 +492,7 @@ where expression::terminal(&top.args[0], |x| Pk::Hash::from_str(x).map(Terminal::PkH)) } ("after", 1) => expression::terminal(&top.args[0], |x| { - expression::parse_num(x).map(Terminal::After) + expression::parse_num(x).map(|x| Terminal::After(LockTime::from(x))) }), ("older", 1) => expression::terminal(&top.args[0], |x| { expression::parse_num(x).map(Terminal::Older) @@ -653,7 +654,7 @@ impl Terminal { .push_slice(&Pk::hash_to_hash160(hash)[..]) .push_opcode(opcodes::all::OP_EQUALVERIFY), Terminal::After(t) => builder - .push_int(t as i64) + .push_int(t.to_u32() as i64) .push_opcode(opcodes::all::OP_CLTV), Terminal::Older(t) => builder.push_int(t as i64).push_opcode(opcodes::all::OP_CSV), Terminal::Sha256(h) => builder @@ -788,7 +789,7 @@ impl Terminal { match *self { Terminal::PkK(ref pk) => Ctx::pk_len(pk), Terminal::PkH(..) => 24, - Terminal::After(n) => script_num_size(n as usize) + 1, + Terminal::After(n) => script_num_size(n.to_u32() as usize) + 1, Terminal::Older(n) => script_num_size(n as usize) + 1, Terminal::Sha256(..) => 33 + 6, Terminal::Hash256(..) => 33 + 6, diff --git a/src/miniscript/decode.rs b/src/miniscript/decode.rs index b137f535e..b4612e49c 100644 --- a/src/miniscript/decode.rs +++ b/src/miniscript/decode.rs @@ -26,6 +26,7 @@ use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash}; use crate::miniscript::lex::{Token as Tk, TokenIter}; use crate::miniscript::limits::MAX_PUBKEYS_PER_MULTISIG; +use crate::bitcoin::locktime::LockTime; use crate::miniscript::types::extra_props::ExtData; use crate::miniscript::types::{Property, Type}; use crate::miniscript::ScriptContext; @@ -133,7 +134,7 @@ pub enum Terminal { PkH(Pk::Hash), // timelocks /// `n CHECKLOCKTIMEVERIFY` - After(u32), + After(LockTime), /// `n CHECKSEQUENCEVERIFY` Older(u32), // hashlocks @@ -388,7 +389,7 @@ pub fn parse( Tk::CheckSequenceVerify, Tk::Num(n) => term.reduce0(Terminal::Older(n))?, Tk::CheckLockTimeVerify, Tk::Num(n) - => term.reduce0(Terminal::After(n))?, + => term.reduce0(Terminal::After(LockTime::from(n)))?, // hashlocks Tk::Equal => match_token!( tokens, diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index 559f0e286..93fe12875 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -978,7 +978,7 @@ mod tests { )); assert_eq!( ms.unwrap_err().to_string(), - "unexpected «Key hex decoding error: bad hex string length 64 (expected 66)»" + "unexpected «key hex decoding error»" ); Tapscript::from_str_insane(&format!( "pk(2788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99)" diff --git a/src/miniscript/satisfy.rs b/src/miniscript/satisfy.rs index deb547ea1..b542c32ed 100644 --- a/src/miniscript/satisfy.rs +++ b/src/miniscript/satisfy.rs @@ -22,13 +22,13 @@ use std::collections::{BTreeMap, HashMap}; use std::sync::Arc; use std::{cmp, i64, mem}; -use bitcoin; +use bitcoin::LockTime; use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d}; use bitcoin::secp256k1::XOnlyPublicKey; use bitcoin::util::taproot::{ControlBlock, LeafVersion, TapLeafHash}; use crate::miniscript::limits::{ - LOCKTIME_THRESHOLD, SEQUENCE_LOCKTIME_DISABLE_FLAG, SEQUENCE_LOCKTIME_TYPE_FLAG, + SEQUENCE_LOCKTIME_DISABLE_FLAG, SEQUENCE_LOCKTIME_TYPE_FLAG, }; use crate::util::witness_size; use crate::{Miniscript, MiniscriptKey, ScriptContext, Terminal, ToPublicKey}; @@ -115,7 +115,7 @@ pub trait Satisfier { } /// Assert whether a absolute locktime is satisfied - fn check_after(&self, _: u32) -> bool { + fn check_after(&self, _: LockTime) -> bool { false } } @@ -148,21 +148,6 @@ impl Satisfier for Older { } } -/// Newtype around `u32` which implements `Satisfier` using `n` as an -/// absolute locktime -pub struct After(pub u32); - -impl Satisfier for After { - fn check_after(&self, n: u32) -> bool { - // if n > self.0; we will be returning false anyways - if n < LOCKTIME_THRESHOLD && self.0 >= LOCKTIME_THRESHOLD { - false - } else { - n <= self.0 - } - } -} - impl Satisfier for HashMap { fn lookup_ecdsa_sig(&self, key: &Pk) -> Option { self.get(key).copied() @@ -277,7 +262,7 @@ impl<'a, Pk: MiniscriptKey + ToPublicKey, S: Satisfier> Satisfier for &' (**self).check_older(t) } - fn check_after(&self, t: u32) -> bool { + fn check_after(&self, t: LockTime) -> bool { (**self).check_after(t) } } @@ -339,7 +324,7 @@ impl<'a, Pk: MiniscriptKey + ToPublicKey, S: Satisfier> Satisfier for &' (**self).check_older(t) } - fn check_after(&self, t: u32) -> bool { + fn check_after(&self, t: LockTime) -> bool { (**self).check_after(t) } } @@ -483,7 +468,7 @@ macro_rules! impl_tuple_satisfier { false } - fn check_after(&self, n: u32) -> bool { + fn check_after(&self, n: LockTime) -> bool { let &($(ref $ty,)*) = self; $( if $ty.check_after(n) { diff --git a/src/miniscript/types/extra_props.rs b/src/miniscript/types/extra_props.rs index b6f396a7c..b73874b38 100644 --- a/src/miniscript/types/extra_props.rs +++ b/src/miniscript/types/extra_props.rs @@ -4,10 +4,12 @@ use std::cmp; use std::iter::once; +use bitcoin::LockTime; + use super::{Error, ErrorKind, Property, ScriptContext}; use crate::miniscript::context::SigType; use crate::miniscript::limits::{ - LOCKTIME_THRESHOLD, SEQUENCE_LOCKTIME_DISABLE_FLAG, SEQUENCE_LOCKTIME_TYPE_FLAG, + SEQUENCE_LOCKTIME_DISABLE_FLAG, SEQUENCE_LOCKTIME_TYPE_FLAG, }; use crate::{script_num_size, MiniscriptKey, Terminal}; @@ -337,9 +339,9 @@ impl Property for ExtData { unreachable!() } - fn from_after(t: u32) -> Self { + fn from_after(t: LockTime) -> Self { ExtData { - pk_cost: script_num_size(t as usize) + 1, + pk_cost: script_num_size(t.to_u32() as usize) + 1, has_free_verify: false, ops: OpLimits::new(1, Some(0), None), stack_elem_count_sat: Some(0), @@ -349,8 +351,8 @@ impl Property for ExtData { timelock_info: TimelockInfo { csv_with_height: false, csv_with_time: false, - cltv_with_height: t < LOCKTIME_THRESHOLD, - cltv_with_time: t >= LOCKTIME_THRESHOLD, + cltv_with_height: t.is_height(), + cltv_with_time: t.is_time(), contains_combination: false, }, exec_stack_elem_count_sat: Some(1), // @@ -933,7 +935,7 @@ impl Property for ExtData { // Note that for CLTV this is a limitation not of Bitcoin but Miniscript. The // number on the stack would be a 5 bytes signed integer but Miniscript's B type // only consumes 4 bytes from the stack. - if t == 0 || (t & SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0 { + if t.to_u32() == 0 || (t.to_u32() & SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0 { return Err(Error { fragment: fragment.clone(), error: ErrorKind::InvalidTime, diff --git a/src/miniscript/types/mod.rs b/src/miniscript/types/mod.rs index 728a4abcc..ab4bb580a 100644 --- a/src/miniscript/types/mod.rs +++ b/src/miniscript/types/mod.rs @@ -22,6 +22,8 @@ pub mod malleability; use std::{error, fmt}; +use bitcoin::LockTime; + pub use self::correctness::{Base, Correctness, Input}; pub use self::extra_props::ExtData; pub use self::malleability::{Dissat, Malleability}; @@ -300,8 +302,8 @@ pub trait Property: Sized { /// Type property of an absolute timelock. Default implementation simply /// passes through to `from_time` - fn from_after(t: u32) -> Self { - Self::from_time(t) + fn from_after(t: LockTime) -> Self { + Self::from_time(t.to_u32()) } /// Type property of a relative timelock. Default implementation simply @@ -434,7 +436,7 @@ pub trait Property: Sized { // Note that for CLTV this is a limitation not of Bitcoin but Miniscript. The // number on the stack would be a 5 bytes signed integer but Miniscript's B type // only consumes 4 bytes from the stack. - if t == 0 || (t & SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0 { + if t.to_u32() == 0 || (t.to_u32() & SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0 { return Err(Error { fragment: fragment.clone(), error: ErrorKind::InvalidTime, @@ -621,7 +623,7 @@ impl Property for Type { } } - fn from_after(t: u32) -> Self { + fn from_after(t: LockTime) -> Self { Type { corr: Property::from_after(t), mall: Property::from_after(t), @@ -817,7 +819,7 @@ impl Property for Type { // Note that for CLTV this is a limitation not of Bitcoin but Miniscript. The // number on the stack would be a 5 bytes signed integer but Miniscript's B type // only consumes 4 bytes from the stack. - if t == 0 || (t & SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0 { + if t.to_u32() == 0 || (t.to_u32() & SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0 { return Err(Error { fragment: fragment.clone(), error: ErrorKind::InvalidTime, diff --git a/src/policy/concrete.rs b/src/policy/concrete.rs index 542013219..f17bf204a 100644 --- a/src/policy/concrete.rs +++ b/src/policy/concrete.rs @@ -18,6 +18,7 @@ use std::collections::HashSet; use std::{error, fmt, str}; +use bitcoin::LockTime; use bitcoin::hashes::hex::FromHex; use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d}; #[cfg(feature = "compiler")] @@ -37,7 +38,7 @@ use { use super::ENTAILMENT_MAX_TERMINALS; use crate::expression::{self, FromTree}; -use crate::miniscript::limits::{LOCKTIME_THRESHOLD, SEQUENCE_LOCKTIME_TYPE_FLAG}; +use crate::miniscript::limits::{SEQUENCE_LOCKTIME_TYPE_FLAG}; use crate::miniscript::types::extra_props::TimelockInfo; use crate::{errstr, Error, ForEach, ForEachKey, MiniscriptKey}; @@ -53,7 +54,7 @@ pub enum Policy { /// A public key which must sign to satisfy the descriptor Key(Pk), /// An absolute locktime restriction - After(u32), + After(LockTime), /// A relative locktime restriction Older(u32), /// A SHA256 whose preimage must be provided to satisfy the descriptor @@ -462,8 +463,8 @@ impl Policy { Policy::After(t) => TimelockInfo { csv_with_height: false, csv_with_time: false, - cltv_with_height: t < LOCKTIME_THRESHOLD, - cltv_with_time: t >= LOCKTIME_THRESHOLD, + cltv_with_height: t.is_height(), + cltv_with_time: t.is_time(), contains_combination: false, }, Policy::Older(t) => TimelockInfo { @@ -528,7 +529,16 @@ impl Policy { Ok(()) } } - Policy::After(n) | Policy::Older(n) => { + Policy::After(n) => { + if n.to_u32() == 0 { + Err(PolicyError::ZeroTime) + } else if n.to_u32() > 2u32.pow(31) { + Err(PolicyError::TimeTooFar) + } else { + Ok(()) + } + }, + Policy::Older(n) => { if n == 0 { Err(PolicyError::ZeroTime) } else if n > 2u32.pow(31) { @@ -748,7 +758,7 @@ where } else if num == 0 { return Err(Error::PolicyError(PolicyError::ZeroTime)); } - Ok(Policy::After(num)) + Ok(Policy::After(LockTime::from(num))) } ("older", 1) => { let num = expression::terminal(&top.args[0], expression::parse_num)?; diff --git a/src/policy/semantic.rs b/src/policy/semantic.rs index 122d2b26e..545260d00 100644 --- a/src/policy/semantic.rs +++ b/src/policy/semantic.rs @@ -17,12 +17,13 @@ use std::str::FromStr; use std::{fmt, str}; +use bitcoin::LockTime; use bitcoin::hashes::hex::FromHex; use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d}; use super::concrete::PolicyError; use super::ENTAILMENT_MAX_TERMINALS; -use crate::{errstr, expression, timelock, Error, ForEach, ForEachKey, MiniscriptKey}; +use crate::{errstr, expression, Error, ForEach, ForEachKey, MiniscriptKey}; /// Abstract policy which corresponds to the semantics of a Miniscript /// and which allows complex forms of analysis, e.g. filtering and @@ -39,7 +40,7 @@ pub enum Policy { /// Signature and public key matching a given hash is required KeyHash(Pk::Hash), /// An absolute locktime restriction - After(u32), + After(LockTime), /// A relative locktime restriction Older(u32), /// A SHA256 whose preimage must be provided to satisfy the descriptor @@ -316,7 +317,7 @@ where Pk::Hash::from_str(pk).map(Policy::KeyHash) }), ("after", 1) => expression::terminal(&top.args[0], |x| { - expression::parse_num(x).map(Policy::After) + expression::parse_num(x).map(|x| Policy::After(LockTime::from(x))) }), ("older", 1) => expression::terminal(&top.args[0], |x| { expression::parse_num(x).map(Policy::Older) @@ -502,7 +503,7 @@ impl Policy { | Policy::Ripemd160(..) | Policy::Hash160(..) => vec![], Policy::Older(..) => vec![], - Policy::After(t) => vec![t], + Policy::After(t) => vec![t.to_u32()], Policy::Threshold(_, ref subs) => subs.iter().fold(vec![], |mut acc, x| { acc.extend(x.real_absolute_timelocks()); acc @@ -540,10 +541,13 @@ impl Policy { /// Filter a policy by eliminating absolute timelock constraints /// that are not satisfied at the given age. - pub fn at_height(mut self, time: u32) -> Policy { + // TODO: Find example of this warning and fix it. + // WARNING: age and height are mixed up in this function and above, at other places in the lib + // 'age' refers to absolute locks. + pub fn at_height(mut self, time: LockTime) -> Policy { self = match self { Policy::After(t) => { - if !timelock::absolute_timelocks_are_same_unit(t, time) { + if !t.is_same_unit(t) { Policy::Unsatisfiable } else if t > time { Policy::Unsatisfiable @@ -766,7 +770,7 @@ mod tests { // Block height 1000. let policy = StringPolicy::from_str("after(1000)").unwrap(); - assert_eq!(policy, Policy::After(1000)); + assert_eq!(policy, Policy::After(LockTime::from(1000))); assert_eq!(policy.absolute_timelocks(), vec![1000]); assert_eq!(policy.relative_timelocks(), vec![]); assert_eq!(policy.clone().at_height(0), Policy::Unsatisfiable); diff --git a/src/psbt/mod.rs b/src/psbt/mod.rs index 7d129148f..81f030c06 100644 --- a/src/psbt/mod.rs +++ b/src/psbt/mod.rs @@ -28,11 +28,11 @@ use bitcoin::secp256k1::{self, Secp256k1}; use bitcoin::util::psbt::{self, PartiallySignedTransaction as Psbt}; use bitcoin::util::sighash::SighashCache; use bitcoin::util::taproot::{self, ControlBlock, LeafVersion, TapLeafHash}; -use bitcoin::{self, EcdsaSighashType, SchnorrSighashType, Script}; +use bitcoin::{self, locktime, EcdsaSighashType, LockTime, SchnorrSighashType, Script}; use crate::miniscript::iter::PkPkh; use crate::miniscript::limits::SEQUENCE_LOCKTIME_DISABLE_FLAG; -use crate::miniscript::satisfy::{After, Older}; +use crate::miniscript::satisfy::Older; use crate::{ descriptor, interpreter, Descriptor, DescriptorPublicKey, MiniscriptKey, Preimage32, Satisfier, ToPublicKey, TranslatePk, TranslatePk2, @@ -332,16 +332,16 @@ impl<'psbt, Pk: MiniscriptKey + ToPublicKey> Satisfier for PsbtInputSatisfie .map(|(pk, sig)| (*pk, *sig)) } - fn check_after(&self, n: u32) -> bool { - let locktime = self.psbt.unsigned_tx.lock_time; - let seq = self.psbt.unsigned_tx.input[self.index].sequence; + fn check_after(&self, n: LockTime) -> bool { + let lock_time = LockTime::from(self.psbt.unsigned_tx.lock_time); - // https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki - // fail if TxIn is finalized - if seq == 0xffffffff { - false - } else { - >::check_after(&After(locktime), n) + if self.psbt.unsigned_tx.ignore_lock_time_for_index(self.index) { + return false; + } + + match locktime::is_satisfied(n, lock_time) { + Err(_) => false, + Ok(res) => res, } } @@ -1397,7 +1397,7 @@ mod tests { let mut non_witness_utxo = bitcoin::Transaction { version: 1, - lock_time: 0, + lock_time: LockTime::from(0), input: vec![], output: vec![TxOut { value: 1_000, @@ -1410,7 +1410,7 @@ mod tests { let tx = bitcoin::Transaction { version: 1, - lock_time: 0, + lock_time: LockTime::from(0), input: vec![TxIn { previous_output: OutPoint { txid: non_witness_utxo.txid(), diff --git a/src/timelock.rs b/src/timelock.rs deleted file mode 100644 index a28e211e8..000000000 --- a/src/timelock.rs +++ /dev/null @@ -1,21 +0,0 @@ -//! Various functions for manipulating Bitcoin timelocks. - -use crate::miniscript::limits::LOCKTIME_THRESHOLD; - -/// Returns true if `a` and `b` are the same unit i.e., both are block heights or both are UNIX -/// timestamps. `a` and `b` are nLockTime values. -pub fn absolute_timelocks_are_same_unit(a: u32, b: u32) -> bool { - n_lock_time_is_block_height(a) == n_lock_time_is_block_height(b) -} - -// https://github.com/bitcoin/bitcoin/blob/9ccaee1d5e2e4b79b0a7c29aadb41b97e4741332/src/script/script.h#L39 - -/// Returns true if nLockTime `n` is to be interpreted as a block height. -pub fn n_lock_time_is_block_height(n: u32) -> bool { - n < LOCKTIME_THRESHOLD -} - -/// Returns true if nLockTime `n` is to be interpreted as a UNIX timestamp. -pub fn n_lock_time_is_timestamp(n: u32) -> bool { - n >= LOCKTIME_THRESHOLD -}