@@ -58,19 +58,47 @@ fn tx::sighash::tr_leaf($tx, $vin, $script_leaf, $utxos, $sighash_ty) = psbt::si
58
58
59
59
// TOOD tx::sighash::sw0() with just the signed utxo & tx::sighash::presw() with just the utxo's script
60
60
61
+ //
62
+ // Script Looping utilities
63
+ //
64
+
65
+ // Loop unrolling: run $loop_body as long as $condition is met, up to $max_iterations times.
66
+ // $loop_body can be a Script or a Function that accepts the iteration count and returns a Script.
67
+ // For example: `<num> unrollLoop(50, `OP_DUP 0 OP_GREATERTHANOREQUAL`, `OP_1SUB`)` to count down from <num> to 0, for <num>s of up to 50
68
+ // more advanced example with some comments: https://min.sc/v0.3/#gist=758c25489869d77d4ef624ea43f18c49
69
+ fn unrollLoop($max_iterations, $condition, $loop_body) {
70
+ $body_fn = if isFunction($loop_body) then $loop_body else |_| $loop_body;
71
+
72
+ fn _unrollLoop($i) =
73
+ if $i < $max_iterations then `$condition OP_IF $body_fn($i) _unrollLoop($i+1) OP_ENDIF`
74
+ else `$condition OP_NOT OP_VERIFY` // fail the script if the condition is still met after $max_iterations
75
+ ;
76
+ _unrollLoop(0)
77
+ }
78
+
79
+ // Read the top stack item as the number of times to run $for_body
80
+ // Example with accumulator: `0 <num> unrollFor(50, `OP_DUP OP_ROT OP_ADD OP_SWAP`)` to sum the numbers from <num> to 1
81
+ fn unrollFor($max_iterations, $for_body) {
82
+ $body_fn = if isFunction($for_body) then $for_body else |_| $for_body;
83
+ `
84
+ unrollLoop($max_iterations, `OP_DUP OP_0NOTEQUAL`, |$i| `$body_fn($i) OP_1SUB`)
85
+ OP_DROP // drop the counter (always 0 by now)
86
+ `
87
+ }
88
+
61
89
//
62
90
// Script Altstack manipulation
63
91
//
64
92
65
93
// ROLL/PICK from the altstack, for static $n
66
94
fn rollAlt($n) = `
67
95
OP_FROMALTSTACK*$n
68
- {`OP_SWAP OP_TOALTSTACK`*($n - 1)}
96
+ {`OP_SWAP OP_TOALTSTACK`*($n- 1)}
69
97
`;
70
98
fn pickAlt($n) = `
71
99
OP_FROMALTSTACK*$n
72
100
OP_DUP OP_TOALTSTACK
73
- {`OP_SWAP OP_TOALTSTACK`*($n - 1)}
101
+ {`OP_SWAP OP_TOALTSTACK`*($n- 1)}
74
102
`;
75
103
76
104
// ROLL/PICK from the altstack, using the number at the top of the stack as the depth
@@ -107,34 +135,6 @@ fn nFromAlt($max_n) = `
107
135
unrollFor($max_n, `OP_FROMALTSTACK OP_ROT*2`)
108
136
`;
109
137
110
- //
111
- // Script Looping utilities
112
- //
113
-
114
- // Loop unrolling: run $loop_body as long as $condition is met, up to $max_iterations times
115
- // $loop_body can be a Script or a Function that accepts the iteration count and returns a Script.
116
- // For example: `<num> unrollLoop(50, `OP_DUP 0 OP_GREATERTHANOREQUAL`, `OP_1SUB`)` to count down from <num> to 0, for <num>s of up to 50
117
- // more advanced example with some comments: https://min.sc/v0.3/#gist=758c25489869d77d4ef624ea43f18c49
118
- fn unrollLoop($max_iterations, $condition, $loop_body) {
119
- $body_fn = if isFunction($loop_body) then $loop_body else |_| $loop_body;
120
-
121
- fn _unrollLoop($i) =
122
- if $i < $max_iterations then `$condition OP_IF $body_fn($i) _unrollLoop($i+1) OP_ENDIF`
123
- else `$condition OP_NOT OP_VERIFY` // fail the script if the condition is still met after $max_iterations
124
- ;
125
- _unrollLoop(0)
126
- }
127
-
128
- // Read the top stack item as the number of times to run $for_body
129
- // Example with accumulator: `0 <num> unrollFor(50, `OP_DUP OP_ROT OP_ADD OP_SWAP`)` to sum the numbers from <num> to 1
130
- fn unrollFor($max_iterations, $for_body) {
131
- $body_fn = if isFunction($for_body) then $for_body else |_| $for_body;
132
- `
133
- unrollLoop($max_iterations, `OP_DUP OP_0NOTEQUAL`, |$i| `$body_fn($i) OP_1SUB`)
134
- OP_DROP // drop the counter (always 0 by now)
135
- `
136
- }
137
-
138
138
//
139
139
// Script Conditional control structures
140
140
//
@@ -200,14 +200,14 @@ fn select($scripts) =
200
200
//
201
201
202
202
MARK_SCRIPT=true;
203
- MARK_CTX="" ;
203
+ MARK_CTX=[] ;
204
204
// SCRIPT_MARKER_MAGIC available from Rust
205
205
206
206
dyn fn mark($kind, $body) = if !MARK_SCRIPT then `` else
207
- `SCRIPT_MARKER_MAGIC OP_DROP $kind OP_DROP {MARK_CTX+ str($body)} OP_DROP`;
208
- dyn fn mark::comment($comment) = mark("comment", $comment);
209
- dyn fn mark::label($name) = mark("label", $name);
207
+ `SCRIPT_MARKER_MAGIC OP_DROP $kind OP_DROP str($body) OP_DROP`;
208
+ dyn fn mark::comment($comment) = mark("comment", join(MARK_CTX+[str( $comment)], " · ") );
209
+ dyn fn mark::label($name) = mark("label", join(MARK_CTX+[str( $name)], "__") );
210
210
dyn fn mark::ctx($$context, $$fn) {
211
- MARK_CTX = MARK_CTX + $$context;
211
+ MARK_CTX = MARK_CTX + [ str( $$context) ] ;
212
212
$$fn()
213
213
}
0 commit comments