commit f342f554abe8c34412de13fdda91236b457f3598
parent a8cf965dc00ba966616b9b85995c47aa332333d3
Author: William Casarin <jb55@jb55.com>
Date: Tue, 19 Dec 2017 10:49:38 -0800
opcode: implement if opcodes
Diffstat:
3 files changed, 44 insertions(+), 3 deletions(-)
diff --git a/script.c b/script.c
@@ -30,6 +30,8 @@ int
cast_to_bool(struct val val) {
// TODO: implement cast_to_bool
switch (val.type) {
+ case VT_SMALLINT:
+ return val.ind != 0;
case VT_SCRIPTNUM: {
struct num *sn = num_pool_get(val.ind);
return sn->val != 0;
@@ -112,6 +114,7 @@ script_eval(u8 *script, size_t script_size, struct stack *stack) {
u8 *p = script;
u8 *top = script + script_size;
static char tmpbuf[32];
+ enum opcode opcode;
static const struct val val_true = {.type = VT_SMALLINT, .ind = 1};
static const struct val val_false = {.type = VT_SMALLINT, .ind = 0};
static const struct num bn_one = {.val = 1, .ind = -1};
@@ -131,9 +134,9 @@ script_eval(u8 *script, size_t script_size, struct stack *stack) {
while (p < top) {
c++;
- enum opcode opcode;
script_getop(&p, top, &opcode, (u8*)tmpbuf, ARRAY_SIZE(tmpbuf), &tmplen);
- int if_exec = !stack_size(ifstack);
+ int if_exec = !stack_any_val(ifstack, falseval);
+
// Note OP_RESERVED does not count towards the opcode limit.
if (opcode > OP_16 && ++op_count > MAX_OPS_PER_SCRIPT)
SCRIPTERR("MAX_OPS_PER_SCRIPT");
@@ -209,6 +212,7 @@ script_eval(u8 *script, size_t script_size, struct stack *stack) {
if (stack_size(stack) < 1)
return SCRIPTERR("SCRIPT_ERR_UNBALANCED_CONDITIONAL");
struct val val = stack_top_val(stack, -1);
+ // TODO: minimal if?
/* if (sigversion == SIGVERSION_WITNESS_V0 && (flags & SCRIPT_VERIFY_MINIMALIF)) { */
/* if (vch.size() > 1) */
/* return SCRIPTERR(SCRIPT_ERR_MINIMALIF); */
@@ -220,10 +224,28 @@ script_eval(u8 *script, size_t script_size, struct stack *stack) {
ifval = !ifval;
stack_pop(stack);
}
- stack_push_small(int, ifstack, &ifval);
+ stack_push_val(ifstack, smallintval(ifval));
+ }
+ break;
+
+ case OP_ELSE:
+ {
+ if (stack_size(ifstack) == 0)
+ return SCRIPTERR("SCRIPT_ERR_UNBALANCED_CONDITIONAL");
+ struct val v = stack_pop_val(ifstack);
+ assert(v.type == VT_SMALLINT);
+ v.ind = !v.ind;
+ stack_push_val(ifstack, v);
}
break;
+ case OP_ENDIF:
+ {
+ if (stack_size(ifstack) == 0)
+ return SCRIPTERR("SCRIPT_ERR_UNBALANCED_CONDITIONAL");
+ stack_pop(ifstack);
+ }
+ break;
case OP_RETURN:
{
@@ -629,6 +651,9 @@ script_eval(u8 *script, size_t script_size, struct stack *stack) {
}
}
+ if (stack_size(ifstack) != 0)
+ return SCRIPTERR("SCRIPT_ERR_UNBALANCED_CONDITIONAL");
+
stack_free(altstack);
stack_free(ifstack);
return 1;
diff --git a/val.h b/val.h
@@ -25,6 +25,8 @@ struct val {
};
#define smallintval(n) ((struct val){ .type = VT_SMALLINT, .ind = n })
+#define falseval smallintval(0)
+#define trueval smallintval(1)
// we want val to fit into the size of a 32-bit pointer
STATIC_ASSERT(sizeof(struct val) <= 4, val_doesnt_fit_in_stack);
diff --git a/valstack.h b/valstack.h
@@ -54,4 +54,18 @@ stack_push_op(struct stack *stack, enum opcode opcode) {
stack_push_val(stack, val);
}
+static inline int
+stack_any_val(struct stack *stack, struct val val) {
+ void **p = stack->bottom;
+ struct val *cval;
+
+ while (p < stack->top) {
+ cval = (struct val*)p;
+ if (val.type == cval->type && val.ind == cval->ind)
+ return 1;
+ }
+
+ return 0;
+}
+
#endif /* BTCS_VALSTACK_H */