Skip to content

Commit e4eb285

Browse files
committed
Add a minimal timelock module
Currently if we mix up height/time absolute timelocks when filtering policies the result is incorrect. Add a `timelock` module that includes a single public function for checking if absolute timelocks are the same unit. Use the new function to fix a bug in policy filtering.
1 parent 0b62f5e commit e4eb285

File tree

3 files changed

+26
-2
lines changed

3 files changed

+26
-2
lines changed

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ pub mod interpreter;
104104
pub mod miniscript;
105105
pub mod policy;
106106
pub mod psbt;
107+
pub mod timelock;
107108

108109
mod util;
109110

src/policy/semantic.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d};
2222

2323
use super::concrete::PolicyError;
2424
use super::ENTAILMENT_MAX_TERMINALS;
25-
use crate::{errstr, expression, Error, ForEach, ForEachKey, MiniscriptKey};
25+
use crate::{errstr, expression, timelock, Error, ForEach, ForEachKey, MiniscriptKey};
2626

2727
/// Abstract policy which corresponds to the semantics of a Miniscript
2828
/// and which allows complex forms of analysis, e.g. filtering and
@@ -543,7 +543,9 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
543543
pub fn at_height(mut self, time: u32) -> Policy<Pk> {
544544
self = match self {
545545
Policy::After(t) => {
546-
if t > time {
546+
if !timelock::absolute_timelocks_are_same_unit(t, time) {
547+
Policy::Unsatisfiable
548+
} else if t > time {
547549
Policy::Unsatisfiable
548550
} else {
549551
Policy::After(t)

src/timelock.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//! Various functions for manipulating Bitcoin timelocks.
2+
3+
use crate::miniscript::limits::LOCKTIME_THRESHOLD;
4+
5+
/// Returns true if `a` and `b` are the same unit i.e., both are block heights or both are UNIX
6+
/// timestamps. `a` and `b` are nLockTime values.
7+
pub fn absolute_timelocks_are_same_unit(a: u32, b: u32) -> bool {
8+
n_lock_time_is_block_height(a) == n_lock_time_is_block_height(b)
9+
}
10+
11+
// https://github.com/bitcoin/bitcoin/blob/9ccaee1d5e2e4b79b0a7c29aadb41b97e4741332/src/script/script.h#L39
12+
13+
/// Returns true if nLockTime `n` is to be interpreted as a block height.
14+
pub fn n_lock_time_is_block_height(n: u32) -> bool {
15+
n < LOCKTIME_THRESHOLD
16+
}
17+
18+
/// Returns true if nLockTime `n` is to be interpreted as a UNIX timestamp.
19+
pub fn n_lock_time_is_timestamp(n: u32) -> bool {
20+
n >= LOCKTIME_THRESHOLD
21+
}

0 commit comments

Comments
 (0)