Skip to content

Commit 637720a

Browse files
committed
plan/satisfy: use relative::LockTime instead of Sequence to indicate relative locktimes
Eliminates some error logic. Also replaces manual implementations of `is_implied_by` in a couple places. This introduces a couple unwrap()s which will be removed in a later commit, and which occur because there is a mismatch between the `Sequence` type used in `satisfy::Satisfaction` and `bitcoin::relative::LockTime` (and we can't switch this `Sequence` because we depend on `Ord`, which will need a new newtype, which should wait for another commit). This *also* deletes a couple lines in the PSBT code which cites BIP 112 saying that if the sequence number passed to OP_CSV has the disable flag set, to automatically pass `check_older`. With this code change, it is no longer possible to produce such a situation, so we drop the check and the citation. I believe this is correct because no Miniscript-generated call to OP_CSV should have the disable flag set. I believe the Miniscript spec is silent on this and more-or-less says you can pass any crap you want as the argument to `older`, but I am taking a stand here and think we should Miniscripts with the disable flag set.
1 parent bd6ef65 commit 637720a

File tree

5 files changed

+115
-94
lines changed

5 files changed

+115
-94
lines changed

src/descriptor/mod.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,10 @@ impl Descriptor<DefiniteDescriptorKey> {
512512
descriptor: self,
513513
template: stack,
514514
absolute_timelock: satisfaction.absolute_timelock.map(Into::into),
515-
relative_timelock: satisfaction.relative_timelock,
515+
// unwrap to be removed in a later commit
516+
relative_timelock: satisfaction
517+
.relative_timelock
518+
.map(|s| s.to_relative_lock_time().unwrap()),
516519
})
517520
} else {
518521
Err(self)
@@ -540,7 +543,10 @@ impl Descriptor<DefiniteDescriptorKey> {
540543
descriptor: self,
541544
template: stack,
542545
absolute_timelock: satisfaction.absolute_timelock.map(Into::into),
543-
relative_timelock: satisfaction.relative_timelock,
546+
// unwrap to be removed in a later commit
547+
relative_timelock: satisfaction
548+
.relative_timelock
549+
.map(|s| s.to_relative_lock_time().unwrap()),
544550
})
545551
} else {
546552
Err(self)

src/miniscript/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1426,7 +1426,7 @@ mod tests {
14261426
}
14271427
}
14281428

1429-
fn check_older(&self, _: bitcoin::Sequence) -> bool { true }
1429+
fn check_older(&self, _: bitcoin::relative::LockTime) -> bool { true }
14301430

14311431
fn check_after(&self, _: bitcoin::absolute::LockTime) -> bool { true }
14321432
}

src/miniscript/satisfy.rs

Lines changed: 28 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use core::{cmp, fmt, i64, mem};
1111
use bitcoin::hashes::hash160;
1212
use bitcoin::key::XOnlyPublicKey;
1313
use bitcoin::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapNodeHash};
14-
use bitcoin::{absolute, ScriptBuf, Sequence};
14+
use bitcoin::{absolute, relative, ScriptBuf, Sequence};
1515
use sync::Arc;
1616

1717
use super::context::SigType;
@@ -94,7 +94,7 @@ pub trait Satisfier<Pk: MiniscriptKey + ToPublicKey> {
9494
/// NOTE: If a descriptor mixes time-based and height-based timelocks, the implementation of
9595
/// this method MUST only allow timelocks of either unit, but not both. Allowing both could cause
9696
/// miniscript to construct an invalid witness.
97-
fn check_older(&self, _: Sequence) -> bool { false }
97+
fn check_older(&self, _: relative::LockTime) -> bool { false }
9898

9999
/// Assert whether a absolute locktime is satisfied
100100
///
@@ -108,39 +108,21 @@ pub trait Satisfier<Pk: MiniscriptKey + ToPublicKey> {
108108
impl<Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk> for () {}
109109

110110
impl<Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk> for Sequence {
111-
fn check_older(&self, n: Sequence) -> bool {
112-
if !self.is_relative_lock_time() {
113-
return false;
114-
}
115-
116-
// We need a relative lock time type in rust-bitcoin to clean this up.
117-
118-
/* If nSequence encodes a relative lock-time, this mask is
119-
* applied to extract that lock-time from the sequence field. */
120-
const SEQUENCE_LOCKTIME_MASK: u32 = 0x0000ffff;
121-
const SEQUENCE_LOCKTIME_TYPE_FLAG: u32 = 0x00400000;
122-
123-
let mask = SEQUENCE_LOCKTIME_MASK | SEQUENCE_LOCKTIME_TYPE_FLAG;
124-
let masked_n = n.to_consensus_u32() & mask;
125-
let masked_seq = self.to_consensus_u32() & mask;
126-
if masked_n < SEQUENCE_LOCKTIME_TYPE_FLAG && masked_seq >= SEQUENCE_LOCKTIME_TYPE_FLAG {
127-
false
111+
fn check_older(&self, n: relative::LockTime) -> bool {
112+
if let Some(lt) = self.to_relative_lock_time() {
113+
Satisfier::<Pk>::check_older(&lt, n)
128114
} else {
129-
masked_n <= masked_seq
115+
false
130116
}
131117
}
132118
}
133119

134-
impl<Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk> for absolute::LockTime {
135-
fn check_after(&self, n: absolute::LockTime) -> bool {
136-
use absolute::LockTime::*;
120+
impl<Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk> for relative::LockTime {
121+
fn check_older(&self, n: relative::LockTime) -> bool { n.is_implied_by(*self) }
122+
}
137123

138-
match (n, *self) {
139-
(Blocks(n), Blocks(lock_time)) => n <= lock_time,
140-
(Seconds(n), Seconds(lock_time)) => n <= lock_time,
141-
_ => false, // Not the same units.
142-
}
143-
}
124+
impl<Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk> for absolute::LockTime {
125+
fn check_after(&self, n: absolute::LockTime) -> bool { n.is_implied_by(*self) }
144126
}
145127

146128
macro_rules! impl_satisfier_for_map_key_to_ecdsa_sig {
@@ -323,7 +305,7 @@ impl<'a, Pk: MiniscriptKey + ToPublicKey, S: Satisfier<Pk>> Satisfier<Pk> for &'
323305

324306
fn lookup_hash160(&self, h: &Pk::Hash160) -> Option<Preimage32> { (**self).lookup_hash160(h) }
325307

326-
fn check_older(&self, t: Sequence) -> bool { (**self).check_older(t) }
308+
fn check_older(&self, t: relative::LockTime) -> bool { (**self).check_older(t) }
327309

328310
fn check_after(&self, n: absolute::LockTime) -> bool { (**self).check_after(n) }
329311
}
@@ -383,7 +365,7 @@ impl<'a, Pk: MiniscriptKey + ToPublicKey, S: Satisfier<Pk>> Satisfier<Pk> for &'
383365

384366
fn lookup_hash160(&self, h: &Pk::Hash160) -> Option<Preimage32> { (**self).lookup_hash160(h) }
385367

386-
fn check_older(&self, t: Sequence) -> bool { (**self).check_older(t) }
368+
fn check_older(&self, t: relative::LockTime) -> bool { (**self).check_older(t) }
387369

388370
fn check_after(&self, n: absolute::LockTime) -> bool { (**self).check_after(n) }
389371
}
@@ -529,7 +511,7 @@ macro_rules! impl_tuple_satisfier {
529511
None
530512
}
531513

532-
fn check_older(&self, n: Sequence) -> bool {
514+
fn check_older(&self, n: relative::LockTime) -> bool {
533515
let &($(ref $ty,)*) = self;
534516
$(
535517
if $ty.check_older(n) {
@@ -1295,18 +1277,20 @@ impl<Pk: MiniscriptKey + ToPublicKey> Satisfaction<Placeholder<Pk>> {
12951277
Satisfaction { stack, has_sig: false, relative_timelock: None, absolute_timelock }
12961278
}
12971279
Terminal::Older(t) => {
1298-
let (stack, relative_timelock) = if stfr.check_older(t) {
1299-
(Witness::empty(), Some(t))
1300-
} else if root_has_sig {
1301-
// If the root terminal has signature, the
1302-
// signature covers the nLockTime and nSequence
1303-
// values. The sender of the transaction should
1304-
// take care that it signs the value such that the
1305-
// timelock is not met
1306-
(Witness::Impossible, None)
1307-
} else {
1308-
(Witness::Unavailable, None)
1309-
};
1280+
// unwrap to be removed in a later commit
1281+
let (stack, relative_timelock) =
1282+
if stfr.check_older(t.to_relative_lock_time().unwrap()) {
1283+
(Witness::empty(), Some(t))
1284+
} else if root_has_sig {
1285+
// If the root terminal has signature, the
1286+
// signature covers the nLockTime and nSequence
1287+
// values. The sender of the transaction should
1288+
// take care that it signs the value such that the
1289+
// timelock is not met
1290+
(Witness::Impossible, None)
1291+
} else {
1292+
(Witness::Unavailable, None)
1293+
};
13101294
Satisfaction { stack, has_sig: false, relative_timelock, absolute_timelock: None }
13111295
}
13121296
Terminal::Ripemd160(ref h) => Satisfaction {

0 commit comments

Comments
 (0)