Skip to content

Commit 7137293

Browse files
committed
interpreter: use relative::LockTime for constraints from Miniscript
In general, the type from the transaction should be `Sequence` while the type we are comparing to should be `RelLockTime` or `relative::LockTime`. Having different types here should help us avoid getting these comparisons backward.
1 parent c63e100 commit 7137293

File tree

3 files changed

+26
-20
lines changed

3 files changed

+26
-20
lines changed

src/interpreter/error.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use bitcoin::hashes::hash160;
99
use bitcoin::hex::DisplayHex;
1010
#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/121684
1111
use bitcoin::secp256k1;
12-
use bitcoin::taproot;
12+
use bitcoin::{absolute, relative, taproot};
1313

1414
use super::BitcoinKey;
1515
use crate::prelude::*;
@@ -18,9 +18,9 @@ use crate::prelude::*;
1818
#[derive(Debug)]
1919
pub enum Error {
2020
/// Could not satisfy, absolute locktime not met
21-
AbsoluteLocktimeNotMet(u32),
21+
AbsoluteLocktimeNotMet(absolute::LockTime),
2222
/// Could not satisfy, lock time values are different units
23-
AbsoluteLocktimeComparisonInvalid(u32, u32),
23+
AbsoluteLocktimeComparisonInvalid(absolute::LockTime, absolute::LockTime),
2424
/// Cannot Infer a taproot descriptor
2525
/// Key spends cannot infer the internal key of the descriptor
2626
/// Inferring script spends is possible, but is hidden nodes are currently
@@ -85,7 +85,9 @@ pub enum Error {
8585
/// Parse Error while parsing a `stack::Element::Push` as a XOnlyPublicKey (32 bytes)
8686
XOnlyPublicKeyParseError,
8787
/// Could not satisfy, relative locktime not met
88-
RelativeLocktimeNotMet(u32),
88+
RelativeLocktimeNotMet(relative::LockTime),
89+
/// Could not satisfy, the sequence number on the tx input had the disable flag set.
90+
RelativeLocktimeDisabled(relative::LockTime),
8991
/// Forward-secp related errors
9092
Secp(secp256k1::Error),
9193
/// Miniscript requires the entire top level script to be satisfied.
@@ -162,6 +164,9 @@ impl fmt::Display for Error {
162164
Error::RelativeLocktimeNotMet(n) => {
163165
write!(f, "required relative locktime CSV of {} blocks, not met", n)
164166
}
167+
Error::RelativeLocktimeDisabled(n) => {
168+
write!(f, "required relative locktime CSV of {} blocks, but tx sequence number has disable-flag set", n)
169+
}
165170
Error::ScriptSatisfactionError => f.write_str("Top level script must be satisfied"),
166171
Error::Secp(ref e) => fmt::Display::fmt(e, f),
167172
Error::SchnorrSig(ref s) => write!(f, "Schnorr sig error: {}", s),
@@ -213,6 +218,7 @@ impl error::Error for Error {
213218
| PkEvaluationError(_)
214219
| PkHashVerifyFail(_)
215220
| RelativeLocktimeNotMet(_)
221+
| RelativeLocktimeDisabled(_)
216222
| ScriptSatisfactionError
217223
| TapAnnexUnsupported
218224
| UncompressedPubkey

src/interpreter/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use core::fmt;
1212
use core::str::FromStr;
1313

1414
use bitcoin::hashes::{hash160, ripemd160, sha256, Hash};
15-
use bitcoin::{absolute, secp256k1, sighash, taproot, Sequence, TxOut, Witness};
15+
use bitcoin::{absolute, relative, secp256k1, sighash, taproot, Sequence, TxOut, Witness};
1616

1717
use crate::miniscript::context::{NoChecks, SigType};
1818
use crate::miniscript::ScriptContext;
@@ -468,7 +468,7 @@ pub enum SatisfiedConstraint {
468468
///Relative Timelock for CSV.
469469
RelativeTimelock {
470470
/// The value of RelativeTimelock
471-
n: Sequence,
471+
n: relative::LockTime,
472472
},
473473
///Absolute Timelock for CLTV.
474474
AbsoluteTimelock {

src/interpreter/stack.rs

+14-14
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
66
use bitcoin::blockdata::{opcodes, script};
77
use bitcoin::hashes::{hash160, ripemd160, sha256, Hash};
8-
use bitcoin::{absolute, Sequence};
8+
use bitcoin::{absolute, relative, Sequence};
99

1010
use super::error::PkEvalErrInner;
1111
use super::{verify_sersig, BitcoinKey, Error, HashLockType, KeySigPair, SatisfiedConstraint};
@@ -212,19 +212,14 @@ impl<'txin> Stack<'txin> {
212212
let is_satisfied = match (*n, lock_time) {
213213
(Blocks(n), Blocks(lock_time)) => n <= lock_time,
214214
(Seconds(n), Seconds(lock_time)) => n <= lock_time,
215-
_ => {
216-
return Some(Err(Error::AbsoluteLocktimeComparisonInvalid(
217-
n.to_consensus_u32(),
218-
lock_time.to_consensus_u32(),
219-
)))
220-
}
215+
_ => return Some(Err(Error::AbsoluteLocktimeComparisonInvalid(*n, lock_time))),
221216
};
222217

223218
if is_satisfied {
224219
self.push(Element::Satisfied);
225220
Some(Ok(SatisfiedConstraint::AbsoluteTimelock { n: *n }))
226221
} else {
227-
Some(Err(Error::AbsoluteLocktimeNotMet(n.to_consensus_u32())))
222+
Some(Err(Error::AbsoluteLocktimeNotMet(*n)))
228223
}
229224
}
230225

@@ -236,14 +231,19 @@ impl<'txin> Stack<'txin> {
236231
/// booleans
237232
pub(super) fn evaluate_older(
238233
&mut self,
239-
n: &Sequence,
240-
age: Sequence,
234+
n: &relative::LockTime,
235+
sequence: Sequence,
241236
) -> Option<Result<SatisfiedConstraint, Error>> {
242-
if age >= *n {
243-
self.push(Element::Satisfied);
244-
Some(Ok(SatisfiedConstraint::RelativeTimelock { n: *n }))
237+
if let Some(tx_locktime) = sequence.to_relative_lock_time() {
238+
if n.is_implied_by(tx_locktime) {
239+
self.push(Element::Satisfied);
240+
Some(Ok(SatisfiedConstraint::RelativeTimelock { n: *n }))
241+
} else {
242+
Some(Err(Error::RelativeLocktimeNotMet(*n)))
243+
}
245244
} else {
246-
Some(Err(Error::RelativeLocktimeNotMet(n.to_consensus_u32())))
245+
// BIP 112: if the tx locktime has the disable flag set, fail CSV.
246+
Some(Err(Error::RelativeLocktimeNotMet(*n)))
247247
}
248248
}
249249

0 commit comments

Comments
 (0)