Skip to content

Commit

Permalink
Use the new relative::LockTime module
Browse files Browse the repository at this point in the history
Implement `check_older` using the new `relative::LockTime` API.

This code seems upside down, I'm not sure I have the naming correct,
i.e., I don't know which (`self` or arg) is doing the satisfying and
which is satisfied?

I believe the `<=` are going the correct direction, its the naming and
which sequence value to call the 'lock' that I'm struggling with.
  • Loading branch information
tcharding committed Aug 26, 2022
1 parent 93b7749 commit a332ad9
Show file tree
Hide file tree
Showing 15 changed files with 110 additions and 120 deletions.
9 changes: 5 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,23 @@ compiler = []
trace = []

unstable = []
serde = ["actual-serde", "bitcoin/use-serde"]
serde = ["actual-serde", "bitcoin/serde"]
rand = ["bitcoin/rand"]

[dependencies]
bitcoin = { version = "0.29.0", default-features = false }
bitcoin = { path = "/home/tobin/build/github.com/tcharding/rust-bitcoin", default-features = false }
hashbrown = { version = "0.11", optional = true }

# Do NOT use this as a feature! Use the `serde` feature instead.
actual-serde = { package = "serde", version = "1.0", optional = true }


[dev-dependencies]
bitcoind = { git = "https://github.com/tcharding/bitcoind", branch = "dev-build", features=["22_0"] }
bitcoind = { path = "/home/tobin/build/github.com/tcharding/bitcoind", features=["22_0"] }
actual-rand = { package = "rand", version = "0.8.4"}
secp256k1 = {version = "0.24.0", features = ["rand-std"]}
bitcoin = { version = "0.29.0", features = ["rand"] }
bitcoin = { path = "/home/tobin/build/github.com/tcharding/rust-bitcoin", features = ["rand"] }


[[example]]
name = "htlc"
Expand Down
4 changes: 2 additions & 2 deletions examples/sign_multisig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use std::collections::HashMap;
use std::str::FromStr;

use bitcoin::blockdata::witness::Witness;
use bitcoin::{secp256k1, PackedLockTime, Sequence};
use bitcoin::{secp256k1, absolute, Sequence};

fn main() {
let mut tx = spending_transaction();
Expand Down Expand Up @@ -91,7 +91,7 @@ fn main() {
fn spending_transaction() -> bitcoin::Transaction {
bitcoin::Transaction {
version: 2,
lock_time: PackedLockTime::ZERO,
lock_time: absolute::PackedLockTime::ZERO,
input: vec![bitcoin::TxIn {
previous_output: Default::default(),
script_sig: bitcoin::Script::new(),
Expand Down
4 changes: 2 additions & 2 deletions examples/verify_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use std::str::FromStr;
use bitcoin::consensus::Decodable;
use bitcoin::secp256k1::{self, Secp256k1};
use bitcoin::util::sighash;
use bitcoin::{LockTime, Sequence};
use bitcoin::{absolute, Sequence};
use miniscript::interpreter::KeySigPair;

fn main() {
Expand All @@ -35,7 +35,7 @@ fn main() {
&tx.input[0].script_sig,
&tx.input[0].witness,
Sequence::ZERO,
LockTime::ZERO,
absolute::LockTime::ZERO,
)
.unwrap();

Expand Down
14 changes: 7 additions & 7 deletions src/interpreter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use core::str::FromStr;
use bitcoin::blockdata::witness::Witness;
use bitcoin::hashes::{hash160, ripemd160, sha256};
use bitcoin::util::{sighash, taproot};
use bitcoin::{self, secp256k1, LockTime, Sequence, TxOut};
use bitcoin::{self, secp256k1, absolute, Sequence, TxOut};

use crate::miniscript::context::NoChecks;
use crate::miniscript::ScriptContext;
Expand All @@ -49,7 +49,7 @@ pub struct Interpreter<'txin> {
/// is the leaf script; for key-spends it is `None`.
script_code: Option<bitcoin::Script>,
age: Sequence,
lock_time: LockTime,
lock_time: absolute::LockTime,
}

// A type representing functions for checking signatures that accept both
Expand Down Expand Up @@ -174,7 +174,7 @@ impl<'txin> Interpreter<'txin> {
script_sig: &'txin bitcoin::Script,
witness: &'txin Witness,
age: Sequence, // CSV, relative lock time.
lock_time: LockTime, // CLTV, absolute lock time.
lock_time: absolute::LockTime, // CLTV, absolute lock time.
) -> Result<Self, Error> {
let (inner, stack, script_code) = inner::from_txdata(spk, script_sig, witness)?;
Ok(Interpreter {
Expand Down Expand Up @@ -496,7 +496,7 @@ pub enum SatisfiedConstraint {
///Absolute Timelock for CLTV.
AbsoluteTimelock {
/// The value of Absolute timelock
n: LockTime,
n: absolute::LockTime,
},
}

Expand Down Expand Up @@ -532,7 +532,7 @@ pub struct Iter<'intp, 'txin: 'intp> {
state: Vec<NodeEvaluationState<'intp>>,
stack: Stack<'txin>,
age: Sequence,
lock_time: LockTime,
lock_time: absolute::LockTime,
has_errored: bool,
}

Expand Down Expand Up @@ -1146,7 +1146,7 @@ mod tests {
n_satisfied: 0,
}],
age: Sequence::from_height(1002),
lock_time: LockTime::from_height(1002).unwrap(),
lock_time: absolute::LockTime::from_height(1002).unwrap(),
has_errored: false,
}
}
Expand Down Expand Up @@ -1210,7 +1210,7 @@ mod tests {
assert_eq!(
after_satisfied.unwrap(),
vec![SatisfiedConstraint::AbsoluteTimelock {
n: LockTime::from_height(1000).unwrap()
n: absolute::LockTime::from_height(1000).unwrap()
}]
);

Expand Down
8 changes: 4 additions & 4 deletions src/interpreter/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
use bitcoin;
use bitcoin::blockdata::{opcodes, script};
use bitcoin::hashes::{hash160, ripemd160, sha256, Hash};
use bitcoin::{LockTime, Sequence};
use bitcoin::{absolute, Sequence};

use super::error::PkEvalErrInner;
use super::{
Expand Down Expand Up @@ -231,10 +231,10 @@ impl<'txin> Stack<'txin> {
/// booleans
pub(super) fn evaluate_after(
&mut self,
n: &LockTime,
lock_time: LockTime,
n: &absolute::LockTime,
lock_time: absolute::LockTime,
) -> Option<Result<SatisfiedConstraint, Error>> {
use LockTime::*;
use absolute::LockTime::*;

let is_satisfied = match (*n, lock_time) {
(Blocks(n), Blocks(lock_time)) => n <= lock_time,
Expand Down
4 changes: 2 additions & 2 deletions src/miniscript/astelem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use core::fmt;
use core::str::FromStr;

use bitcoin::blockdata::{opcodes, script};
use bitcoin::{LockTime, Sequence};
use bitcoin::{absolute, Sequence};
use sync::Arc;

use crate::miniscript::context::SigType;
Expand Down Expand Up @@ -460,7 +460,7 @@ impl_from_tree!(
}
("pk_h", 1) => expression::terminal(&top.args[0], |x| Pk::from_str(x).map(Terminal::PkH)),
("after", 1) => expression::terminal(&top.args[0], |x| {
expression::parse_num(x).map(|x| Terminal::After(LockTime::from_consensus(x).into()))
expression::parse_num(x).map(|x| Terminal::After(absolute::LockTime::from_consensus(x).into()))
}),
("older", 1) => expression::terminal(&top.args[0], |x| {
expression::parse_num(x).map(|x| Terminal::Older(Sequence::from_consensus(x)))
Expand Down
6 changes: 3 additions & 3 deletions src/miniscript/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use bitcoin::blockdata::constants::MAX_BLOCK_WEIGHT;
use bitcoin::hashes::{hash160, ripemd160, sha256, Hash};
use sync::Arc;

use crate::bitcoin::{LockTime, PackedLockTime, Sequence};
use crate::bitcoin::{absolute, Sequence};
use crate::miniscript::lex::{Token as Tk, TokenIter};
use crate::miniscript::limits::MAX_PUBKEYS_PER_MULTISIG;
use crate::miniscript::types::extra_props::ExtData;
Expand Down Expand Up @@ -140,7 +140,7 @@ pub enum Terminal<Pk: MiniscriptKey, Ctx: ScriptContext> {
RawPkH(Pk::RawPkHash),
// timelocks
/// `n CHECKLOCKTIMEVERIFY`
After(PackedLockTime),
After(absolute::PackedLockTime),
/// `n CHECKSEQUENCEVERIFY`
Older(Sequence),
// hashlocks
Expand Down Expand Up @@ -395,7 +395,7 @@ pub fn parse<Ctx: ScriptContext>(
Tk::CheckSequenceVerify, Tk::Num(n)
=> term.reduce0(Terminal::Older(Sequence::from_consensus(n)))?,
Tk::CheckLockTimeVerify, Tk::Num(n)
=> term.reduce0(Terminal::After(LockTime::from_consensus(n).into()))?,
=> term.reduce0(Terminal::After(absolute::LockTime::from_consensus(n).into()))?,
// hashlocks
Tk::Equal => match_token!(
tokens,
Expand Down
85 changes: 40 additions & 45 deletions src/miniscript/satisfy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use core::{cmp, i64, mem};

use bitcoin::secp256k1::XOnlyPublicKey;
use bitcoin::util::taproot::{ControlBlock, LeafVersion, TapLeafHash};
use bitcoin::{LockTime, Sequence};
use bitcoin::{absolute, relative, Sequence};
use sync::Arc;

use crate::prelude::*;
Expand Down Expand Up @@ -106,12 +106,12 @@ pub trait Satisfier<Pk: MiniscriptKey + ToPublicKey> {
}

/// Assert whether an relative locktime is satisfied
fn check_older(&self, _: Sequence) -> bool {
fn check_older(&self, _: relative::LockTime) -> bool {
false
}

/// Assert whether a absolute locktime is satisfied
fn check_after(&self, _: LockTime) -> bool {
fn check_after(&self, _: absolute::LockTime) -> bool {
false
}
}
Expand All @@ -120,32 +120,17 @@ pub trait Satisfier<Pk: MiniscriptKey + ToPublicKey> {
impl<Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk> for () {}

impl<Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk> for Sequence {
fn check_older(&self, n: Sequence) -> bool {
if !self.is_relative_lock_time() {
return false;
}

// We need a relative lock time type in rust-bitcoin to clean this up.

/* If nSequence encodes a relative lock-time, this mask is
* applied to extract that lock-time from the sequence field. */
const SEQUENCE_LOCKTIME_MASK: u32 = 0x0000ffff;
const SEQUENCE_LOCKTIME_TYPE_FLAG: u32 = 0x00400000;

let mask = SEQUENCE_LOCKTIME_MASK | SEQUENCE_LOCKTIME_TYPE_FLAG;
let masked_n = n.to_consensus_u32() & mask;
let masked_seq = self.to_consensus_u32() & mask;
if masked_n < SEQUENCE_LOCKTIME_TYPE_FLAG && masked_seq >= SEQUENCE_LOCKTIME_TYPE_FLAG {
false
} else {
masked_n <= masked_seq
fn check_older(&self, n: relative::LockTime) -> bool {
match self.to_relative_lock_time() {
None => false,
Some(lock_time) => n.is_satisfied_by(lock_time),
}
}
}

impl<Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk> for LockTime {
fn check_after(&self, n: LockTime) -> bool {
use LockTime::*;
impl<Pk: MiniscriptKey + ToPublicKey> Satisfier<Pk> for absolute::LockTime {
fn check_after(&self, n: absolute::LockTime) -> bool {
use absolute::LockTime::*;

match (n, *self) {
(Blocks(n), Blocks(lock_time)) => n <= lock_time,
Expand Down Expand Up @@ -265,11 +250,11 @@ impl<'a, Pk: MiniscriptKey + ToPublicKey, S: Satisfier<Pk>> Satisfier<Pk> for &'
(**self).lookup_hash160(h)
}

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

fn check_after(&self, n: LockTime) -> bool {
fn check_after(&self, n: absolute::LockTime) -> bool {
(**self).check_after(n)
}
}
Expand Down Expand Up @@ -327,11 +312,11 @@ impl<'a, Pk: MiniscriptKey + ToPublicKey, S: Satisfier<Pk>> Satisfier<Pk> for &'
(**self).lookup_hash160(h)
}

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

fn check_after(&self, n: LockTime) -> bool {
fn check_after(&self, n: absolute::LockTime) -> bool {
(**self).check_after(n)
}
}
Expand Down Expand Up @@ -465,7 +450,7 @@ macro_rules! impl_tuple_satisfier {
None
}

fn check_older(&self, n: Sequence) -> bool {
fn check_older(&self, n: relative::LockTime) -> bool {
let &($(ref $ty,)*) = self;
$(
if $ty.check_older(n) {
Expand All @@ -475,7 +460,7 @@ macro_rules! impl_tuple_satisfier {
false
}

fn check_after(&self, n: LockTime) -> bool {
fn check_after(&self, n: absolute::LockTime) -> bool {
let &($(ref $ty,)*) = self;
$(
if $ty.check_after(n) {
Expand Down Expand Up @@ -953,21 +938,31 @@ impl Satisfaction {
},
has_sig: false,
},
Terminal::Older(t) => Satisfaction {
stack: if stfr.check_older(t) {
Witness::empty()
} else if root_has_sig {
// If the root terminal has signature, the
// signature covers the nLockTime and nSequence
// values. The sender of the transaction should
// take care that it signs the value such that the
// timelock is not met
Witness::Impossible
} else {
Witness::Unavailable
},
Terminal::Older(t) => {
let older = {
match t.to_relative_lock_time() {
// https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki
// Disable flag set => return true.
None => true,
Some(lock) => stfr.check_older(lock),
}
};
Satisfaction {
stack: if older {
Witness::empty()
} else if root_has_sig {
// If the root terminal has signature, the
// signature covers the nLockTime and nSequence
// values. The sender of the transaction should
// take care that it signs the value such that the
// timelock is not met
Witness::Impossible
} else {
Witness::Unavailable
},

has_sig: false,
has_sig: false,
}
},
Terminal::Ripemd160(ref h) => Satisfaction {
stack: Witness::ripemd160_preimage(stfr, h),
Expand Down
6 changes: 3 additions & 3 deletions src/miniscript/types/extra_props.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use core::cmp;
use core::iter::once;

use bitcoin::{LockTime, PackedLockTime, Sequence};
use bitcoin::{absolute, Sequence};

use super::{Error, ErrorKind, Property, ScriptContext};
use crate::miniscript::context::SigType;
Expand Down Expand Up @@ -337,7 +337,7 @@ impl Property for ExtData {
unreachable!()
}

fn from_after(t: LockTime) -> Self {
fn from_after(t: absolute::LockTime) -> Self {
ExtData {
pk_cost: script_num_size(t.to_consensus_u32() as usize) + 1,
has_free_verify: false,
Expand Down Expand Up @@ -933,7 +933,7 @@ impl Property for ExtData {
// Note that for CLTV this is a limitation not of Bitcoin but Miniscript. The
// number on the stack would be a 5 bytes signed integer but Miniscript's B type
// only consumes 4 bytes from the stack.
if t == PackedLockTime::ZERO {
if t == absolute::PackedLockTime::ZERO {
return Err(Error {
fragment: fragment.clone(),
error: ErrorKind::InvalidTime,
Expand Down
Loading

0 comments on commit a332ad9

Please sign in to comment.