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