Skip to content

Commit 019d0ff

Browse files
committed
WIP: Use new LockTime type
1 parent e2e8e77 commit 019d0ff

File tree

21 files changed

+154
-138
lines changed

21 files changed

+154
-138
lines changed

Cargo.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,19 @@ no-std = ["hashbrown", "bitcoin/no-std"]
1717
compiler = []
1818
trace = []
1919
unstable = []
20-
use-serde = ["serde", "bitcoin/use-serde"]
20+
use-serde = ["serde", "bitcoin/serde"]
2121
rand = ["bitcoin/rand"]
2222

2323
[dependencies]
24-
bitcoin = { version = "0.28.1", default-features = false }
24+
bitcoin = { path = "../rust-bitcoin", default-features = false }
2525
serde = { version = "1.0", optional = true }
2626
hashbrown = { version = "0.11", optional = true }
2727

2828
[dev-dependencies]
29-
bitcoind = {version = "0.26.1", features=["22_0"]}
29+
bitcoind = { path = "../../RCasatta/bitcoind", features=["22_0"] }
3030
actual-rand = { package = "rand", version = "0.8.4"}
3131
secp256k1 = {version = "0.22.1", features = ["rand-std"]}
32+
bitcoin = { path = "../rust-bitcoin", features = ["rand"] }
3233

3334
[[example]]
3435
name = "htlc"

examples/sign_multisig.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use std::collections::HashMap;
1818
use std::str::FromStr;
1919

2020
use bitcoin::blockdata::witness::Witness;
21+
use bitcoin::blockdata::locktime;
2122
use bitcoin::secp256k1;
2223

2324
fn main() {
@@ -91,7 +92,7 @@ fn main() {
9192
fn spending_transaction() -> bitcoin::Transaction {
9293
bitcoin::Transaction {
9394
version: 2,
94-
lock_time: 0,
95+
lock_time: locktime::ZERO,
9596
input: vec![bitcoin::TxIn {
9697
previous_output: Default::default(),
9798
script_sig: bitcoin::Script::new(),

examples/verify_tx.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
1717
use std::str::FromStr;
1818

19+
use bitcoin::blockdata::locktime;
1920
use bitcoin::consensus::Decodable;
2021
use bitcoin::secp256k1::{self, Secp256k1};
2122
use bitcoin::util::sighash;
@@ -34,7 +35,7 @@ fn main() {
3435
&tx.input[0].script_sig,
3536
&tx.input[0].witness,
3637
0,
37-
0,
38+
locktime::ZERO,
3839
)
3940
.unwrap();
4041

src/descriptor/tr.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ impl<Pk: MiniscriptKey> Tr<Pk> {
257257
TaprootBuilderError::EmptyTree => {
258258
unreachable!("Taptree is a well formed tree with atleast 1 element")
259259
}
260+
_ => unreachable!("non_exhaustive catchall")
260261
},
261262
}
262263
};

src/interpreter/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ use crate::prelude::*;
2929
pub enum Error {
3030
/// Could not satisfy, absolute locktime not met
3131
AbsoluteLocktimeNotMet(u32),
32+
/// Could not satisfy, lock time values are different units
33+
AbsoluteLocktimeComparisonInvalid(u32, u32),
3234
/// Cannot Infer a taproot descriptor
3335
/// Key spends cannot infer the internal key of the descriptor
3436
/// Inferring script spends is possible, but is hidden nodes are currently
@@ -187,6 +189,7 @@ impl fmt::Display for Error {
187189
Error::VerifyFailed => {
188190
f.write_str("Expected Satisfied Boolean at stack top for VERIFY")
189191
}
192+
_ => f.write_str("Unknown error, non_exhaustive catch all"),
190193
}
191194
}
192195
}
@@ -234,6 +237,7 @@ impl error::Error for Error {
234237
Secp(e) => Some(e),
235238
SchnorrSig(e) => Some(e),
236239
SighashError(e) => Some(e),
240+
_ => None // non_exhaustive catch all.
237241
}
238242
}
239243
}

src/interpreter/mod.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use core::str::FromStr;
2525
use bitcoin::blockdata::witness::Witness;
2626
use bitcoin::hashes::{hash160, ripemd160, sha256};
2727
use bitcoin::util::{sighash, taproot};
28-
use bitcoin::{self, secp256k1, TxOut};
28+
use bitcoin::{self, secp256k1, TxOut, LockTime};
2929

3030
use crate::miniscript::context::NoChecks;
3131
use crate::miniscript::ScriptContext;
@@ -49,7 +49,7 @@ pub struct Interpreter<'txin> {
4949
/// is the leaf script; for key-spends it is `None`.
5050
script_code: Option<bitcoin::Script>,
5151
age: u32,
52-
lock_time: u32,
52+
lock_time: LockTime,
5353
}
5454

5555
// A type representing functions for checking signatures that accept both
@@ -171,8 +171,8 @@ impl<'txin> Interpreter<'txin> {
171171
spk: &bitcoin::Script,
172172
script_sig: &'txin bitcoin::Script,
173173
witness: &'txin Witness,
174-
age: u32, // CSV, relative lock time.
175-
lock_time: u32, // CLTV, absolute lock time.
174+
age: u32, // CSV, relative lock time.
175+
lock_time: LockTime, // CLTV, absolute lock time.
176176
) -> Result<Self, Error> {
177177
let (inner, stack, script_code) = inner::from_txdata(spk, script_sig, witness)?;
178178
Ok(Interpreter {
@@ -494,7 +494,7 @@ pub enum SatisfiedConstraint {
494494
///Absolute Timelock for CLTV.
495495
AbsoluteTimelock {
496496
/// The value of Absolute timelock
497-
time: u32,
497+
n: LockTime,
498498
},
499499
}
500500

@@ -530,7 +530,7 @@ pub struct Iter<'intp, 'txin: 'intp> {
530530
state: Vec<NodeEvaluationState<'intp>>,
531531
stack: Stack<'txin>,
532532
age: u32,
533-
lock_time: u32,
533+
lock_time: LockTime,
534534
has_errored: bool,
535535
}
536536

@@ -1143,7 +1143,7 @@ mod tests {
11431143
n_satisfied: 0,
11441144
}],
11451145
age: 1002,
1146-
lock_time: 1002,
1146+
lock_time: LockTime::from_consensus(1002),
11471147
has_errored: false,
11481148
}
11491149
}
@@ -1206,7 +1206,7 @@ mod tests {
12061206
let after_satisfied: Result<Vec<SatisfiedConstraint>, Error> = constraints.collect();
12071207
assert_eq!(
12081208
after_satisfied.unwrap(),
1209-
vec![SatisfiedConstraint::AbsoluteTimelock { time: 1000 }]
1209+
vec![SatisfiedConstraint::AbsoluteTimelock { n: LockTime::from_consensus(1000) }]
12101210
);
12111211

12121212
//Check Older

src/interpreter/stack.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use bitcoin;
1818
use bitcoin::blockdata::{opcodes, script};
1919
use bitcoin::hashes::{hash160, ripemd160, sha256, Hash};
20+
use bitcoin::LockTime;
2021

2122
use super::error::PkEvalErrInner;
2223
use super::{
@@ -230,14 +231,22 @@ impl<'txin> Stack<'txin> {
230231
/// booleans
231232
pub(super) fn evaluate_after(
232233
&mut self,
233-
n: &u32,
234-
lock_time: u32,
234+
n: &LockTime,
235+
lock_time: LockTime,
235236
) -> Option<Result<SatisfiedConstraint, Error>> {
236-
if lock_time >= *n {
237+
use LockTime::*;
238+
239+
let is_satisfied = match (*n, lock_time) {
240+
(Blocks(n), Blocks(lock_time)) => n <= lock_time,
241+
(Seconds(n), Seconds(lock_time)) => n <= lock_time,
242+
_ => return Some(Err(Error::AbsoluteLocktimeComparisonInvalid(n.to_consensus_u32(), lock_time.to_consensus_u32()))),
243+
};
244+
245+
if is_satisfied {
237246
self.push(Element::Satisfied);
238-
Some(Ok(SatisfiedConstraint::AbsoluteTimelock { time: *n }))
247+
Some(Ok(SatisfiedConstraint::AbsoluteTimelock { n: *n }))
239248
} else {
240-
Some(Err(Error::AbsoluteLocktimeNotMet(*n)))
249+
Some(Err(Error::AbsoluteLocktimeNotMet(n.to_consensus_u32())))
241250
}
242251
}
243252

src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ pub mod interpreter;
116116
pub mod miniscript;
117117
pub mod policy;
118118
pub mod psbt;
119-
pub mod timelock;
120119

121120
#[cfg(test)]
122121
mod test_utils;

src/miniscript/astelem.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use core::fmt;
2323
use core::str::FromStr;
2424

25+
use bitcoin::LockTime;
2526
use bitcoin::blockdata::{opcodes, script};
2627
use bitcoin::hashes::hex::FromHex;
2728
use bitcoin::hashes::{hash160, ripemd160};
@@ -461,7 +462,7 @@ impl_from_tree!(
461462
}
462463
("pk_h", 1) => expression::terminal(&top.args[0], |x| Pk::from_str(x).map(Terminal::PkH)),
463464
("after", 1) => expression::terminal(&top.args[0], |x| {
464-
expression::parse_num(x).map(Terminal::After)
465+
expression::parse_num(x).map(|x| Terminal::After(LockTime::from_consensus(x)))
465466
}),
466467
("older", 1) => expression::terminal(&top.args[0], |x| {
467468
expression::parse_num(x).map(Terminal::Older)
@@ -622,7 +623,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
622623
.push_slice(&Pk::hash_to_hash160(hash)[..])
623624
.push_opcode(opcodes::all::OP_EQUALVERIFY),
624625
Terminal::After(t) => builder
625-
.push_int(t as i64)
626+
.push_int(t.to_consensus_u32() as i64)
626627
.push_opcode(opcodes::all::OP_CLTV),
627628
Terminal::Older(t) => builder.push_int(t as i64).push_opcode(opcodes::all::OP_CSV),
628629
Terminal::Sha256(ref h) => builder
@@ -757,7 +758,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
757758
match *self {
758759
Terminal::PkK(ref pk) => Ctx::pk_len(pk),
759760
Terminal::PkH(..) | Terminal::RawPkH(..) => 24,
760-
Terminal::After(n) => script_num_size(n as usize) + 1,
761+
Terminal::After(n) => script_num_size(n.to_consensus_u32() as usize) + 1,
761762
Terminal::Older(n) => script_num_size(n as usize) + 1,
762763
Terminal::Sha256(..) => 33 + 6,
763764
Terminal::Hash256(..) => 33 + 6,

src/miniscript/decode.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use sync::Arc;
2828

2929
use crate::miniscript::lex::{Token as Tk, TokenIter};
3030
use crate::miniscript::limits::MAX_PUBKEYS_PER_MULTISIG;
31+
use crate::bitcoin::LockTime;
3132
use crate::miniscript::types::extra_props::ExtData;
3233
use crate::miniscript::types::{Property, Type};
3334
use crate::miniscript::ScriptContext;
@@ -139,7 +140,7 @@ pub enum Terminal<Pk: MiniscriptKey, Ctx: ScriptContext> {
139140
RawPkH(Pk::RawPkHash),
140141
// timelocks
141142
/// `n CHECKLOCKTIMEVERIFY`
142-
After(u32),
143+
After(LockTime),
143144
/// `n CHECKSEQUENCEVERIFY`
144145
Older(u32),
145146
// hashlocks
@@ -394,7 +395,7 @@ pub fn parse<Ctx: ScriptContext>(
394395
Tk::CheckSequenceVerify, Tk::Num(n)
395396
=> term.reduce0(Terminal::Older(n))?,
396397
Tk::CheckLockTimeVerify, Tk::Num(n)
397-
=> term.reduce0(Terminal::After(n))?,
398+
=> term.reduce0(Terminal::After(LockTime::from_consensus(n)))?,
398399
// hashlocks
399400
Tk::Equal => match_token!(
400401
tokens,

src/miniscript/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -980,7 +980,7 @@ mod tests {
980980
));
981981
assert_eq!(
982982
ms.unwrap_err().to_string(),
983-
"unexpected «Key hex decoding error: bad hex string length 64 (expected 66)»"
983+
"unexpected «key hex decoding error»"
984984
);
985985
Tapscript::from_str_insane(&format!(
986986
"pk(2788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99)"

src/miniscript/satisfy.rs

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@
2020
2121
use core::{cmp, i64, mem};
2222

23-
use bitcoin;
23+
use bitcoin::LockTime;
2424
use bitcoin::hashes::{hash160, ripemd160};
2525
use bitcoin::secp256k1::XOnlyPublicKey;
2626
use bitcoin::util::taproot::{ControlBlock, LeafVersion, TapLeafHash};
2727
use sync::Arc;
2828

2929
use crate::miniscript::limits::{
30-
LOCKTIME_THRESHOLD, SEQUENCE_LOCKTIME_DISABLE_FLAG, SEQUENCE_LOCKTIME_TYPE_FLAG,
30+
SEQUENCE_LOCKTIME_DISABLE_FLAG, SEQUENCE_LOCKTIME_TYPE_FLAG,
3131
};
3232
use crate::prelude::*;
3333
use crate::util::witness_size;
@@ -115,7 +115,7 @@ pub trait Satisfier<Pk: MiniscriptKey + ToPublicKey> {
115115
}
116116

117117
/// Assert whether a absolute locktime is satisfied
118-
fn check_after(&self, _: u32) -> bool {
118+
fn check_after(&self, _: LockTime) -> bool {
119119
false
120120
}
121121
}
@@ -148,21 +148,6 @@ impl<Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk> for Older {
148148
}
149149
}
150150

151-
/// Newtype around `u32` which implements `Satisfier` using `n` as an
152-
/// absolute locktime
153-
pub struct After(pub u32);
154-
155-
impl<Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk> for After {
156-
fn check_after(&self, n: u32) -> bool {
157-
// if n > self.0; we will be returning false anyways
158-
if n < LOCKTIME_THRESHOLD && self.0 >= LOCKTIME_THRESHOLD {
159-
false
160-
} else {
161-
n <= self.0
162-
}
163-
}
164-
}
165-
166151
impl<Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk> for HashMap<Pk, bitcoin::EcdsaSig> {
167152
fn lookup_ecdsa_sig(&self, key: &Pk) -> Option<bitcoin::EcdsaSig> {
168153
self.get(key).copied()
@@ -278,8 +263,8 @@ impl<'a, Pk: MiniscriptKey + ToPublicKey, S: Satisfier<Pk>> Satisfier<Pk> for &'
278263
(**self).check_older(t)
279264
}
280265

281-
fn check_after(&self, t: u32) -> bool {
282-
(**self).check_after(t)
266+
fn check_after(&self, n: LockTime) -> bool {
267+
(**self).check_after(n)
283268
}
284269
}
285270

@@ -340,8 +325,8 @@ impl<'a, Pk: MiniscriptKey + ToPublicKey, S: Satisfier<Pk>> Satisfier<Pk> for &'
340325
(**self).check_older(t)
341326
}
342327

343-
fn check_after(&self, t: u32) -> bool {
344-
(**self).check_after(t)
328+
fn check_after(&self, n: LockTime) -> bool {
329+
(**self).check_after(n)
345330
}
346331
}
347332

@@ -484,7 +469,7 @@ macro_rules! impl_tuple_satisfier {
484469
false
485470
}
486471

487-
fn check_after(&self, n: u32) -> bool {
472+
fn check_after(&self, n: LockTime) -> bool {
488473
let &($(ref $ty,)*) = self;
489474
$(
490475
if $ty.check_after(n) {

src/miniscript/types/extra_props.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
use core::cmp;
55
use core::iter::once;
66

7+
use bitcoin::LockTime;
8+
79
use super::{Error, ErrorKind, Property, ScriptContext};
810
use crate::miniscript::context::SigType;
911
use crate::miniscript::limits::{
10-
LOCKTIME_THRESHOLD, SEQUENCE_LOCKTIME_DISABLE_FLAG, SEQUENCE_LOCKTIME_TYPE_FLAG,
12+
SEQUENCE_LOCKTIME_DISABLE_FLAG, SEQUENCE_LOCKTIME_TYPE_FLAG,
1113
};
1214
use crate::prelude::*;
1315
use crate::{script_num_size, MiniscriptKey, Terminal};
@@ -338,9 +340,9 @@ impl Property for ExtData {
338340
unreachable!()
339341
}
340342

341-
fn from_after(t: u32) -> Self {
343+
fn from_after(t: LockTime) -> Self {
342344
ExtData {
343-
pk_cost: script_num_size(t as usize) + 1,
345+
pk_cost: script_num_size(t.to_consensus_u32() as usize) + 1,
344346
has_free_verify: false,
345347
ops: OpLimits::new(1, Some(0), None),
346348
stack_elem_count_sat: Some(0),
@@ -350,8 +352,8 @@ impl Property for ExtData {
350352
timelock_info: TimelockInfo {
351353
csv_with_height: false,
352354
csv_with_time: false,
353-
cltv_with_height: t < LOCKTIME_THRESHOLD,
354-
cltv_with_time: t >= LOCKTIME_THRESHOLD,
355+
cltv_with_height: t.is_block_height(),
356+
cltv_with_time: t.is_block_time(),
355357
contains_combination: false,
356358
},
357359
exec_stack_elem_count_sat: Some(1), // <t>
@@ -934,7 +936,7 @@ impl Property for ExtData {
934936
// Note that for CLTV this is a limitation not of Bitcoin but Miniscript. The
935937
// number on the stack would be a 5 bytes signed integer but Miniscript's B type
936938
// only consumes 4 bytes from the stack.
937-
if t == 0 || (t & SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0 {
939+
if t.to_consensus_u32() == 0 || (t.to_consensus_u32() & SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0 {
938940
return Err(Error {
939941
fragment: fragment.clone(),
940942
error: ErrorKind::InvalidTime,

0 commit comments

Comments
 (0)