tinyminiscript/
descriptor.rs1use core::marker::PhantomData;
2
3use crate::parser::{AST, ASTVisitor, Fragment, ParserContext, Position};
4
5#[cfg_attr(feature = "debug", derive(Debug))]
7#[derive(Clone, PartialEq)]
8pub enum Descriptor {
9 Bare,
11
12 Pkh,
14 Sh,
16
17 Wpkh,
19 Wsh,
21
22 Tr,
24}
25
26impl Default for Descriptor {
27 #[inline]
28 fn default() -> Self {
29 Descriptor::Bare
30 }
31}
32
33impl Descriptor {
34 #[inline]
35 pub fn from_fragment(fragment: &str) -> Self {
36 match fragment {
37 "pkh" => Descriptor::Pkh,
38 "sh" => Descriptor::Sh,
39 "wpkh" => Descriptor::Wpkh,
40 "wsh" => Descriptor::Wsh,
41 "tr" => Descriptor::Tr,
42 _ => Descriptor::Bare,
43 }
44 }
45}
46
47pub struct DescriptorValidator<'a> {
48 phantom: PhantomData<&'a ()>,
49}
50
51impl<'a> DescriptorValidator<'a> {
52 #[inline]
53 pub fn new() -> Self {
54 Self {
55 phantom: PhantomData,
56 }
57 }
58}
59
60#[cfg_attr(feature = "debug", derive(Debug))]
61pub enum DescriptorVisitorError {
62 InvalidFragmentForDescriptor {
63 position: Position,
64 expected: Descriptor,
65 found: Descriptor,
66 },
67 PublicKeyNotCompressed {
68 position: Position,
69 },
70}
71
72impl<'a> ASTVisitor<'a, ()> for DescriptorValidator<'a> {
73 type Error = DescriptorVisitorError;
74
75 fn visit_ast(&mut self, ctx: &ParserContext<'a>, node: &AST<'a>) -> Result<(), Self::Error> {
76 match &node.fragment {
77 Fragment::Descriptor { descriptor, inner } => {
78 self.visit_ast_by_index(ctx, *inner)?;
79 }
80
81 Fragment::False => {}
82 Fragment::True => {}
83 Fragment::PkK { key } | Fragment::PkH { key } => match &ctx.inner_descriptor {
84 Descriptor::Bare => {}
85 Descriptor::Pkh => {}
86 Descriptor::Sh => {}
87 Descriptor::Wpkh | Descriptor::Wsh => {
88 if !key.is_compressed() {
89 return Err(DescriptorVisitorError::PublicKeyNotCompressed {
90 position: node.position,
91 });
92 }
93 }
94 Descriptor::Tr => {}
95 },
96 Fragment::Older { n } => {}
97 Fragment::After { n } => {}
98 Fragment::Sha256 { h } => {}
99 Fragment::Hash256 { h } => {}
100 Fragment::Ripemd160 { h } => {}
101 Fragment::Hash160 { h } => {}
102 Fragment::AndOr { x, y, z } => {
103 self.visit_ast_by_index(ctx, *x)?;
104 self.visit_ast_by_index(ctx, *y)?;
105 self.visit_ast_by_index(ctx, *z)?;
106 }
107 Fragment::AndV { x, y } => {
108 self.visit_ast_by_index(ctx, *x)?;
109 self.visit_ast_by_index(ctx, *y)?;
110 }
111 Fragment::AndB { x, y } => {
112 self.visit_ast_by_index(ctx, *x)?;
113 self.visit_ast_by_index(ctx, *y)?;
114 }
115 Fragment::OrB { x, z } => {
116 self.visit_ast_by_index(ctx, *x)?;
117 self.visit_ast_by_index(ctx, *z)?;
118 }
119 Fragment::OrC { x, z } => {
120 self.visit_ast_by_index(ctx, *x)?;
121 self.visit_ast_by_index(ctx, *z)?;
122 }
123 Fragment::OrD { x, z } => {
124 self.visit_ast_by_index(ctx, *x)?;
125 self.visit_ast_by_index(ctx, *z)?;
126 }
127 Fragment::OrI { x, z } => {
128 self.visit_ast_by_index(ctx, *x)?;
129 self.visit_ast_by_index(ctx, *z)?;
130 }
131 Fragment::Thresh { k, xs } => {
132 for x in xs {
133 self.visit_ast_by_index(ctx, *x)?;
134 }
135 }
136 Fragment::Multi { k, keys } => {
137 if ctx.inner_descriptor != Descriptor::Wsh {
139 return Err(DescriptorVisitorError::InvalidFragmentForDescriptor {
140 position: node.position,
141 expected: Descriptor::Wsh,
142 found: ctx.inner_descriptor.clone(),
143 });
144 }
145 }
146 Fragment::MultiA { k, keys } => {
147 if ctx.inner_descriptor != Descriptor::Tr {
149 return Err(DescriptorVisitorError::InvalidFragmentForDescriptor {
150 position: node.position,
151 expected: Descriptor::Tr,
152 found: ctx.inner_descriptor.clone(),
153 });
154 }
155 }
156 Fragment::Identity { identity_type, x } => {
157 self.visit_ast_by_index(ctx, *x)?;
158 }
159 }
160 Ok(())
161 }
162}