btcs

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

commit 4ec313b99db973af87e88c6421fb4fb228531341
parent 8cb4e6f3311178f0099f637ac1e2eb69a92987d1
Author: William Casarin <jb55@jb55.com>
Date:   Mon,  3 Jun 2019 12:12:42 -0700

fixup val/stack distinction

Diffstat:
Mmain.c | 4++--
Mscript.c | 64+++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Mscript.h | 2+-
Mscript_num.c | 7+++----
Mtest.c | 43++++++++++++++++++++++++++++---------------
Mval.c | 19+++++--------------
Mval.h | 2+-
7 files changed, 91 insertions(+), 50 deletions(-)

diff --git a/main.c b/main.c @@ -51,7 +51,7 @@ int main(int argc, const char *argv[]) { /* size = g_reader_buf_top - g_reader_buf; */ printf("script "); script_print_vals(&g_reader_stack); - script_serialize_minimal(&g_reader_stack, buf, bufsize, &compiled_len); + script_serialize(&g_reader_stack, buf, bufsize, &compiled_len); script_eval(buf, compiled_len, &tmp_stack, &result); printf("script_hex "); @@ -61,7 +61,7 @@ int main(int argc, const char *argv[]) { printf("output "); script_print_vals(&tmp_stack); - script_serialize(&tmp_stack, buf, bufsize, &compiled_len); + stack_serialize(&tmp_stack, buf, bufsize, &compiled_len); printf("output_hex "); for(i = 0; i < compiled_len; ++i) diff --git a/script.c b/script.c @@ -801,8 +801,7 @@ script_push_raw(struct stack *stack, const char *data) { script_push_datastr(stack, data, 1); } -void script_serialize_(struct stack *stack, u8 *buf, int buflen, - int* len, int serialize_minimal) +void script_serialize(struct stack *stack, u8 *buf, int buflen, int* len) { struct val *valp; void **sp; @@ -815,25 +814,64 @@ void script_serialize_(struct stack *stack, u8 *buf, int buflen, /* 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_serialize(*valp, &valsize, p, buflen-(p-buf), - serialize_minimal); + + if (valp->type == VT_SCRIPTNUM) { + struct num *sn = num_pool_get(valp->ind); + + if (sn->val == -1) { + valsize = 1; + *p = OP_1NEGATE; + } + else if (sn->val == 0 ) { + valsize = 1; + *p = 0; + } + else if (sn->val >= 1 && sn->val <= 16 ) { + valsize = 1; + *p = OP_1 - 1 + sn->val; + } + else { + val_serialize(*valp, &valsize, p+1, buflen-((p+1)-buf)); + assert(valsize <= 0xFF); + *p = (u8)valsize; + valsize++; + } + } + else { + val_serialize(*valp, &valsize, p, buflen-(p-buf)); + } + + p += valsize; *len += valsize; assert(p-buf <= buflen); sp++; } -} -void -script_handle_input(struct stack *stack, const char *str) { } -void script_serialize(struct stack *stack, u8 *buf, int buflen, int* len) -{ - script_serialize_(stack, buf, buflen, len, 0); +void stack_serialize(struct stack *stack, u8 *buf, int buflen, int *len) { + struct val *valp; + void **sp; + u8 *p = buf; + u32 valsize; + *len = 0; + 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_serialize(*valp, &valsize, p, buflen-(p-buf)); + + p += valsize; + *len += valsize; + assert(p-buf <= buflen); + sp++; + } } -void script_serialize_minimal(struct stack *stack, u8 *buf, int buflen, int* len) -{ - script_serialize_(stack, buf, buflen, len, 1); +void +script_handle_input(struct stack *stack, const char *str) { } diff --git a/script.h b/script.h @@ -22,7 +22,7 @@ void script_push_raw(struct stack *, const char *str); void script_push_datastr(struct stack *, const char *str, int israw); void script_serialize(struct stack *stack, u8 *buf, int buflen, int* len); -void script_serialize_minimal(struct stack *stack, u8 *buf, int buflen, int* len); +void stack_serialize(struct stack *stack, u8 *buf, int buflen, int* len); extern int g_silence_script_err; extern int g_silence_script_warn; diff --git a/script_num.c b/script_num.c @@ -31,8 +31,7 @@ sn_from_int(s64 n, struct num *sn) { /* } */ -void -sn_serialize(struct num *sn, u8 *buf, int bufsize, u16 *len) { +void sn_serialize(struct num *sn, u8 *buf, int bufsize, u16 *len) { u8 *p = buf; if(sn->val == 0) { @@ -44,7 +43,7 @@ sn_serialize(struct num *sn, u8 *buf, int bufsize, u16 *len) { u64 absvalue = neg ? -(sn->val) : sn->val; while(absvalue) { - *p++ = absvalue & 0xff; + *(p++) = absvalue & 0xff; assert((p - buf) <= bufsize); absvalue >>= 8; } @@ -60,7 +59,7 @@ sn_serialize(struct num *sn, u8 *buf, int bufsize, u16 *len) { // converting to an integral. if (*(p - 1) & 0x80) - *p++ = neg ? 0x80 : 0; + *(p++) = neg ? 0x80 : 0; else if (neg) *(p - 1) |= 0x80; diff --git a/test.c b/test.c @@ -95,20 +95,21 @@ TEST(test_2dup_not_enough_input) { TEST(negative_integer) { static u8 buf[6]; - int len; - u8 in_script[] = { 0x01, 0x82 }; - int res = script_eval(in_script, ARRAY_SIZE(in_script), stack, result); - script_serialize(stack, buf, ARRAY_SIZE(buf), &len); - cmp_data(buf, in_script, len, ARRAY_SIZE(in_script), "negative 2 serializes ok"); + int buflen; + u8 expected_in[] = { 0x01, 0x82 }; + u8 expected_out[] = { 0x82 }; + script_eval(expected_in, sizeof(expected_in), stack, result); + stack_serialize(stack, buf, sizeof(buf), &buflen); + cmp_data(buf, expected_out, buflen, sizeof(expected_out), "negative 2 serializes ok"); } TEST(add_negative_two) { static u8 buf[12]; int len; static u8 in_script[] = { 0x01, 0x82, 0x01, 0x82, OP_ADD }; - static u8 expected_out[] = { 0x01, 0x84 }; - int res = script_eval(in_script, ARRAY_SIZE(in_script), stack, result); - script_serialize(stack, buf, ARRAY_SIZE(buf), &len); + static u8 expected_out[] = { 0x84 }; + script_eval(in_script, ARRAY_SIZE(in_script), stack, result); + stack_serialize(stack, buf, sizeof(buf), &len); cmp_data(buf, expected_out, len, ARRAY_SIZE(expected_out), "add negative two twice"); } @@ -117,7 +118,7 @@ TEST(big_int_serializes_ok) { static u8 buf[12]; static u8 expected_in[] = { 0x04, 0xff, 0xff, 0xff, 0x7f, 0x04, 0xff, 0xff, 0xff, 0x7f, OP_ADD }; - static u8 expected_out[] = { 0x05, 0xfe, 0xff, 0xff, 0xff, 0 }; + static u8 expected_out[] = { 0xfe, 0xff, 0xff, 0xff, 0 }; script_push_int(script, 2147483647LL); script_push_int(script, 2147483647LL); @@ -129,7 +130,7 @@ TEST(big_int_serializes_ok) { "big int input serializes ok"); script_eval(buf, ARRAY_SIZE(expected_in), stack, result); - script_serialize(stack, buf, ARRAY_SIZE(buf), &len); + stack_serialize(stack, buf, ARRAY_SIZE(buf), &len); cmp_data(buf, expected_out, len, ARRAY_SIZE(expected_out), "big int output serializes ok"); @@ -141,16 +142,28 @@ TEST(test_small_int) { static u8 expected_in[] = { 0x01, 0x7f }; script_push_int(script, 127); - script_serialize(script, buf, ARRAY_SIZE(buf), &len); - cmp_data(buf, expected_in, len, ARRAY_SIZE(expected_in), + script_serialize(script, buf, sizeof(buf), &len); + cmp_data(buf, expected_in, len, sizeof(expected_in), "small integer input serializes ok"); - script_eval(buf, ARRAY_SIZE(expected_in), stack, result); - script_serialize(stack, buf, ARRAY_SIZE(buf), &len); - cmp_data(buf, expected_in, len, ARRAY_SIZE(expected_in), + script_eval(buf, sizeof(expected_in), stack, result); + stack_serialize(stack, buf, sizeof(buf), &len); + cmp_data(buf, expected_in, len, sizeof(expected_in), "small integer output serializes ok"); } +void test_sn_serialize_small() { + static u8 buf[2] = {0}; + struct num sn; + static u8 expected_serial[] = { 0x01, 0x7f }; + u16 len; + sn_from_int(127, &sn); + sn_serialize(&sn, buf, sizeof(buf), &len); + + cmp_data(buf, expected_serial, len, sizeof(expected_serial), + "small scriptnum (127) serializes ok"); +} + // TODO test scriptnum overflows // TODO test scriptnum negative zero boolean logic // TODO test scriptnum add into overflow + hash diff --git a/val.c b/val.c @@ -31,11 +31,10 @@ val_from_int(s64 intval) { void val_bytes(struct val val, u32 *len, u8 *buf, int bufsize) { if (val.type == VT_DATA) val.type = VT_RAW; - static const int serialize_minimal = 0; - val_serialize(val, len, buf, bufsize, serialize_minimal); + val_serialize(val, len, buf, bufsize); } -void val_serialize(struct val val, u32 *len, u8 *buf, int bufsize, int serialize_minimal) { +void val_serialize(struct val val, u32 *len, u8 *buf, int bufsize) { struct num *sn; int n; u16 valsize; @@ -44,15 +43,7 @@ void val_serialize(struct val val, u32 *len, u8 *buf, int bufsize, int serialize sn = num_pool_get(val.ind); assert(sn); - if (serialize_minimal) { - if (sn->val == -1) { *len = 1; *buf = OP_1NEGATE; return; } - if (sn->val == 0 ) { *len = 1; *buf = 0; return; } - if (sn->val >= 1 && sn->val <= 16 ) { - *len = 1; - *buf = OP_1 - 1 + sn->val; - return; - } - } + /// TODO: if serialize_minimal sn_serialize(sn, buf, bufsize, &valsize); assert(valsize <= 0xFF); *len = valsize; @@ -130,8 +121,8 @@ val_eq(struct val a, struct val b, int require_minimal) { // TODO: do I need to serialize to compare? /* abytes = val_serialize(a, &alen, require_minimal); */ /* bbytes = val_serialize(b, &blen, require_minimal); */ - val_serialize(a, &alen, tmpa, tmpsize, 0); - val_serialize(b, &blen, tmpb, tmpsize, 0); + val_serialize(a, &alen, tmpa, tmpsize); + val_serialize(b, &blen, tmpb, tmpsize); // TODO: what if they're semantically equivalent? or does that matter // (eg. minimal vs not miniminal)? diff --git a/val.h b/val.h @@ -38,7 +38,7 @@ u32 val_size(struct val val); int val_eq(struct val a, struct val b, int require_minimal); -void val_serialize(struct val val, u32 *len, u8 *buf, int bufsize, int serialize_minimal); +void val_serialize(struct val val, u32 *len, u8 *buf, int bufsize); void val_bytes(struct val val, u32 *len, u8 *buf, int bufsize); struct val val_from_int(s64);