btcs

bitcoin script parser/evaluator/compiler/decompiler
git clone git://jb55.com/btcs
Log | Files | Refs | README | LICENSE

commit f342f554abe8c34412de13fdda91236b457f3598
parent a8cf965dc00ba966616b9b85995c47aa332333d3
Author: William Casarin <jb55@jb55.com>
Date:   Tue, 19 Dec 2017 10:49:38 -0800

opcode: implement if opcodes

Diffstat:
Mscript.c | 31++++++++++++++++++++++++++++---
Mval.h | 2++
Mvalstack.h | 14++++++++++++++
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 */