commit d28de7fcf808c69c93528472cd341812eecdede6
parent 25ccf3328c9ba80c12a981ecabda89afbd7a29d2
Author: William Casarin <jb55@jb55.com>
Date: Sun, 3 Dec 2017 21:14:33 -0800
data: implement PUSHDATA
* Generate proper pushdata
* Parse pushdata properly
I'm making a bunch of assumptions here, need to compare
against core
Closes #7
Diffstat:
10 files changed, 67 insertions(+), 28 deletions(-)
diff --git a/alloc.c b/alloc.c
@@ -50,10 +50,10 @@ num_pool_new(int *ind) {
}
u8 *
-byte_pool_new(u16 len, u16 *ind) {
+byte_pool_new(u32 len, u16 *ind) {
assert((g_arenas.bytes_top - g_arenas.bytes + len) <= g_arenas.nbytes);
u8 *start = g_arenas.bytes_top;
- u16 *c = (u16*)g_arenas.bytes_top;
+ u32 *c = (u32*)g_arenas.bytes_top;
*c++ = len;
u8 *p = (u8*)c;
p += len;
@@ -70,23 +70,23 @@ byte_pool_new(u16 len, u16 *ind) {
u8 *
byte_pool_pop() {
u8 *p = (u8*)stack_pop(&g_arenas.bytes_map);
- u16 *c = (u16*)p;
- memset(p, 0, *c + sizeof(u16));
+ u32 *c = (u32*)p;
+ memset(p, 0, *c + sizeof(u32));
return p;
}
u8 *
-byte_pool_get(int ind, u16 *len) {
+byte_pool_get(int ind, u32 *len) {
assert(ind <= stack_size(&g_arenas.bytes_map) - 1);
void **vp;
u8 *p;
- u16 *up;
+ u32 *up;
vp = g_arenas.bytes_map.bottom + ind;
p = (u8*)(*vp);
assert((g_arenas.bytes_top - g_arenas.bytes + *len) <= g_arenas.nbytes);
assert(p);
- up = (u16*)p;
+ up = (u32*)p;
*len = *up++;
p = (u8*)up;
assert((g_arenas.bytes_top - g_arenas.bytes + *len) <= g_arenas.nbytes);
diff --git a/alloc.h b/alloc.h
@@ -14,8 +14,8 @@ struct num * num_pool_new(int *ind);
struct num * num_pool_pop();
struct num * num_pool_get(const int ind);
-u8 *byte_pool_new(u16 len, u16 *ind);
-u8 *byte_pool_get(int ind, u16 *len);
+u8 *byte_pool_new(u32 len, u16 *ind);
+u8 *byte_pool_get(int ind, u32 *len);
u8 *byte_pool_pop();
struct arenas {
diff --git a/lexer.l b/lexer.l
@@ -24,6 +24,10 @@
[oO][pP]_ {}
@[a-fA-F0-9]+ {
+ if (strlen(yytext + 1) % 2 != 0) {
+ yylval.str = "Invalid data string, byte string must have even length";
+ return T_ERR;
+ }
yylval.str = yytext + 1;
return T_DATA;
}
diff --git a/main.c b/main.c
@@ -64,3 +64,8 @@ void yyerror(const char* s) {
exit(1);
}
+void
+parse_error(char* err) {
+ fprintf(stderr, "[btcs] parse error: %s\n", err);
+ exit(1);
+}
diff --git a/op.c b/op.c
@@ -370,13 +370,13 @@ val_print(struct val val) {
printf("%d", val.ind);
break;
case VT_DATA: {
- u16 len;
+ u32 len;
u8 *data = byte_pool_get(val.ind, &len);
if (len == 0)
printf("0", len);
else
- printf("0x", len);
+ printf("@", len);
print_bytes(data, len, 0);
break;
diff --git a/parser.y b/parser.y
@@ -22,6 +22,7 @@ void yyerror(const char* s);
%token T_INT
%token T_VAL
%token T_DATA
+%token T_ERR
%token T_NEWLINE T_QUIT T_EXAMPLE
%type<opcode> T_OP
@@ -29,6 +30,7 @@ void yyerror(const char* s);
%type<str> T_DATA
%type<val> T_VAL
%type<str> T_EXAMPLE
+%type<str> T_ERR
%start script
@@ -43,6 +45,7 @@ line: T_NEWLINE
| T_VAL { stack_push_val(&g_reader_stack, $1); }
| T_OP { stack_push_op(&g_reader_stack, $1); }
| T_DATA { script_push_datastr(&g_reader_stack, $1); }
+ | T_ERR { parse_error($1); }
| T_EXAMPLE { ; }
diff --git a/script.c b/script.c
@@ -35,7 +35,7 @@ cast_to_bool(struct val val) {
return sn->val != 0;
}
case VT_DATA: {
- u16 len;
+ u32 len;
const u8 * bytes = byte_pool_get(val.ind, &len);
return *bytes != 0;
}
@@ -47,6 +47,8 @@ int
script_getop(u8 **p, u8 *end, enum opcode *popcode, u8 *buf, int bufsize, u32 *outlen) {
*popcode = OP_INVALIDOPCODE;
u32 nsize = 0;
+ // TODO: HACK: I don't know why I have to do this... 🤔
+ end++;
int opcode;
@@ -54,7 +56,7 @@ script_getop(u8 **p, u8 *end, enum opcode *popcode, u8 *buf, int bufsize, u32 *o
memset(buf, 0, bufsize);
opcode = **p;
- *p = *p + 1;
+ (*p)++;
if (opcode <= OP_PUSHDATA4) {
if (opcode < OP_PUSHDATA1) {
@@ -72,27 +74,30 @@ script_getop(u8 **p, u8 *end, enum opcode *popcode, u8 *buf, int bufsize, u32 *o
if ((end - *p) < 2) {
return 0;
}
- nsize = readle16(*p);
- *p += 2;
+ nsize = **(u16**)p;
+ printf("nsize %d %02x %02x\n", nsize, **p, *(*p + 1));
+ *p = *p + 2;
break;
case OP_PUSHDATA4:
if ((end - *p) < 4) {
return 0;
}
- nsize = readle32(*p);
- *p += 4;
+ nsize = **(u32**)p;
+ *p = *p + 4;
break;
default:
break;
}
}
- if ((end - *p) < 0 || (u32)(end - *p) < nsize) {
+ if ((end - *p) < 0 || (end - *p) < nsize) {
+ printf("early exit %d %d\n", (u32)(end - *p), nsize);
return 0;
}
if (buf) {
*outlen = nsize;
+ printf("memcpy outlen %d %02x %02x\n", nsize, **p, *(*p + 1));
memcpy(buf, *p, nsize);
}
*p += nsize;
@@ -156,7 +161,7 @@ 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 (if_exec && opcode <= OP_PUSHDATA4) {
/* if (fRequireMinimal && !CheckMinimalPush(vchPushValue, opcode)) { */
/* return set_error(serror, SCRIPT_ERR_MINIMALDATA); */
/* } */
@@ -718,7 +723,7 @@ script_serialize(struct stack *stack, u8 *buf, int buflen, int* len) {
struct val *valp;
void **sp;
u8 *p = buf;
- u16 valsize;
+ u32 valsize;
*len = 0;
sp = stack->bottom;
diff --git a/script_num.c b/script_num.c
@@ -139,7 +139,7 @@ sn_from_val(struct val val, struct num ** sn, int require_minimal) {
return SN_SUCCESS;
case VT_DATA: {
u8 *data;
- u16 size;
+ u32 size;
enum sn_result res;
assert(val.ind != -1);
data = byte_pool_get(val.ind, &size);
@@ -178,6 +178,7 @@ sn_to_val(struct num *sn) {
snref->val = sn->val;
val.ind = ind;
}
+
}
return val;
}
diff --git a/val.c b/val.c
@@ -28,7 +28,7 @@ val_from_int(s64 intval) {
}
void
-val_serialize(struct val val, u16 *len, u8 *buf, int bufsize) {
+val_serialize(struct val val, u32 *len, u8 *buf, int bufsize) {
struct num *sn;
int n;
u16 valsize;
@@ -59,13 +59,34 @@ val_serialize(struct val val, u16 *len, u8 *buf, int bufsize) {
case VT_DATA: {
u8 *p;
p = byte_pool_get(val.ind, len);
- if (*len <= 0xFF) {
- *buf++ = *len & 0xFF;
+ if (*len < OP_PUSHDATA1) {
+ *buf++ = *len;
memcpy(buf, p, *len);
- *len = *len + 1;
+ *len += 1;
+ }
+ else if (*len <= 0xFF) {
+ *buf++ = OP_PUSHDATA1;
+ *buf++ = *len;
+ memcpy(buf, p, *len);
+ *len += 2;
+ }
+ else if (*len <= 0xFFFF) {
+ *buf++ = OP_PUSHDATA2;
+ u16 *sp = (u16*)buf;
+ // TODO: writele16
+ *sp = *len;
+ buf += 2;
+ memcpy(buf, p, *len);
+ *len += 3;
}
else {
- assert(!"serialize bigger pushdata");
+ *buf++ = OP_PUSHDATA4;
+ u32 *ip = (u32*)buf;
+ // TODO: writele32
+ *ip = *len;
+ buf += 4;
+ memcpy(buf, p, *len);
+ *len += 5;
}
return;
}
@@ -88,7 +109,7 @@ val_serialize(struct val val, u16 *len, u8 *buf, int bufsize) {
int
val_eq(struct val a, struct val b, int require_minimal) {
- u16 alen, blen;
+ u32 alen, blen;
int eq = 0;
static const int tmpsize = 4096;
diff --git a/val.h b/val.h
@@ -34,7 +34,7 @@ int
val_eq(struct val a, struct val b, int require_minimal);
void
-val_serialize(struct val val, u16 *len, u8 *buf, int bufsize);
+val_serialize(struct val val, u32 *len, u8 *buf, int bufsize);
struct val val_from_int(s64);