dubp_documents_parser/raw_text/
wallet_script.rs1use crate::*;
2
3pub fn wallet_script_from_str(source: &str) -> Result<WalletScriptV10, TextParseError> {
4 let mut pairs = RawDocumentsParser::parse(Rule::output_conds, source)
5 .map_err(|e| TextParseError::PestError(e.into()))?;
6 WalletScriptV10::from_pest_pair(pairs.next().unwrap_or_else(|| unreachable!()))
7 }
9
10impl FromPestPair for WalletScriptV10 {
11 fn from_pest_pair(pair: Pair<Rule>) -> Result<Self, TextParseError> {
12 let mut pairs = pair.into_inner();
13 let term_left_pair = pairs.next().unwrap_or_else(|| unreachable!());
14
15 let mut nodes = SmallVec::new();
16
17 let term_left = parse_term(term_left_pair, &mut nodes);
18 let root = parse_op(term_left, pairs, &mut nodes);
19
20 Ok(WalletScriptV10 { root, nodes })
21 }
22}
23
24impl FromPestPair for WalletConditionV10 {
25 #[inline]
26 fn from_pest_pair(pair: Pair<Rule>) -> Result<Self, TextParseError> {
27 Ok(match pair.as_rule() {
28 Rule::output_cond_sig => WalletConditionV10::Sig(
29 ed25519::PublicKey::from_base58(
30 pair.into_inner()
31 .next()
32 .unwrap_or_else(|| unreachable!())
33 .as_str(),
34 )
35 .unwrap_or_else(|_| unreachable!()),
36 ),
37 Rule::output_cond_xhx => WalletConditionV10::Xhx(
38 Hash::from_hex(
39 pair.into_inner()
40 .next()
41 .unwrap_or_else(|| unreachable!())
42 .as_str(),
43 )
44 .unwrap_or_else(|_| unreachable!()),
45 ),
46 Rule::output_cond_csv => WalletConditionV10::Csv(
47 pair.into_inner()
48 .next()
49 .unwrap_or_else(|| unreachable!())
50 .as_str()
51 .parse()
52 .unwrap_or_else(|_| unreachable!()),
53 ),
54 Rule::output_cond_cltv => WalletConditionV10::Cltv(
55 pair.into_inner()
56 .next()
57 .unwrap_or_else(|| unreachable!())
58 .as_str()
59 .parse()
60 .unwrap_or_else(|_| unreachable!()),
61 ),
62 r => panic!("unexpected rule: {:?}", r), })
64 }
65}
66
67#[inline]
68fn parse_term(pair: Pair<Rule>, nodes: &mut WalletScriptNodesV10) -> WalletSubScriptV10 {
69 match pair.as_rule() {
70 Rule::output_conds_brackets_expr => {
71 let mut pairs = pair.into_inner();
72 let term_left_pair = pairs.next().unwrap_or_else(|| unreachable!());
73 let term_left = parse_term(term_left_pair, nodes);
74 let sub_root = parse_op(term_left, pairs, nodes);
75 let sub_script = WalletSubScriptV10::Brackets(nodes.len());
76 nodes.push(sub_root);
77 sub_script
78 }
79 Rule::output_single_cond => WalletSubScriptV10::Single(
80 WalletConditionV10::from_pest_pair(
81 pair.into_inner().next().unwrap_or_else(|| unreachable!()),
82 )
83 .unwrap_or_else(|_| unreachable!()),
84 ),
85 r => panic!("unexpected rule: {:?}", r), }
87}
88
89fn parse_op(
90 left: WalletSubScriptV10,
91 mut pairs: Pairs<Rule>,
92 nodes: &mut WalletScriptNodesV10,
93) -> WalletSubScriptV10 {
94 if let Some(pair) = pairs.next() {
95 let left_index = nodes.len();
96 nodes.push(left);
97 let next_left_term = parse_term(pairs.next().unwrap_or_else(|| unreachable!()), nodes);
98 let right = parse_op(next_left_term, pairs, nodes);
99 let right_index = nodes.len();
100 nodes.push(right);
101 match pair.as_rule() {
102 Rule::output_cond_op_and => WalletSubScriptV10::And(left_index, right_index),
103 Rule::output_cond_op_or => WalletSubScriptV10::Or(left_index, right_index),
104 r => panic!("unexpected rule: {:?}", r), }
106 } else {
107 left
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114 use crate::tests::*;
115
116 #[test]
117 fn parse_complex_wallet_script_v10() -> Result<(), TextParseError> {
118 let script_v10_str =
119 "SIG(6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i) || (XHX(3EB4702F2AC2FD3FA4FDC46A4FC05AE8CDEE1A85F2AC2FD3FA4FDC46A4FC01CA) && SIG(42jMJtb8chXrpHMAMcreVdyPJK7LtWjEeRqkPw4eSEVp))";
120 let expected_script = WalletScriptV10 {
121 root: WalletSubScriptV10::Or(0, 4),
122 nodes: svec![
123 WalletSubScriptV10::Single(WalletConditionV10::Sig(pk(
124 "6DyGr5LFtFmbaJYRvcs9WmBsr4cbJbJ1EV9zBbqG7A6i"
125 ))),
126 WalletSubScriptV10::Single(WalletConditionV10::Xhx(h(
127 "3EB4702F2AC2FD3FA4FDC46A4FC05AE8CDEE1A85F2AC2FD3FA4FDC46A4FC01CA"
128 ))),
129 WalletSubScriptV10::Single(WalletConditionV10::Sig(pk(
130 "42jMJtb8chXrpHMAMcreVdyPJK7LtWjEeRqkPw4eSEVp"
131 ))),
132 WalletSubScriptV10::And(1, 2),
133 WalletSubScriptV10::Brackets(3),
134 ],
135 };
136
137 assert_eq!(script_v10_str, expected_script.to_string(),);
138
139 assert_eq!(expected_script, wallet_script_from_str(script_v10_str)?);
140
141 Ok(())
142 }
143}