commit 907597bddc77066eaf8b624fba10a309d8c34750
parent 270f7597b189064a7b298a14210e35884da8a266
Author: William Casarin <jb55@jb55.com>
Date: Sun, 12 Nov 2017 13:11:05 -0800
IMPLEMENT ALL THE THINGS
not doing any descriptibe commit messages yet... too much churn
Diffstat:
M | Makefile | | | 2 | +- |
M | alloc.c | | | 18 | ++++++++++-------- |
M | alloc.h | | | 11 | ++++++----- |
M | main.c | | | 10 | +++++++--- |
M | op.c | | | 4 | ++++ |
M | op.h | | | 14 | -------------- |
M | parser.y | | | 2 | +- |
M | script.c | | | 107 | ++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------- |
M | test.c | | | 5 | +++-- |
M | val.c | | | 9 | +++++++-- |
M | val.h | | | 27 | ++++----------------------- |
A | valstack.h | | | 55 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
12 files changed, 166 insertions(+), 98 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,5 +1,5 @@
-CFLAGS=-O0 -Ideps -std=c99 -g -Wall -Wno-unused-variable -Wno-unused-function
+CFLAGS=-O0 -Ideps -std=c99 -g -Wall -Wno-unused-variable -Wno-unused-function -Wunreachable-code
DEPS=script.c \
oplookup.c \
diff --git a/alloc.c b/alloc.c
@@ -40,14 +40,16 @@ num_pool_new(int *ind) {
return p;
}
-char *
-byte_pool_new(const u16 len) {
+u8 *
+byte_pool_new(const u16 len, u16 *ind) {
assert(g_arenas.bytes_top - g_arenas.bytes + len <= g_arenas.nbytes);
- char *start = g_arenas.bytes_top;
+ u8 *start = g_arenas.bytes_top;
u16 *c = (u16*)g_arenas.bytes_top;
*c++ = len;
- char *p = (char*)c;
+ u8 *p = (u8*)c;
p += len;
+ *ind = stack_size(&g_arenas.bytes_map);
+ stack_push(&g_arenas.bytes_map, (void*)start);
g_arenas.bytes_top = p;
assert(*p == 0);
return start;
@@ -55,7 +57,7 @@ byte_pool_new(const u16 len) {
// useful for quick alloc/deallocs
-char *
+u8 *
byte_pool_pop() {
char *p = (char*)stack_pop(&g_arenas.bytes_map);
u16 *c = (u16*)p;
@@ -64,15 +66,15 @@ byte_pool_pop() {
}
-char *
+u8 *
byte_pool_get(const int ind, u16 *len) {
char *p;
u16 *up;
- p = (char*)(g_arenas.bytes_map.bottom + ind);
+ p = (u8*)(g_arenas.bytes_map.bottom + ind);
assert(p);
up = (u16*)p;
*len = *(up++);
- p = (char*)up;
+ p = (u8*)up;
return p;
}
diff --git a/alloc.h b/alloc.h
@@ -4,6 +4,7 @@
#include "consts.h"
#include "script_num.h"
+#include "misc.h"
// MAX_OPS_PER_SCRIPT *
#define MAX_PUSHDATA_REFS (MAX_OPS_PER_SCRIPT * MAX_STACK_SIZE)
@@ -12,14 +13,14 @@
struct num * num_pool_new(int *ind);
struct num * num_pool_get(const int ind);
-char * byte_pool_new(const u16 len);
-char * byte_pool_get(const int ind, u16 *len);
-char * byte_pool_pop();
+u8 *byte_pool_new(const u16 len, u16 *ind);
+u8 *byte_pool_get(const int ind, u16 *len);
+u8 *byte_pool_pop();
struct arenas {
struct num *nums;
- char *bytes;
- char *bytes_top;
+ u8 *bytes;
+ u8 *bytes_top;
struct stack bytes_map;
int nbytes;
int num_count;
diff --git a/main.c b/main.c
@@ -18,6 +18,9 @@ int main() {
yyin = stdin;
size_t size;
+ size_t bufsize = MAX_STACK_SIZE * MAX_STACK_SIZE;
+ int compiled_len;
+ u8 *buf = (u8*)malloc(bufsize);
struct stack tmp_stack;
alloc_arenas(0, MAX_STACK_SIZE, MAX_STACK_SIZE * MAX_STACK_SIZE);
stack_init(&tmp_stack);
@@ -27,13 +30,14 @@ int main() {
} while(!feof(yyin));
size = g_reader_buf_top - g_reader_buf;
- script_eval(g_reader_buf, size, &tmp_stack);
+ script_serialize(g_reader_buf, buf, bufsize, &compiled_len);
+ script_eval(buf, size, &tmp_stack);
printf("script: ");
- script_print_ops(g_reader_buf, g_reader_buf_top -);
+ script_print_ops(g_reader_buf, g_reader_buf_top);
printf("stack: ");
script_print_vals(&tmp_stack);
- stack_free(&reader_stack);
+ stack_free(&g_reader_buf);
stack_free(&tmp_stack);
free_arenas(0);
diff --git a/op.c b/op.c
@@ -359,8 +359,12 @@ val_print(struct val val) {
case VT_SCRIPTNUM:
assert(val.ind != -1);
n = num_pool_get(val.ind);
+ assert(n);
printf("sn:%lu", n->val);
break;
+ case VT_OP:
+ printf("op:%d", val.ind);
+ break;
case VT_SMALLINT:
printf("si:%d", val.ind);
break;
diff --git a/op.h b/op.h
@@ -310,20 +310,6 @@ enum opcode op_tokenize(char *);
void val_print(struct val);
const char * val_name(struct val);
-static inline void
-stack_push_val(struct stack *stack, struct val val) {
-#if 1
- printf("pushing val ");
- val_print(val);
- printf("\n");
-#endif
- stack_push_small(struct val, stack, &val);
-}
-
-static inline void
-stack_push_op(struct stack *stack, enum opcode opcode) {
- stack_push_small(enum opcode, stack, &opcode);
-}
#endif /* BCS_OP_H */
diff --git a/parser.y b/parser.y
@@ -30,7 +30,7 @@ script:
;
line: T_NEWLINE
- | T_OP { stack_push_small(enum opcode, &reader_stack, &$1); }
+ | T_OP { stack_push_op(&reader_stack, &$1); }
| T_EXAMPLE { ; }
diff --git a/script.c b/script.c
@@ -4,6 +4,7 @@
#include "script_num.h"
#include "stack.h"
#include "alloc.h"
+#include "valstack.h"
#include <stdio.h>
#define SCRIPTERR(serr) script_add_error(c, opcode, serr)
@@ -35,7 +36,7 @@ cast_to_bool(struct val val) {
}
case VT_DATA: {
u16 len;
- const char * bytes = byte_pool_get(val.ind, &len);
+ const u8 * bytes = byte_pool_get(val.ind, &len);
return *bytes != 0;
}
}
@@ -43,40 +44,62 @@ cast_to_bool(struct val val) {
}
int
-script_getop(u8 **p, u8 *end, enum opcode *opcode, u8 *buf, int bufsize, u32 *outlen) {
+script_getop(u8 **p, u8 *end, enum opcode *popcode, u8 *buf, int bufsize, u32 *outlen) {
+ *popcode = OP_INVALIDOPCODE;
u32 nsize = 0;
- *opcode = *(*p++);
+ int opcode;
- if (*opcode > OP_PUSHDATA4)
- return 1;
+ if (buf)
+ memset(buf, 0, bufsize);
- if (*opcode < OP_PUSHDATA1)
- nsize = *opcode;
- else if (*opcode == OP_PUSHDATA1) {
- if (end - *p < 1)
- return 0;
- nsize = *(*p++);
- }
- else if (*opcode == OP_PUSHDATA2) {
- if (end - *p < 2)
- return 0;
- nsize = readle16(*p);
- *p += 2;
- }
- else if (*opcode == OP_PUSHDATA4) {
- if (end - *p < 4)
+ opcode = **p;
+ *p = *p + 1;
+
+ if (opcode <= OP_PUSHDATA4) {
+ if (opcode < OP_PUSHDATA1) {
+ nsize = opcode;
+ }
+ else {
+ switch (opcode) {
+ case OP_PUSHDATA1:
+ if ((end - *p) < 1) {
+ return 0;
+ }
+ nsize = *(*p++);
+ break;
+ case OP_PUSHDATA2:
+ if ((end - *p) < 2) {
+ return 0;
+ }
+ nsize = readle16(*p);
+ *p += 2;
+ break;
+ case OP_PUSHDATA4:
+ if ((end - *p) < 4) {
+ return 0;
+ }
+ nsize = readle32(*p);
+ *p += 4;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if ((end - *p) < 0 || (u32)(end - *p) < nsize) {
return 0;
- nsize = readle32(*p);
- *p += 4;
- }
+ }
- if (buf) {
- *outlen = nsize;
- memcpy(buf, *p, nsize);
+ if (buf) {
+ *outlen = nsize;
+ memcpy(buf, *p, nsize);
+ }
*p += nsize;
}
+ *popcode = opcode;
+
return 1;
}
@@ -110,10 +133,6 @@ script_eval(u8 *script, size_t script_size, struct stack *stack) {
enum opcode opcode;
script_getop(&p, top, &opcode, (u8*)tmpbuf, ARRAY_SIZE(tmpbuf), &tmplen);
int if_exec = !stack_size(ifstack);
- p++;
- // TODO: pushdata ops
- assert(!(opcode >= OP_PUSHDATA1 && opcode <= OP_PUSHDATA4));
-
// 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");
@@ -137,7 +156,13 @@ script_eval(u8 *script, size_t script_size, struct stack *stack) {
SCRIPTERR("SCRIPT_ERR_DISABLED_OPCODE"); // Disabled opcodes.
}
-
+ if (if_exec && 0 <= opcode && opcode <= OP_PUSHDATA4) {
+ /* if (fRequireMinimal && !CheckMinimalPush(vchPushValue, opcode)) { */
+ /* return set_error(serror, SCRIPT_ERR_MINIMALDATA); */
+ /* } */
+ printf("pushing data of size %d\n", tmplen);
+ stack_push_data(stack, (u8*)tmpbuf, tmplen);
+ } else if (if_exec || (OP_IF <= opcode && opcode <= OP_ENDIF))
switch (opcode) {
case OP_1NEGATE:
case OP_1:
@@ -659,19 +684,23 @@ script_push_int(struct stack *script, s64 intval) {
void
script_serialize(struct stack *stack, u8 *buf, int buflen, int* len) {
- struct val val;
- u8 *huh = (u8*)&val;
+ struct val *valp;
+ void **sp;
u8 *p = buf;
u16 valsize;
*len = 0;
-
- while (stack_size(stack) != 0) {
- val = stack_pop_val(stack);
- printf("%02x %02x %02x %02x | ", huh[0], huh[1], huh[2], huh[3]);
- printf("%d %d\n", val.type, val.ind);
- val_serialize(val, &valsize, p, buflen-(p-buf));
+ sp = stack->bottom;
+
+ while (sp < stack->top) {
+ /* printf("%02x %02x %02x %02x | ", huh[0], huh[1], huh[2], huh[3]); */
+ /* printf("%d %d\n", val.type, val.ind); */
+ valp = (struct val*)sp;
+ val_print(*valp);
+ printf("\n");
+ val_serialize(*valp, &valsize, p, buflen-(p-buf));
p += valsize;
*len += valsize;
assert(p-buf <= buflen);
+ sp++;
}
}
diff --git a/test.c b/test.c
@@ -3,6 +3,7 @@
#include "script.h"
#include "op.h"
#include "alloc.h"
+#include "valstack.h"
#include "tap.c/tap.h"
typedef void (program)(struct stack *script, struct stack *stack,\
@@ -95,8 +96,8 @@ TEST(big_int_serializes_ok) {
0x04, 0xff, 0xff, 0xff, 0x7f, OP_ADD };
static u8 expected_out[] = { 0x05, 0xfe, 0xff, 0xff, 0xff, 0 };
- script_push_int(script, 2147483647);
- script_push_int(script, 2147483647);
+ script_push_int(script, 2147483647UL);
+ script_push_int(script, 2147483647UL);
stack_push_op(script, OP_ADD);
script_serialize(script, buf, ARRAY_SIZE(buf), &len);
diff --git a/val.c b/val.c
@@ -41,9 +41,14 @@ val_serialize(struct val val, u16 *len, u8 *buf, int bufsize) {
*buf = (u8)valsize;
*len = valsize + 1;
return;
+ case VT_OP:
+ *len = 1;
+ *buf = val.ind & 0xFF;
+ return;
case VT_DATA:
assert("!implement val_serialize VT_DATA");
byte_pool_get(val.ind, len);
+ return;
case VT_SMALLINT:
*len = 1;
n = val.ind;
@@ -66,8 +71,8 @@ val_eq(struct val a, struct val b, int require_minimal) {
int eq = 0;
static const int tmpsize = 4096;
- static u8 tmpa[tmpsize];
- static u8 tmpb[tmpsize];
+ static u8 tmpa[4096];
+ static u8 tmpb[4096];
const u8 *abytes, *bbytes;
// TODO: do I need to serialize to compare?
diff --git a/val.h b/val.h
@@ -4,19 +4,21 @@
#include "misc.h"
#include "stack.h"
+#include "op.h"
enum valtype {
VT_SCRIPTNUM=0,
VT_SMALLINT,
+ VT_OP,
VT_DATA,
VT_N
};
// UPDATE VAL_TYPE_BITS if you need more valtypes
-#define VAL_TYPE_BITS 2
+#define VAL_TYPE_BITS 3
/* static const int COMPACT_VAL_BITS = (32-VAL_TYPE_BITS-1); */
-#define VAL_COMPACT_BITS 30
+#define VAL_COMPACT_BITS 29
struct val {
u8 type : VAL_TYPE_BITS;
@@ -29,27 +31,6 @@ struct val {
STATIC_ASSERT(sizeof(struct val) <= 4, val_doesnt_fit_in_stack);
-static inline struct val
-stack_top_val(struct stack *stack, int ind) {
- struct val val;
- stack_top_small(struct val, stack, &val, ind);
- return val;
-}
-
-static inline struct val
-stack_pop_val(struct stack *stack) {
- struct val val;
- val = stack_top_val(stack, -1);
- stack_pop(stack);
- return val;
-}
-
-static inline void
-stack_set_val(struct stack *stack, int ind, struct val val) {
- struct val *pval = (struct val *)(stack->top + ind);
- *pval = val;
-}
-
int
val_eq(struct val a, struct val b, int require_minimal);
diff --git a/valstack.h b/valstack.h
@@ -0,0 +1,55 @@
+
+#ifndef BTCS_VALSTACK_H
+#define BTCS_VALSTACK_H
+
+#include "op.h"
+#include "val.h"
+
+static inline struct val
+stack_top_val(struct stack *stack, int ind) {
+ struct val val;
+ stack_top_small(struct val, stack, &val, ind);
+ return val;
+}
+
+static inline struct val
+stack_pop_val(struct stack *stack) {
+ struct val val;
+ val = stack_top_val(stack, -1);
+ stack_pop(stack);
+ return val;
+}
+
+static inline void
+stack_set_val(struct stack *stack, int ind, struct val val) {
+ struct val *pval = (struct val *)(stack->top + ind);
+ *pval = val;
+}
+
+static inline void
+stack_push_val(struct stack *stack, struct val val) {
+#if 0
+ printf("pushing val ");
+ val_print(val);
+ printf("\n");
+#endif
+ stack_push_small(struct val, stack, &val);
+}
+
+static inline void
+stack_push_data(struct stack *stack, u8 *data, int len) {
+ struct val val = { .type = VT_DATA };
+ u8 *p;
+ u16 ind;
+ byte_pool_new(len, &ind);
+ val.ind = ind;
+ stack_push_val(stack, val);
+}
+
+static inline void
+stack_push_op(struct stack *stack, enum opcode opcode) {
+ struct val val = { .type = VT_OP, .ind = opcode };
+ stack_push_val(stack, val);
+}
+
+#endif /* BTCS_VALSTACK_H */