@@ -58,19 +58,47 @@ fn tx::sighash::tr_leaf($tx, $vin, $script_leaf, $utxos, $sighash_ty) = psbt::si
5858
5959// TOOD tx::sighash::sw0() with just the signed utxo & tx::sighash::presw() with just the utxo's script
6060
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+
6189//
6290// Script Altstack manipulation
6391//
6492
6593// ROLL/PICK from the altstack, for static $n
6694fn rollAlt($n) = `
6795 OP_FROMALTSTACK*$n
68- {`OP_SWAP OP_TOALTSTACK`*($n - 1)}
96+ {`OP_SWAP OP_TOALTSTACK`*($n- 1)}
6997`;
7098fn pickAlt($n) = `
7199 OP_FROMALTSTACK*$n
72100 OP_DUP OP_TOALTSTACK
73- {`OP_SWAP OP_TOALTSTACK`*($n - 1)}
101+ {`OP_SWAP OP_TOALTSTACK`*($n- 1)}
74102`;
75103
76104// 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) = `
107135 unrollFor($max_n, `OP_FROMALTSTACK OP_ROT*2`)
108136`;
109137
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-
138138//
139139// Script Conditional control structures
140140//
@@ -200,14 +200,14 @@ fn select($scripts) =
200200//
201201
202202MARK_SCRIPT=true;
203- MARK_CTX="" ;
203+ MARK_CTX=[] ;
204204// SCRIPT_MARKER_MAGIC available from Rust
205205
206206dyn 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)], "__") );
210210dyn fn mark::ctx($$context, $$fn) {
211- MARK_CTX = MARK_CTX + $$context;
211+ MARK_CTX = MARK_CTX + [ str( $$context) ] ;
212212 $$fn()
213213}
0 commit comments