elements_miniscript/extensions/
tx_ver.rs1use std::fmt;
6
7use elements::encode::serialize;
8
9use super::{FromTokenIterError, ParseableExt, TxEnv};
10use crate::descriptor::CovError;
11use crate::miniscript::astelem::StackCtxOperations;
12use crate::miniscript::lex::{Token as Tk, TokenIter};
13use crate::miniscript::satisfy::{Satisfaction, Witness};
14use crate::miniscript::types::extra_props::{OpLimits, TimelockInfo};
15use crate::miniscript::types::{Base, Correctness, Dissat, ExtData, Input, Malleability};
16use crate::policy::{self, Liftable};
17use crate::{
18 expression, interpreter, miniscript, util, Error, Extension, MiniscriptKey, Satisfier,
19 ToPublicKey,
20};
21
22#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
25pub struct LegacyVerEq {
26 pub n: u32, }
29
30impl fmt::Display for LegacyVerEq {
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 write!(f, "ver_eq({})", self.n)
33 }
34}
35
36impl<Pk: MiniscriptKey> Liftable<Pk> for LegacyVerEq {
37 fn lift(&self) -> Result<policy::Semantic<Pk>, Error> {
38 Err(Error::CovError(CovError::CovenantLift))
39 }
40}
41
42impl Extension for LegacyVerEq {
43 fn segwit_ctx_checks(&self) -> Result<(), miniscript::context::ScriptContextError> {
44 Ok(())
45 }
46
47 fn corr_prop(&self) -> Correctness {
48 Correctness {
49 base: Base::B,
50 input: Input::Zero,
51 dissatisfiable: false, unit: true,
53 }
54 }
55
56 fn mall_prop(&self) -> Malleability {
57 Malleability {
58 dissat: Dissat::None, safe: false,
60 non_malleable: true,
61 }
62 }
63
64 fn extra_prop(&self) -> ExtData {
65 ExtData {
66 pk_cost: 4 + 1 + 1 + 4, has_free_verify: true,
68 stack_elem_count_sat: Some(0),
69 stack_elem_count_dissat: Some(0),
70 max_sat_size: Some((0, 0)),
71 max_dissat_size: Some((0, 0)),
72 timelock_info: TimelockInfo::default(),
73 exec_stack_elem_count_sat: Some(2),
74 exec_stack_elem_count_dissat: Some(2),
75 ops: OpLimits {
76 count: 4,
77 sat: Some(0),
78 nsat: Some(0),
79 },
80 }
81 }
82
83 fn script_size(&self) -> usize {
84 4 + 1 + 1 + 4 }
86
87 fn from_name_tree(
88 name: &str,
89 children: &[expression::Tree<'_>],
90 ) -> Result<Self, FromTokenIterError> {
91 if children.len() == 1 && name == "ver_eq" {
92 let n = expression::terminal(&children[0], expression::parse_num)
93 .map_err(|_| FromTokenIterError)?;
94 Ok(Self { n })
95 } else {
96 Err(FromTokenIterError)
98 }
99 }
100}
101
102impl ParseableExt for LegacyVerEq {
103 fn satisfy<Pk, S>(&self, sat: &S) -> Satisfaction
104 where
105 Pk: ToPublicKey,
106 S: Satisfier<Pk>,
107 {
108 let wit = match sat.lookup_nversion() {
109 Some(k) => {
110 if k == self.n {
111 Witness::empty()
112 } else {
113 Witness::Impossible
114 }
115 }
116 None => Witness::Unavailable,
119 };
120 Satisfaction {
121 stack: wit,
122 has_sig: false,
123 }
124 }
125
126 fn dissatisfy<Pk, S>(&self, sat: &S) -> Satisfaction
127 where
128 Pk: ToPublicKey,
129 S: Satisfier<Pk>,
130 {
131 let wit = if let Some(k) = sat.lookup_nversion() {
132 if k == self.n {
133 Witness::Impossible
134 } else {
135 Witness::empty()
136 }
137 } else {
138 Witness::empty()
139 };
140 Satisfaction {
141 stack: wit,
142 has_sig: false,
143 }
144 }
145
146 fn push_to_builder(&self, builder: elements::script::Builder) -> elements::script::Builder {
147 builder.check_item_eq(12, &serialize(&self.n))
148 }
149
150 fn from_token_iter(tokens: &mut TokenIter<'_>) -> Result<Self, FromTokenIterError> {
151 let ver = {
152 let sl = tokens.peek_slice(5).ok_or(FromTokenIterError)?;
153 if let Tk::PickPush4(ver) = sl[3] {
154 if sl[0] == Tk::Depth
155 && sl[1] == Tk::Num(12)
156 && sl[2] == Tk::Sub
157 && sl[4] == Tk::Equal
158 {
159 Self { n: ver }
160 } else {
161 return Err(FromTokenIterError);
162 }
163 } else {
164 return Err(FromTokenIterError);
165 }
166 };
167 tokens.advance(5).expect("Size checked previously");
168 Ok(ver)
169 }
170
171 fn evaluate(
172 &self,
173 stack: &mut interpreter::Stack,
174 _txenv: Option<&TxEnv>,
175 ) -> Result<bool, interpreter::Error> {
176 let ver = stack[11];
178 let elem = ver.try_push()?;
179 if elem.len() == 4 {
180 let wit_ver = util::slice_to_u32_le(elem);
181 if wit_ver == self.n {
182 stack.push(interpreter::Element::Satisfied);
183 Ok(true)
184 } else {
185 Ok(false)
186 }
187 } else {
188 Err(interpreter::Error::CovWitnessSizeErr {
189 pos: 1,
190 expected: 4,
191 actual: elem.len(),
192 })
193 }
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use bitcoin::PublicKey;
200
201 use super::*;
202 use crate::{Miniscript, Segwitv0};
203
204 #[test]
205 fn test_ver_eq() {
206 type MsExtVer = Miniscript<PublicKey, Segwitv0, LegacyVerEq>;
207
208 let ms = MsExtVer::from_str_insane("ver_eq(8)").unwrap();
209 assert_eq!(ms.to_string(), "ver_eq(8)");
211 assert_eq!(ms, MsExtVer::parse_insane(&ms.encode()).unwrap())
213 }
214}