Skip to content

Commit d9ffbef

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 d9ffbef

File tree

3 files changed

+27
-1
lines changed

3 files changed

+27
-1
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 & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d};
2222

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

2728
/// Abstract policy which corresponds to the semantics of a Miniscript
@@ -543,7 +544,9 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
543544
pub fn at_height(mut self, time: u32) -> Policy<Pk> {
544545
self = match self {
545546
Policy::After(t) => {
546-
if t > time {
547+
if !timelock::absolute_timelocks_are_same_unit(t, time) {
548+
Policy::Unsatisfiable
549+
} else if t > time {
547550
Policy::Unsatisfiable
548551
} else {
549552
Policy::After(t)

src/timelock.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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+
|| n_lock_time_is_timestamp(a) && n_lock_time_is_timestamp(b)
10+
}
11+
12+
// https://github.com/bitcoin/bitcoin/blob/9ccaee1d5e2e4b79b0a7c29aadb41b97e4741332/src/script/script.h#L39
13+
14+
/// Returns true if nLockTime `n` is to be interpreted as a block height.
15+
fn n_lock_time_is_block_height(n: u32) -> bool {
16+
n < LOCKTIME_THRESHOLD
17+
}
18+
19+
/// Returns true if nLockTime `n` is to be interpreted as a UNIX timestamp.
20+
fn n_lock_time_is_timestamp(n: u32) -> bool {
21+
n >= LOCKTIME_THRESHOLD
22+
}

0 commit comments

Comments
 (0)