script: fix macro for future rustc changes

This commit is contained in:
Andrew Poelstra 2016-02-18 17:56:51 +00:00
parent b88d04f0bc
commit 92c3b2459c
1 changed files with 57 additions and 41 deletions

View File

@ -1759,29 +1759,45 @@ fn check_signature(secp: &Secp256k1, sig_slice: &[u8], pk_slice: &[u8], script:
// were really hard to read and verify -- see OP_PICK and OP_ROLL // were really hard to read and verify -- see OP_PICK and OP_ROLL
// for an example of what Rust vector-stack manipulation looks // for an example of what Rust vector-stack manipulation looks
// like. // like.
// Commands can be given in any order, except that `require` should
// always come first and `drop` should always come last, to avoid
// surprises.
macro_rules! stack_opcode { macro_rules! stack_opcode {
($stack:ident($min:expr): ($stack:ident($min:expr): $($cmd:ident $args:tt);*) => ({
$(require $r:expr);* $(stack_opcode_internal!($cmd: $stack, $min, $args);)*
$(copy $c:expr);* });
$(swap ($a:expr, $b:expr));* }
$(perm ($first:expr, $($i:expr),*) );*
$(drop $d:expr);* // The actual commands available to the above macro
) => ({ macro_rules! stack_opcode_internal {
$( $stack.require_n_elems($r); )* (require: $stack:ident, $min:expr, $r:expr) => ({
$stack.require_n_elems($r);
// Record top // Record top
let top = $stack.len(); let top = $stack.len();
// Check stack size // Check stack size
if top < $min { return Err(Error::PopEmptyStack); } if top < $min { return Err(Error::PopEmptyStack); }
// Do copies });
$( let elem = $stack[top - $c].clone(); (copy: $stack:ident, $min:expr, $c:expr) => ({
$stack.push(elem); )* let top = $stack.len();
// Do swaps if top < $min { return Err(Error::PopEmptyStack); }
$( (&mut $stack[..]).swap(top - $a, top - $b); )* let elem = $stack[top - $c].clone();
// Do permutations $stack.push(elem);
$( let first = $first; });
$( (&mut $stack[..]).swap(top - first, top - $i); )* )* (swap: $stack:ident, $min:expr, ($a:expr, $b:expr)) => ({
// Do drops last so that dropped values will be available above let top = $stack.len();
$( $stack.remove(top - $d); )* if top < $min { return Err(Error::PopEmptyStack); }
(&mut $stack[..]).swap(top - $a, top - $b);
});
(perm: $stack:ident, $min:expr, ($first:expr, $($i:expr),*)) => ({
let top = $stack.len();
if top < $min { return Err(Error::PopEmptyStack); }
let first = $first;
$( (&mut $stack[..]).swap(top - first, top - $i); )*
});
(drop: $stack:ident, $min:expr, $d:expr) => ({
let top = $stack.len();
if top < $min { return Err(Error::PopEmptyStack); }
$stack.remove(top - $d);
}); });
} }
@ -2049,7 +2065,7 @@ impl Script {
}; };
if n < 0 { return Err(Error::NegativePick); } if n < 0 { return Err(Error::NegativePick); }
let n = n as usize; let n = n as usize;
stack_opcode!(stack(n + 1): copy n + 1) stack_opcode!(stack(n + 1): copy (n + 1))
} }
opcodes::Ordinary::OP_ROLL => { opcodes::Ordinary::OP_ROLL => {
let n = match stack.pop() { let n = match stack.pop() {
@ -2058,11 +2074,11 @@ impl Script {
}; };
if n < 0 { return Err(Error::NegativeRoll); } if n < 0 { return Err(Error::NegativeRoll); }
let n = n as usize; let n = n as usize;
stack_opcode!(stack(n + 1): copy n + 1 drop n + 1) stack_opcode!(stack(n + 1): copy (n + 1); drop (n + 1))
} }
opcodes::Ordinary::OP_ROT => stack_opcode!(stack(3): perm (1, 2, 3)), opcodes::Ordinary::OP_ROT => stack_opcode!(stack(3): perm (1, 2, 3)),
opcodes::Ordinary::OP_SWAP => stack_opcode!(stack(2): swap (1, 2)), opcodes::Ordinary::OP_SWAP => stack_opcode!(stack(2): swap (1, 2)),
opcodes::Ordinary::OP_TUCK => stack_opcode!(stack(2): copy 2; copy 1 drop 2), opcodes::Ordinary::OP_TUCK => stack_opcode!(stack(2): copy 2; copy 1; drop 2),
opcodes::Ordinary::OP_IFDUP => { opcodes::Ordinary::OP_IFDUP => {
match stack.last().map(|v| read_scriptbool(&v[..])) { match stack.last().map(|v| read_scriptbool(&v[..])) {
None => { return Err(Error::IfEmptyStack); } None => { return Err(Error::IfEmptyStack); }
@ -2412,20 +2428,20 @@ impl Script {
opcodes::Ordinary::OP_VERIFY => op_verify_satisfy!(stack), opcodes::Ordinary::OP_VERIFY => op_verify_satisfy!(stack),
opcodes::Ordinary::OP_TOALTSTACK => { stack.top_to_altstack(); } opcodes::Ordinary::OP_TOALTSTACK => { stack.top_to_altstack(); }
opcodes::Ordinary::OP_FROMALTSTACK => { try!(stack.top_from_altstack()); } opcodes::Ordinary::OP_FROMALTSTACK => { try!(stack.top_from_altstack()); }
opcodes::Ordinary::OP_2DROP => stack_opcode!(stack(2): require 2 drop 1; drop 2), opcodes::Ordinary::OP_2DROP => stack_opcode!(stack(2): require 2; drop 1; drop 2),
opcodes::Ordinary::OP_2DUP => stack_opcode!(stack(2): require 2 copy 2; copy 1), opcodes::Ordinary::OP_2DUP => stack_opcode!(stack(2): require 2; copy 2; copy 1),
opcodes::Ordinary::OP_3DUP => stack_opcode!(stack(3): require 3 copy 3; copy 2; copy 1), opcodes::Ordinary::OP_3DUP => stack_opcode!(stack(3): require 3; copy 3; copy 2; copy 1),
opcodes::Ordinary::OP_2OVER => stack_opcode!(stack(4): require 4 copy 4; copy 3), opcodes::Ordinary::OP_2OVER => stack_opcode!(stack(4): require 4; copy 4; copy 3),
opcodes::Ordinary::OP_2ROT => stack_opcode!(stack(6): require 6 opcodes::Ordinary::OP_2ROT => stack_opcode!(stack(6): require 6;
perm (1, 3, 5); perm (1, 3, 5);
perm (2, 4, 6)), perm (2, 4, 6)),
opcodes::Ordinary::OP_2SWAP => stack_opcode!(stack(4): require 4 opcodes::Ordinary::OP_2SWAP => stack_opcode!(stack(4): require 4;
swap (2, 4); swap (2, 4);
swap (1, 3)), swap (1, 3)),
opcodes::Ordinary::OP_DROP => stack_opcode!(stack(1): require 1 drop 1), opcodes::Ordinary::OP_DROP => stack_opcode!(stack(1): require 1; drop 1),
opcodes::Ordinary::OP_DUP => stack_opcode!(stack(1): require 1 copy 1), opcodes::Ordinary::OP_DUP => stack_opcode!(stack(1): require 1; copy 1),
opcodes::Ordinary::OP_NIP => stack_opcode!(stack(2): require 2 drop 2), opcodes::Ordinary::OP_NIP => stack_opcode!(stack(2): require 2; drop 2),
opcodes::Ordinary::OP_OVER => stack_opcode!(stack(2): require 2 copy 2), opcodes::Ordinary::OP_OVER => stack_opcode!(stack(2): require 2; copy 2),
opcodes::Ordinary::OP_PICK => { opcodes::Ordinary::OP_PICK => {
let top_n = { let top_n = {
let top = stack.peek_mut(); let top = stack.peek_mut();
@ -2435,7 +2451,7 @@ impl Script {
}; };
stack.pop(); stack.pop();
match top_n { match top_n {
Some(n) => stack_opcode!(stack(n + 1): require n + 1 copy n + 1), Some(n) => stack_opcode!(stack(n + 1): require (n + 1); copy (n + 1)),
// The stack will wind up with the 1 and nth inputs being identical // The stack will wind up with the 1 and nth inputs being identical
// with n input-dependent. I can imagine scripts which check this // with n input-dependent. I can imagine scripts which check this
// condition or its negation for various n to get arbitrary finite // condition or its negation for various n to get arbitrary finite
@ -2453,7 +2469,7 @@ impl Script {
}; };
stack.pop(); stack.pop();
match top_n { match top_n {
Some(n) => stack_opcode!(stack(n + 1): require n + 1 copy n + 1 drop n + 1), Some(n) => stack_opcode!(stack(n + 1): require (n + 1); copy (n + 1); drop (n + 1)),
// The stack will wind up reordered, so in principle I could just force // The stack will wind up reordered, so in principle I could just force
// the input to be zero (other n values can be converted to zero by just // the input to be zero (other n values can be converted to zero by just
// manually rearranging the input). The problem is if numeric bounds are // manually rearranging the input). The problem is if numeric bounds are
@ -2461,9 +2477,9 @@ impl Script {
None => { return Err(Error::Unanalyzable); } None => { return Err(Error::Unanalyzable); }
} }
} }
opcodes::Ordinary::OP_ROT => stack_opcode!(stack(3): require 3 perm (1, 2, 3)), opcodes::Ordinary::OP_ROT => stack_opcode!(stack(3): require 3; perm (1, 2, 3)),
opcodes::Ordinary::OP_SWAP => stack_opcode!(stack(2): require 3 swap (1, 2)), opcodes::Ordinary::OP_SWAP => stack_opcode!(stack(2): require 3; swap (1, 2)),
opcodes::Ordinary::OP_TUCK => stack_opcode!(stack(2): require 2 copy 2; copy 1 drop 2), opcodes::Ordinary::OP_TUCK => stack_opcode!(stack(2): require 2; copy 2; copy 1; drop 2),
opcodes::Ordinary::OP_IFDUP => { opcodes::Ordinary::OP_IFDUP => {
let top_bool = { let top_bool = {
let top = stack.peek_mut(); let top = stack.peek_mut();
@ -2471,7 +2487,7 @@ impl Script {
}; };
match top_bool { match top_bool {
Some(false) => { } Some(false) => { }
Some(true) => { stack_opcode!(stack(1): require 1 copy 1); } Some(true) => { stack_opcode!(stack(1): require 1; copy 1); }
None => { None => {
let mut stack_true = stack.clone(); let mut stack_true = stack.clone();
// Try pushing false and see what happens // Try pushing false and see what happens