/* * Copyright 2016 Luke Dashjr * * This program is free software; you can redistribute it and/or modify it * under the terms of the standard MIT license. See COPYING for more details. */ #include #include #include #include #include #include #include "blktemplate.h" #include "blkmaker.h" #include "blkmaker_jansson.h" static bool my_sha256(void *digest, const void *buffer, size_t length) { gcry_md_hash_buffer(GCRY_MD_SHA256, digest, buffer, length); return true; } static bool bad_sha256(void *digest, const void *buffer, size_t length) { return false; } static void capabilityname_test() { for (unsigned int i = 0; i < GBT_CAPABILITY_COUNT; ++i) { const gbt_capabilities_t capid = (1 << i); const char * const capname = blktmpl_capabilityname(capid); if (!capname) { continue; } const size_t strlen_capname = strlen(capname); assert(strlen_capname > 0); assert(strlen_capname <= BLKTMPL_LONGEST_CAPABILITY_NAME); assert(blktmpl_getcapability(capname) == capid); } assert(!blktmpl_getcapability("foo")); assert(!blktmpl_capabilityname((uint32_t)1 << GBT_CAPABILITY_COUNT)); } static void blktxn_test(const int c) { struct blktxn_t * const txn = malloc(sizeof(*txn)); memset(txn, c, sizeof(*txn)); blktxn_init(txn); blktxn_clean(txn); free(txn); } static bool caps_includes(const uint32_t caps, const uint32_t expected_caps) { return (caps & expected_caps) == expected_caps; } static void blktmpl_test() { blktemplate_t * const tmpl = blktmpl_create(); { static const uint32_t expected_fresh_caps = GBT_CBTXN | GBT_WORKID | BMM_TIMEINC | BMM_CBAPPEND | BMM_VERFORCE | BMM_VERDROP | BMAb_COINBASE | BMAb_TRUNCATE; assert(caps_includes(blktmpl_addcaps(tmpl), expected_fresh_caps)); } assert(!tmpl->version); assert(!blktmpl_get_longpoll(tmpl)); assert(!blktmpl_get_submitold(tmpl)); blktmpl_free(tmpl); } static bool json_are_equal(json_t * const ja, json_t * const jb) { char *sa, *sb; sa = json_dumps(ja, JSON_COMPACT | JSON_SORT_KEYS); sb = json_dumps(jb, JSON_COMPACT | JSON_SORT_KEYS); const bool rv = !strcmp(sa, sb); free(sa); free(sb); return rv; } static void rulecompare(json_t * const jb, const char * const * const rulelist) { const size_t z = json_array_size(jb); const char *sa; json_t *jc; for (size_t i = 0; i < z; ++i) { assert((jc = json_array_get(jb, i))); assert((sa = json_string_value(jc))); assert(!strcmp(sa, rulelist[i])); } assert(!rulelist[z]); } static void check_request(json_t * const ja, const char * const * const rulelist, uint32_t * const out_caps) { const char *sa; json_t *jb, *jc; assert(json_object_get(ja, "id")); assert((jb = json_object_get(ja, "method"))); assert((sa = json_string_value(jb))); assert(!strcmp(sa, "getblocktemplate")); assert((jb = json_object_get(ja, "params"))); assert(json_is_array(jb)); assert(json_array_size(jb) >= 1); jc = json_array_get(jb, 0); assert(json_is_object(jc)); assert((jb = json_object_get(jc, "maxversion"))); assert(json_number_value(jb) == BLKMAKER_MAX_BLOCK_VERSION); assert((jb = json_object_get(jc, "rules"))); assert(json_is_array(jb)); rulecompare(jb, rulelist); if (out_caps) { *out_caps = 0; if ((jb = json_object_get(jc, "capabilities")) && json_is_array(jb)) { const size_t z = json_array_size(jb); for (size_t i = 0; i < z; ++i) { assert((jc = json_array_get(jb, i))); assert((sa = json_string_value(jc))); uint32_t capid = blktmpl_getcapability(sa); assert(capid); *out_caps |= capid; } } } } static void blktmpl_request_jansson_test_old() { blktemplate_t * const tmpl = blktmpl_create(); json_t *ja, *jb; ja = blktmpl_request_jansson2(0, NULL, blkmk_supported_rules); jb = blktmpl_request_jansson(0, NULL); assert(json_are_equal(ja, jb)); json_decref(jb); check_request(ja, blkmk_supported_rules, NULL); json_decref(ja); blktmpl_free(tmpl); } static void blktmpl_request_jansson_test_custom_rulelist() { blktemplate_t * const tmpl = blktmpl_create(); json_t *ja; const char *custom_rulelist[] = { "abc", "xyz", NULL }; ja = blktmpl_request_jansson2(0, NULL, custom_rulelist); check_request(ja, custom_rulelist, NULL); json_decref(ja); blktmpl_free(tmpl); } static void blktmpl_request_jansson_test_custom_caps_i(json_t * const ja, const uint32_t test_caps) { uint32_t caps; check_request(ja, blkmk_supported_rules, &caps); assert(caps == test_caps); json_decref(ja); } static void blktmpl_request_jansson_test_custom_caps() { blktemplate_t * const tmpl = blktmpl_create(); json_t *ja; uint32_t test_caps = GBT_SERVICE | GBT_LONGPOLL; ja = blktmpl_request_jansson2(test_caps, NULL, blkmk_supported_rules); blktmpl_request_jansson_test_custom_caps_i(ja, test_caps); test_caps |= blktmpl_addcaps(tmpl); ja = blktmpl_request_jansson2(test_caps, NULL, blkmk_supported_rules); blktmpl_request_jansson_test_custom_caps_i(ja, test_caps); blktmpl_free(tmpl); } static void blktmpl_request_jansson_test_longpoll() { blktemplate_t * const tmpl = blktmpl_create(); static const char * const lpid = "mylpid00"; const char *sa; json_t *ja, *jb, *jc; ja = blktmpl_request_jansson2(0, lpid, blkmk_supported_rules); check_request(ja, blkmk_supported_rules, NULL); jb = json_array_get(json_object_get(ja, "params"), 0); assert((jc = json_object_get(jb, "longpollid"))); assert((sa = json_string_value(jc))); assert(!strcmp(sa, lpid)); json_decref(ja); blktmpl_free(tmpl); } static const char *blktmpl_add_jansson_str(blktemplate_t * const tmpl, const char * const s, const time_t time_rcvd) { json_t * const j = json_loads(s, 0, NULL); assert(j); const char * const rv = blktmpl_add_jansson(tmpl, j, time_rcvd); json_decref(j); return rv; } static const time_t simple_time_rcvd = 0x777; static void blktmpl_jansson_simple() { blktemplate_t *tmpl = blktmpl_create(); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":2,\"height\":3,\"bits\":\"1d00ffff\",\"curtime\":777,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512}", simple_time_rcvd)); assert(blktmpl_addcaps(tmpl) == 0); // Until we support merging templates assert(tmpl->version == 2); assert(tmpl->height == 3); assert(!memcmp(tmpl->diffbits, "\xff\xff\0\x1d", 4)); assert(tmpl->curtime == 777); for (int i = 0; i < 7; ++i) { assert(tmpl->prevblk[i] == 0x77777777); } assert(!tmpl->prevblk[7]); assert(tmpl->has_cbvalue); assert(tmpl->cbvalue == 512); // Check clear values assert(tmpl->txncount == 0); assert(tmpl->txns_datasz == 0); assert(tmpl->txns_sigops == 0); assert(!tmpl->cbtxn); assert(!tmpl->workid); assert(!blktmpl_get_longpoll(tmpl)); assert(blktmpl_get_submitold(tmpl)); assert(!tmpl->target); assert(!tmpl->mutations); assert(tmpl->aux_count == 0); assert(!tmpl->rules); assert(!tmpl->unsupported_rule); assert(!tmpl->vbavailable); assert(!tmpl->vbrequired); // Check reasonable default ranges assert(tmpl->sigoplimit >= 20000); assert(tmpl->sizelimit >= 1000000); assert(tmpl->expires >= 60); assert(tmpl->maxtime >= tmpl->curtime + 60); assert(tmpl->maxtimeoff >= 60); assert(tmpl->mintime <= tmpl->curtime - 60); assert(tmpl->mintimeoff <= -60); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":2,\"height\":3,\"bits\":\"1d00ffff\",\"curtime\":777,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":0}", simple_time_rcvd)); assert(tmpl->has_cbvalue); assert(tmpl->cbvalue == 0); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(blktmpl_add_jansson_str(tmpl, "{\"height\":3,\"bits\":\"1d00ffff\",\"curtime\":777,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512}", simple_time_rcvd)); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"bits\":\"1d00ffff\",\"curtime\":777,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512}", simple_time_rcvd)); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(blktmpl_add_jansson_str(tmpl, "{\"version\":2,\"height\":3,\"curtime\":777,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512}", simple_time_rcvd)); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(blktmpl_add_jansson_str(tmpl, "{\"version\":2,\"height\":3,\"bits\":\"1d00ffff\",\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512}", simple_time_rcvd)); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(blktmpl_add_jansson_str(tmpl, "{\"version\":2,\"height\":3,\"bits\":\"1d00ffff\",\"curtime\":777,\"coinbasevalue\":512}", simple_time_rcvd)); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(blktmpl_add_jansson_str(tmpl, "{\"version\":2,\"height\":3,\"bits\":\"1d00ffff\",\"curtime\":777,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\"}", simple_time_rcvd)); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(blktmpl_add_jansson_str(tmpl, "{\"version\":2,\"height\":3,\"bits\":\"1d00ffff\",\"curtime\":777,\"previousblockhash\":\"0??0000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512}", simple_time_rcvd)); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(blktmpl_add_jansson_str(tmpl, "{\"version\":2,\"height\":3,\"bits\":\"1d00ffff\",\"curtime\":777,\"previousblockhash\":\"00000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512}", simple_time_rcvd)); blktmpl_free(tmpl); } static void blktmpl_jansson_bip22_required() { blktemplate_t * const tmpl = blktmpl_create(); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"sigoplimit\":100,\"sizelimit\":1000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaAaaaa00222222220100100000015100000000\",\"required\":true},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62F2cdd80937c9c0857cEDeC005b11d3B902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1],\"fee\":12,\"required\":false,\"sigops\":4},{\"data\":\"01000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000\"}],\"coinbaseaux\":{\"dummy\":\"deadbeef\"},\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"workid\":\"mywork\"}", simple_time_rcvd)); assert(tmpl->version == 3); assert(tmpl->height == 4); assert(!memcmp(tmpl->diffbits, "\xff\x7f\0\x1d", 4)); assert(tmpl->curtime == 877); for (int i = 0; i < 7; ++i) { assert(tmpl->prevblk[i] == 0xa7777777); } assert(!tmpl->prevblk[7]); assert(tmpl->has_cbvalue); assert(tmpl->cbvalue == 640); assert(tmpl->sigoplimit == 100); assert(tmpl->sizelimit == 1000); assert(tmpl->txncount == 3); assert(tmpl->txns); assert(tmpl->txns[0].data); assert(tmpl->txns[0].datasz == 57); assert(!memcmp(tmpl->txns[0].data, "\x01\0\0\0\x01\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\xaa\xaa\xaa\xaa\0\x22\x22\x22\x22\x01\0\x10\0\0\x01\x51\0\0\0\0", 57)); assert(tmpl->txns[0].dependscount == -1); assert(tmpl->txns[0].fee_ == -1); assert(tmpl->txns[0].required); assert(tmpl->txns[0].sigops_ == -1); assert(tmpl->txns[1].data); assert(tmpl->txns[1].datasz == 57); assert(!memcmp(tmpl->txns[1].data, "\x01\0\0\0\x01\x1c\x69\xf2\x12\xe6\x2f\x2c\xdd\x80\x93\x7c\x9c\x08\x57\xce\xde\xc0\x05\xb1\x1d\x3b\x90\x2d\x21\0\x7c\x93\x2c\x1c\x7c\xd2\x0f\0\0\0\0\0\x44\x44\x44\x44\x01\0\x10\0\0\x01\x51\0\0\0\0", 57)); assert(tmpl->txns[1].dependscount == 1); assert(tmpl->txns[1].depends); assert(tmpl->txns[1].depends[0] == 1); assert(tmpl->txns[1].fee_ == 12); assert(!tmpl->txns[1].required); assert(tmpl->txns[1].sigops_ == 4); assert(!memcmp(tmpl->txns[1].hash_, "\x8d\x7e\x01\x67\x43\x9d\xab\x18\x6e\x86\xf9\x13\xb2\x7f\x3a\xc2\x15\x67\xdd\x4e\xde\xf8\x9a\xa8\x01\x64\x99\x67\x8b\x1a\xda\x8e", 32)); assert(tmpl->txns[2].data); assert(tmpl->txns[2].datasz == 57); assert(!memcmp(tmpl->txns[2].data, "\x01\0\0\0\x01\0\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\xaa\xaa\xaa\xaa\0\x55\x55\x55\x55\x01\0\x10\0\0\x01\x51\0\0\0\0", 57)); assert(tmpl->txns[2].dependscount == -1); assert(tmpl->txns[2].fee_ == -1); assert(!tmpl->txns[2].required); assert(tmpl->txns[2].sigops_ == -1); assert(tmpl->cbtxn->data); assert(tmpl->cbtxn->datasz == 64); assert(!memcmp(tmpl->cbtxn->data, "\x01\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xff\xff\xff\xff\x07\x01\x04\x04\xde\xad\xbe\xef\x33\x33\x33\x33\x01\0\x10\0\0\x01\x51\0\0\0\0", 64)); assert(tmpl->aux_count == 1); assert(tmpl->auxs); assert(tmpl->auxs[0].auxname); assert(!strcmp(tmpl->auxs[0].auxname, "dummy")); assert(tmpl->auxs[0].datasz == 4); assert(!memcmp(tmpl->auxs[0].data, "\xde\xad\xbe\xef", 4)); assert(tmpl->workid); assert(!strcmp(tmpl->workid, "mywork")); assert(blktmpl_get_submitold(tmpl)); blktmpl_free(tmpl); } static void blktmpl_jansson_bip22_longpoll() { blktemplate_t *tmpl = blktmpl_create(); const struct blktmpl_longpoll_req *lp; assert(!blktmpl_get_longpoll(tmpl)); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"longpollid\":\"mylpid\"}", simple_time_rcvd)); lp = blktmpl_get_longpoll(tmpl); assert(lp->id); assert(!strcmp(lp->id, "mylpid")); assert(!lp->uri); assert(blktmpl_get_submitold(tmpl)); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"longpollid\":\"myLPid\",\"longpolluri\":\"/LP\",\"submitold\":false}", simple_time_rcvd)); lp = blktmpl_get_longpoll(tmpl); assert(lp->id); assert(!strcmp(lp->id, "myLPid")); assert(lp->uri); assert(!strcmp(lp->uri, "/LP")); assert(!blktmpl_get_submitold(tmpl)); blktmpl_free(tmpl); } static void blktmpl_jansson_bip23_bpe() { blktemplate_t *tmpl = blktmpl_create(); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"expires\":99,\"target\":\"0000000077777777777777777777777777777777777777777777777777777777\"}", simple_time_rcvd)); assert(tmpl->expires == 99); assert(!(*tmpl->target)[0]); for (int i = 1; i < 8; ++i) { assert((*tmpl->target)[i] == 0x77777777); } blktmpl_free(tmpl); } static void blktmpl_jansson_bip23_mutations() { blktemplate_t *tmpl = blktmpl_create(); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"maxtime\":2113929216,\"maxtimeoff\":50,\"mintime\":800,\"mintimeoff\":-50,\"mutable\":[\"prevblock\",\"version/force\"],\"noncerange\":\"01000000f0000000\"}", simple_time_rcvd)); assert(tmpl->maxtime == 2113929216); assert(tmpl->maxtimeoff == 50); assert(tmpl->mintime == 800); assert(tmpl->mintimeoff == -50); // As of right now, implied mutations are not included in the value // assert(tmpl->mutations == (BMM_CBAPPEND | BMM_CBSET | BMM_GENERATE | BMM_TIMEINC | BMM_TIMEDEC | BMM_TXNADD | BMM_PREVBLK | BMM_VERFORCE)); assert(caps_includes(tmpl->mutations, BMM_PREVBLK | BMM_VERFORCE)); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"mutable\":[\"version/reduce\",\"coinbase/append\",\"generation\",\"time\",\"transactions\"],\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"transactions\":[]}", simple_time_rcvd)); assert(tmpl->mutations == (BMM_CBAPPEND | BMM_GENERATE | BMM_TIMEINC | BMM_TIMEDEC | BMM_TXNADD | BMM_VERDROP)); blktmpl_free(tmpl); } static void blktmpl_jansson_bip23_abbrev() { blktemplate_t * const tmpl = blktmpl_create(); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"mutable\":[\"submit/hash\",\"submit/coinbase\",\"submit/truncate\"]}", simple_time_rcvd)); assert(tmpl->mutations == (BMA_TXNHASH | BMAb_COINBASE | BMAb_TRUNCATE)); blktmpl_free(tmpl); } static void blktmpl_jansson_bip9() { blktemplate_t *tmpl; tmpl = blktmpl_create(); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":536871040,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"rules\":[\"csv\"],\"vbavailable\":{\"!segwit\":7}}", simple_time_rcvd)); assert(tmpl->version == 0x20000080); assert(tmpl->rules); assert(tmpl->rules[0]); assert(!strcmp(tmpl->rules[0], "csv")); assert(!tmpl->rules[1]); assert(!tmpl->unsupported_rule); assert(tmpl->vbavailable); assert(tmpl->vbavailable[0]); assert(tmpl->vbavailable[0]->name); assert(!strcmp(tmpl->vbavailable[0]->name, "!segwit")); assert(tmpl->vbavailable[0]->bitnum == 7); assert(!tmpl->vbavailable[1]); assert(!tmpl->vbrequired); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":536871040,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"rules\":[\"csv\"],\"vbavailable\":{\"!segwit\":7},\"vbrequired\":128}", simple_time_rcvd)); assert(tmpl->version == 0x20000080); assert(tmpl->rules); assert(tmpl->rules[0]); assert(!strcmp(tmpl->rules[0], "csv")); assert(!tmpl->rules[1]); assert(!tmpl->unsupported_rule); assert(tmpl->vbavailable); assert(tmpl->vbavailable[0]); assert(tmpl->vbavailable[0]->name); assert(!strcmp(tmpl->vbavailable[0]->name, "!segwit")); assert(tmpl->vbavailable[0]->bitnum == 7); assert(!tmpl->vbavailable[1]); assert(tmpl->vbrequired == 0x80); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":536871040,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"rules\":[\"csv\",\"foo\"],\"vbavailable\":{}}", simple_time_rcvd)); assert(tmpl->version == 0x20000080); assert(tmpl->rules); assert(tmpl->rules[0]); assert(!strcmp(tmpl->rules[0], "csv")); assert(tmpl->rules[1]); assert(!strcmp(tmpl->rules[1], "foo")); assert(!tmpl->rules[2]); assert(tmpl->unsupported_rule); assert(tmpl->vbavailable); assert(!tmpl->vbavailable[0]); assert(!tmpl->vbrequired); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(blktmpl_add_jansson_str(tmpl, "{\"version\":536871040,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"rules\":[\"csv\",\"!foo\"],\"vbavailable\":{}}", simple_time_rcvd)); blktmpl_free(tmpl); } static void test_blktmpl_jansson_floaty() { blktemplate_t *tmpl = blktmpl_create(); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":536871040.0,\"height\":3.0,\"bits\":\"1d00ffff\",\"curtime\":777.0,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512.000,\"sigoplimit\":1000.0,\"sizelimit\":10000.0,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\"},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1.0],\"fee\":12.0,\"sigops\":4.0}],\"expires\":33.0,\"maxtime\":2113929216.0,\"maxtimeoff\":50.0,\"mintime\":800.0,\"mintimeoff\":-50.0,\"rules\":[\"csv\"],\"vbavailable\":{\"!segwit\":7.0},\"vbrequired\":128.0}", simple_time_rcvd)); assert(tmpl->version == 536871040); assert(tmpl->height == 3); assert(!memcmp(tmpl->diffbits, "\xff\xff\0\x1d", 4)); assert(tmpl->curtime == 777); for (int i = 0; i < 7; ++i) { assert(tmpl->prevblk[i] == 0x77777777); } assert(!tmpl->prevblk[7]); assert(tmpl->has_cbvalue); assert(tmpl->cbvalue == 512); assert(tmpl->txncount == 2); assert(tmpl->txns_datasz == 114); assert(tmpl->txns_sigops == -1); assert(tmpl->txns); assert(tmpl->txns[0].data); assert(tmpl->txns[0].datasz == 57); assert(!memcmp(tmpl->txns[0].data, "\x01\0\0\0\x01\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\xaa\xaa\xaa\xaa\0\x22\x22\x22\x22\x01\0\x10\0\0\x01\x51\0\0\0\0", 57)); assert(tmpl->txns[0].dependscount == -1); assert(tmpl->txns[0].fee_ == -1); assert(tmpl->txns[0].sigops_ == -1); assert(tmpl->txns[1].data); assert(tmpl->txns[1].datasz == 57); assert(!memcmp(tmpl->txns[1].data, "\x01\0\0\0\x01\x1c\x69\xf2\x12\xe6\x2f\x2c\xdd\x80\x93\x7c\x9c\x08\x57\xce\xde\xc0\x05\xb1\x1d\x3b\x90\x2d\x21\0\x7c\x93\x2c\x1c\x7c\xd2\x0f\0\0\0\0\0\x44\x44\x44\x44\x01\0\x10\0\0\x01\x51\0\0\0\0", 57)); assert(tmpl->txns[1].dependscount == 1); assert(tmpl->txns[1].depends); assert(tmpl->txns[1].depends[0] == 1); assert(tmpl->txns[1].fee_ == 12); assert(!tmpl->txns[1].required); assert(tmpl->txns[1].sigops_ == 4); assert(!memcmp(tmpl->txns[1].hash_, "\x8d\x7e\x01\x67\x43\x9d\xab\x18\x6e\x86\xf9\x13\xb2\x7f\x3a\xc2\x15\x67\xdd\x4e\xde\xf8\x9a\xa8\x01\x64\x99\x67\x8b\x1a\xda\x8e", 32)); assert(tmpl->rules); assert(tmpl->rules[0]); assert(!strcmp(tmpl->rules[0], "csv")); assert(!tmpl->rules[1]); assert(!tmpl->unsupported_rule); assert(tmpl->vbavailable); assert(tmpl->vbavailable[0]); assert(tmpl->vbavailable[0]->name); assert(!strcmp(tmpl->vbavailable[0]->name, "!segwit")); assert(tmpl->vbavailable[0]->bitnum == 7); assert(!tmpl->vbavailable[1]); assert(tmpl->vbrequired == 0x80); assert(tmpl->sigoplimit == 1000); assert(tmpl->sizelimit == 10000); assert(tmpl->expires == 33); assert(tmpl->maxtime == 2113929216); assert(tmpl->maxtimeoff == 50); assert(tmpl->mintime == 800); assert(tmpl->mintimeoff == -50); blktmpl_free(tmpl); tmpl = blktmpl_create(); // Truncate times (curtime perhaps ought to pull limits closer to it, but it's a fraction of a second anyway, so don't bother) // Ignore coinbasevalue problems if we have coinbasetxn assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":2.0,\"height\":3.0,\"bits\":\"1d00ffff\",\"curtime\":777.5,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512.333,\"expires\":33.4,\"maxtime\":2113929216.6,\"maxtimeoff\":50.3,\"mintime\":800.4,\"mintimeoff\":-50.5,\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000000000\"}}", simple_time_rcvd)); assert(tmpl->version == 2); assert(tmpl->height == 3); assert(!memcmp(tmpl->diffbits, "\xff\xff\0\x1d", 4)); assert(tmpl->curtime == 777); for (int i = 0; i < 7; ++i) { assert(tmpl->prevblk[i] == 0x77777777); } assert(!tmpl->prevblk[7]); assert(!tmpl->has_cbvalue); assert(!tmpl->cbvalue); assert(tmpl->expires == 33); assert(tmpl->maxtime == 2113929216); assert(tmpl->maxtimeoff == 50); assert(tmpl->mintime == 800); assert(tmpl->mintimeoff == -50); blktmpl_free(tmpl); tmpl = blktmpl_create(); // Most values with a fraction should fail assert(blktmpl_add_jansson_str(tmpl, "{\"version\":2.3,\"height\":3.0,\"bits\":\"1d00ffff\",\"curtime\":777.0,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512.000}", simple_time_rcvd)); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(blktmpl_add_jansson_str(tmpl, "{\"version\":2.0,\"height\":3.5,\"bits\":\"1d00ffff\",\"curtime\":777.0,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512.000}", simple_time_rcvd)); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(blktmpl_add_jansson_str(tmpl, "{\"version\":2.0,\"height\":3.0,\"bits\":\"1d00ffff\",\"curtime\":777.0,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512.5}", simple_time_rcvd)); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(blktmpl_add_jansson_str(tmpl, "{\"version\":536871040.0,\"height\":3.0,\"bits\":\"1d00ffff\",\"curtime\":777.0,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512.000,\"rules\":[\"csv\"],\"vbavailable\":{\"!segwit\":7.2},\"vbrequired\":128.0}", simple_time_rcvd)); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(blktmpl_add_jansson_str(tmpl, "{\"version\":536871040.0,\"height\":3.0,\"bits\":\"1d00ffff\",\"curtime\":777.0,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512.000,\"rules\":[\"csv\"],\"vbavailable\":{\"!segwit\":7.0},\"vbrequired\":128.6}", simple_time_rcvd)); blktmpl_free(tmpl); tmpl = blktmpl_create(); // Transaction-related values are optional, so it's safe to ignore them // Even though they could indicate varying rules, we have BIP9 to deal with that, and don't enforce the limits when missing tx info anyway assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3.0,\"height\":3.0,\"bits\":\"1d00ffff\",\"curtime\":777.0,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512.000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\"},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1.5],\"fee\":12.3,\"sigops\":4.6}],\"sigoplimit\":4444.4,\"sizelimit\":323333.3}", simple_time_rcvd)); assert(tmpl->version == 3); assert(tmpl->height == 3); // These should be defaults assert(tmpl->sigoplimit >= 20000); assert(tmpl->sizelimit >= 1000000); assert(tmpl->txncount == 2); assert(tmpl->txns_datasz == 114); assert(tmpl->txns_sigops == -1); assert(tmpl->txns); assert(tmpl->txns[0].data); assert(tmpl->txns[0].datasz == 57); assert(!memcmp(tmpl->txns[0].data, "\x01\0\0\0\x01\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\xaa\xaa\xaa\xaa\0\x22\x22\x22\x22\x01\0\x10\0\0\x01\x51\0\0\0\0", 57)); assert(tmpl->txns[0].dependscount == -1); assert(tmpl->txns[0].fee_ == -1); assert(tmpl->txns[0].sigops_ == -1); assert(tmpl->txns[1].data); assert(tmpl->txns[1].datasz == 57); assert(!memcmp(tmpl->txns[1].data, "\x01\0\0\0\x01\x1c\x69\xf2\x12\xe6\x2f\x2c\xdd\x80\x93\x7c\x9c\x08\x57\xce\xde\xc0\x05\xb1\x1d\x3b\x90\x2d\x21\0\x7c\x93\x2c\x1c\x7c\xd2\x0f\0\0\0\0\0\x44\x44\x44\x44\x01\0\x10\0\0\x01\x51\0\0\0\0", 57)); assert(tmpl->txns[1].dependscount == -1); assert(tmpl->txns[1].fee_ == -1); assert(tmpl->txns[1].sigops_ == -1); assert(!memcmp(tmpl->txns[1].hash_, "\x8d\x7e\x01\x67\x43\x9d\xab\x18\x6e\x86\xf9\x13\xb2\x7f\x3a\xc2\x15\x67\xdd\x4e\xde\xf8\x9a\xa8\x01\x64\x99\x67\x8b\x1a\xda\x8e", 32)); blktmpl_free(tmpl); } static void blktmpl_jansson_submit_data_check(const char * const sa, const int level) { assert(strlen(sa) >= 160); assert(!memcmp(sa, "03000000777777a7777777a7777777a7777777a7777777a7777777a7777777a700000000", 72)); // Don't check merkle root assert(!memcmp(&sa[136], "6d030000ff7f001d", 16)); // Don't check nonce size_t pos = 160; if (level > 0) { assert(!strncmp(&sa[pos], "0401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000", 130)); pos += 130; if (level > 1) { assert(!strcmp(&sa[pos], "01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa0022222222010010000001510000000001000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f000000000044444444010010000001510000000001000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000")); pos += strlen(&sa[pos]); } } if (level >= 0) { assert(sa[pos] == '\0'); } } static void blktmpl_jansson_propose_check(json_t *j, const int level) { const char *sa; j = json_array_get(json_object_get(j, "params"), 0); assert((j = json_object_get(j, "data"))); assert((sa = json_string_value(j))); return blktmpl_jansson_submit_data_check(sa, level); } static void blktmpl_jansson_propose() { blktemplate_t * const tmpl = blktmpl_create(); const char *sa; json_t *j, *ja, *jb; assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"sigoplimit\":100,\"sizelimit\":1000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\",\"required\":true},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1],\"fee\":12,\"required\":false,\"sigops\":4},{\"data\":\"01000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000\"}],\"coinbaseaux\":{\"dummy\":\"deadbeef\"},\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"workid\":\"mywork\"}", simple_time_rcvd)); assert((j = blktmpl_propose_jansson(tmpl, 0, false))); check_request(j, blkmk_supported_rules, NULL); ja = json_array_get(json_object_get(j, "params"), 0); assert((jb = json_object_get(ja, "mode"))); assert((sa = json_string_value(jb))); assert(!strcmp(sa, "proposal")); assert((jb = json_object_get(ja, "workid"))); assert((sa = json_string_value(jb))); assert(!strcmp(sa, "mywork")); blktmpl_jansson_propose_check(j, 2); json_decref(j); tmpl->mutations |= BMAb_COINBASE; assert((j = blktmpl_propose_jansson(tmpl, 0, false))); check_request(j, blkmk_supported_rules, NULL); blktmpl_jansson_propose_check(j, 1); json_decref(j); tmpl->mutations |= BMAb_TRUNCATE; assert((j = blktmpl_propose_jansson(tmpl, 0, false))); check_request(j, blkmk_supported_rules, NULL); blktmpl_jansson_propose_check(j, 0); json_decref(j); blktmpl_free(tmpl); } static void blktmpl_jansson_submit() { blktemplate_t * const tmpl = blktmpl_create(); const char *sa; uint8_t data[76]; int16_t i16; unsigned int dataid; json_t *j, *ja, *jb, *jc; assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"sigoplimit\":100,\"sizelimit\":1000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\",\"required\":true},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1],\"fee\":12,\"required\":false,\"sigops\":4},{\"data\":\"01000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000\"}],\"coinbaseaux\":{\"dummy\":\"deadbeef\"},\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"workid\":\"mywork\",\"mutable\":[\"submit/coinbase\",\"submit/truncate\",\"coinbase/append\"]}", simple_time_rcvd)); assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &dataid)); assert((j = blkmk_submit_foreign_jansson(tmpl, data, 0, 0x12345678))); assert((ja = json_object_get(j, "params"))); assert(json_is_array(ja)); assert(json_array_size(ja) >= 1); assert((sa = json_string_value(json_array_get(ja, 0)))); blktmpl_jansson_submit_data_check(sa, 2); if (json_array_size(ja) >= 2) { assert(json_is_object((jb = json_array_get(ja, 1)))); assert(!json_object_get(jb, "workid")); } json_decref(j); assert((j = blkmk_submit_jansson(tmpl, data, 0, 0x12345678))); assert(json_object_get(j, "id")); assert((ja = json_object_get(j, "method"))); assert((sa = json_string_value(ja))); assert(!strcmp(sa, "submitblock")); assert((ja = json_object_get(j, "params"))); assert(json_is_array(ja)); assert(json_array_size(ja) >= 2); assert((sa = json_string_value(json_array_get(ja, 0)))); blktmpl_jansson_submit_data_check(sa, 0); assert(!memcmp(&sa[72], "512a63f45f96f0269a2d23ccd96bcf0322ee4f60254748e30b89e2b59431aba16d030000ff7f001d12345678", 64)); // merkle root assert(!memcmp(&sa[152], "12345678", 8)); // nonce assert(json_is_object((jb = json_array_get(ja, 1)))); assert((jc = json_object_get(jb, "workid"))); assert((sa = json_string_value(jc))); assert(!strcmp(sa, "mywork")); json_decref(j); assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &dataid)); assert((j = blkmk_submit_jansson(tmpl, data, dataid, 0x12345678))); assert((ja = json_object_get(j, "params"))); assert(json_is_array(ja)); assert(json_array_size(ja) >= 2); assert((sa = json_string_value(json_array_get(ja, 0)))); blktmpl_jansson_submit_data_check(sa, -1); // TODO: Check inserted dataid assert(json_is_object((jb = json_array_get(ja, 1)))); assert((jc = json_object_get(jb, "workid"))); assert((sa = json_string_value(jc))); assert(!strcmp(sa, "mywork")); json_decref(j); blktmpl_free(tmpl); } static void blktmpl_jansson_submitm() { blktemplate_t * const tmpl = blktmpl_create(); const char *sa; uint8_t data[76], *cbtxn, *branches, extranonce[10]; size_t cbextranonceoffset, cbtxnsize; int branchcount; int16_t i16; json_t *j, *ja, *jb, *jc; assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"sigoplimit\":100,\"sizelimit\":1000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\",\"required\":true},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1],\"fee\":12,\"required\":false,\"sigops\":4},{\"data\":\"01000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000\"}],\"coinbaseaux\":{\"dummy\":\"deadbeef\"},\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"workid\":\"mywork\",\"mutable\":[\"submit/coinbase\",\"submit/truncate\",\"coinbase/append\"]}", simple_time_rcvd)); assert(blkmk_get_mdata(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, 1, false)); free(cbtxn); free(branches); memset(&data[36], '\xee', 32); // merkle root, must be provided by caller extranonce[0] = 11; assert((j = blkmk_submitm_jansson(tmpl, data, extranonce, 1, 0x12345678, false))); assert(json_object_get(j, "id")); assert((ja = json_object_get(j, "method"))); assert((sa = json_string_value(ja))); assert(!strcmp(sa, "submitblock")); assert((ja = json_object_get(j, "params"))); assert(json_is_array(ja)); assert(json_array_size(ja) >= 2); assert((sa = json_string_value(json_array_get(ja, 0)))); blktmpl_jansson_submit_data_check(sa, -1); assert(!strcmp(&sa[160], "0401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08010404deadbeef0b333333330100100000015100000000")); assert(json_is_object((jb = json_array_get(ja, 1)))); assert((jc = json_object_get(jb, "workid"))); assert((sa = json_string_value(jc))); assert(!strcmp(sa, "mywork")); json_decref(j); extranonce[0] = 22; assert((j = blkmk_submitm_jansson(tmpl, data, extranonce, 1, 0x12345678, true))); assert((ja = json_object_get(j, "params"))); assert(json_is_array(ja)); assert(json_array_size(ja) >= 2); assert((sa = json_string_value(json_array_get(ja, 0)))); blktmpl_jansson_submit_data_check(sa, -1); assert(!strcmp(&sa[160], "0401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08010404deadbeef1633333333010010000001510000000001000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa0022222222010010000001510000000001000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f000000000044444444010010000001510000000001000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000")); json_decref(j); assert(blkmk_get_mdata(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, 3, false)); free(cbtxn); free(branches); extranonce[0] = 0x11; extranonce[1] = 0x22; extranonce[2] = 0x33; assert((j = blkmk_submitm_jansson(tmpl, data, extranonce, 3, 0x12345678, false))); assert((ja = json_object_get(j, "params"))); assert(json_is_array(ja)); assert(json_array_size(ja) >= 2); assert((sa = json_string_value(json_array_get(ja, 0)))); blktmpl_jansson_submit_data_check(sa, -1); assert(!strcmp(&sa[160], "0401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0a010404deadbeef112233333333330100100000015100000000")); json_decref(j); extranonce[2] = 0xed; assert((j = blkmk_submitm_jansson(tmpl, data, extranonce, 3, 0x12345678, true))); assert((ja = json_object_get(j, "params"))); assert(json_is_array(ja)); assert(json_array_size(ja) >= 2); assert((sa = json_string_value(json_array_get(ja, 0)))); blktmpl_jansson_submit_data_check(sa, -1); assert(!strcmp(&sa[160], "0401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0a010404deadbeef1122ed33333333010010000001510000000001000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa0022222222010010000001510000000001000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f000000000044444444010010000001510000000001000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000")); json_decref(j); blktmpl_free(tmpl); } static void test_blkmk_varint_encode_internal(const unsigned long txncount, const char * const expected, const size_t expectedsz) { blktemplate_t * const tmpl = blktmpl_create(); const char *sa; uint8_t data[76]; int16_t i16; unsigned int dataid; json_t *j, *ja, *jb; j = json_loads("{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"transactions\":[{\"data\":\"01\"}],\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"mutable\":[\"submit/coinbase\"]}", 0, NULL); assert(j); assert((ja = json_object_get(j, "transactions"))); assert((jb = json_array_get(ja, 0))); for (unsigned int i = 2; i < txncount; ++i) { assert(!json_array_append(ja, jb)); } assert(json_array_size(ja) == txncount - 1); assert(!blktmpl_add_jansson(tmpl, j, simple_time_rcvd)); json_decref(j); assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &dataid)); assert((j = blkmk_submit_jansson(tmpl, data, 0, 0x12345678))); assert((ja = json_object_get(j, "params"))); assert(json_is_array(ja)); assert(json_array_size(ja) >= 1); assert((sa = json_string_value(json_array_get(ja, 0)))); blktmpl_jansson_submit_data_check(sa, -1); assert(!memcmp(&sa[160], expected, expectedsz)); // tx count + gentx version json_decref(j); blktmpl_free(tmpl); } static void test_blkmk_varint_encode() { test_blkmk_varint_encode_internal(4, "0401000000", 10); test_blkmk_varint_encode_internal(0xfc, "fc01000000", 10); test_blkmk_varint_encode_internal(0xfd, "fdfd0001000000", 14); test_blkmk_varint_encode_internal(0xffff, "fdffff01000000", 14); test_blkmk_varint_encode_internal(0x10000, "fe0000010001000000", 18); // TODO: Find a way to test 64-bit and upper 32-bit } static void test_blkmk_supports_rule() { for (const char **rule = blkmk_supported_rules; *rule; ++rule) { assert(blkmk_supports_rule(*rule)); char important_rule[strlen(*rule) + 2]; important_rule[0] = '!'; strcpy(&important_rule[1], *rule); assert(!blkmk_supports_rule(important_rule)); } assert(!blkmk_supports_rule("foo")); assert(!blkmk_supports_rule("")); } static void test_blkmk_address_to_script() { uint8_t script[0x100]; assert(blkmk_address_to_script(script, sizeof(script), "1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh") == 25); assert(!memcmp(script, "\x76\xa9\x14\xfe\x14\xc4\xc6\x8d\x83\xda\x61\xfc\x57\x7b\x04\xcb\x6e\xcb\x6d\x31\xba\x1d\x52\x88\xac", 25)); assert(blkmk_address_to_script(script, sizeof(script), "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy") == 23); assert(!memcmp(script, "\xa9\x14\xb4\x72\xa2\x66\xd0\xbd\x89\xc1\x37\x06\xa4\x13\x2c\xcf\xb1\x6f\x7c\x3b\x9f\xcb\x87", 23)); assert(blkmk_address_to_script(script, sizeof(script), "1BitcoinEaterAddressDontSendf59kuE") == 25); assert(!memcmp(script, "\x76\xa9\x14\x75\x9d\x66\x77\x09\x1e\x97\x3b\x9e\x9d\x99\xf1\x9c\x68\xfb\xf4\x3e\x3f\x05\xf9\x88\xac", 25)); assert(blkmk_address_to_script(script, 25, "1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh") == 25); assert(!memcmp(script, "\x76\xa9\x14\xfe\x14\xc4\xc6\x8d\x83\xda\x61\xfc\x57\x7b\x04\xcb\x6e\xcb\x6d\x31\xba\x1d\x52\x88\xac", 25)); assert(blkmk_address_to_script(script, 23, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy") == 23); assert(!memcmp(script, "\xa9\x14\xb4\x72\xa2\x66\xd0\xbd\x89\xc1\x37\x06\xa4\x13\x2c\xcf\xb1\x6f\x7c\x3b\x9f\xcb\x87", 23)); assert(blkmk_address_to_script(script, 25, "1BitcoinEaterAddressDontSendf59kuE") == 25); assert(!memcmp(script, "\x76\xa9\x14\x75\x9d\x66\x77\x09\x1e\x97\x3b\x9e\x9d\x99\xf1\x9c\x68\xfb\xf4\x3e\x3f\x05\xf9\x88\xac", 25)); // Missing last letter assert(!blkmk_address_to_script(script, sizeof(script), "1QATWksNFGeUJCWBrN4g6hGM178Lovm7W")); // Extra letters/symbols assert(!blkmk_address_to_script(script, sizeof(script), "1QATWksNFGeUJCWBrN4g6hGM178Lovm7Whz")); assert(!blkmk_address_to_script(script, sizeof(script), "1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh\xff")); assert(!blkmk_address_to_script(script, sizeof(script), "1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh\x01")); assert(!blkmk_address_to_script(script, sizeof(script), "1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh/")); // Missing last byte (decoded) assert(!blkmk_address_to_script(script, sizeof(script), "16FNsF1zNp3bjQuNwgfSdBUwq4CdfGoh")); // Extra byte (decoded) assert(!blkmk_address_to_script(script, sizeof(script), "12mEk2LdJmz4PUumptsyDa8ijHU3QS8Hhh1")); assert(!blkmk_address_to_script(script, sizeof(script), "")); assert(!blkmk_address_to_script(script, sizeof(script), "\x01")); assert(!blkmk_address_to_script(script, sizeof(script), "\xff")); // Too little buffer space assert(blkmk_address_to_script(script, 20, "1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh") == 25); assert(blkmk_address_to_script(script, 0, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy") == 23); assert(blkmk_address_to_script(script, 24, "1BitcoinEaterAddressDontSendf59kuE") == 25); } static void test_blkmk_x_left() { blktemplate_t *tmpl = blktmpl_create(); uint8_t data[76]; int16_t i16; unsigned int dataid, orig_work_left; assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"transactions\":[],\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"expires\":44}", simple_time_rcvd)); assert(blkmk_work_left(tmpl) == 1); assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &dataid)); assert(blkmk_work_left(tmpl) == 0); assert(blkmk_time_left(tmpl, simple_time_rcvd) == 44); assert(blkmk_time_left(tmpl, simple_time_rcvd + 1) == 43); assert(blkmk_time_left(tmpl, simple_time_rcvd + 43) == 1); assert(blkmk_time_left(tmpl, simple_time_rcvd + 50) == 0); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"transactions\":[],\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"mutable\":[\"coinbase/append\"]}", simple_time_rcvd)); orig_work_left = blkmk_work_left(tmpl); assert(orig_work_left > 0xf0); assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &dataid)); assert(blkmk_work_left(tmpl) == orig_work_left - 1); assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &dataid)); assert(blkmk_work_left(tmpl) == orig_work_left - 2); blktmpl_free(tmpl); } static void test_blkmk_get_data() { blktemplate_t *tmpl = blktmpl_create(); uint8_t data[76]; int16_t i16; unsigned int dataid, first_dataid; assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"sigoplimit\":100,\"sizelimit\":1000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\",\"required\":true},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1],\"fee\":12,\"required\":false,\"sigops\":4},{\"data\":\"01000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000\"}],\"coinbaseaux\":{\"dummy\":\"deadbeef\"},\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"workid\":\"mywork\",\"mutable\":[\"submit/coinbase\",\"submit/truncate\",\"coinbase/append\"],\"expires\":32}", simple_time_rcvd)); assert(blkmk_work_left(tmpl) > 0xf0); assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &first_dataid)); assert(first_dataid == 0); assert(i16 == 31 || i16 == 32); assert(!memcmp(data, "\x03\0\0\0\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\0\0\0\0\x51\x2a\x63\xf4\x5f\x96\xf0\x26\x9a\x2d\x23\xcc\xd9\x6b\xcf\x03\x22\xee\x4f\x60\x25\x47\x48\xe3\x0b\x89\xe2\xb5\x94\x31\xab\xa1\x6d\x03\0\0\xff\x7f\0\x1d", 76)); assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd + 4, &i16, &dataid)); assert(dataid == first_dataid + 1); assert(i16 == 27 || i16 == 28); assert(!memcmp(data, "\x03\0\0\0\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\0\0\0\0\x2a\x73\x99\xbc\x0a\x19\xa1\x11\x03\xfc\x3b\x8f\x4b\xe4\0\x68\x18\xea\x3f\x2a\0\xcf\x42\x8b\xd7\x09\x1c\x8d\xe2\xea\xe7\x38\x71\x03\0\0\xff\x7f\0\x1d", 76)); assert(76 == blkmk_get_data(tmpl, data, sizeof(data) + 1, simple_time_rcvd + 8, &i16, &dataid)); assert(dataid == first_dataid + 2); assert(i16 == 23 || i16 == 24); assert(!memcmp(data, "\x03\0\0\0\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\0\0\0\0\xe2\xe4\xbc\x8e\x65\x8b\x52\x2e\xe5\xeb\x69\xd5\xe5\xd4\xa6\x25\xfd\x8f\x32\x2d\x71\x0f\xc0\xb2\x38\xe1\x71\x01\x61\x56\x2c\x2e\x75\x03\0\0\xff\x7f\0\x1d", 76)); // Too-small buffer fails with desired buffer size assert(76 == blkmk_get_data(tmpl, data, sizeof(data) - 1, simple_time_rcvd + 8, &i16, &dataid)); // Make sure dataid wasn't incremented for the failure assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd + 8, &i16, &dataid)); assert(dataid == first_dataid + 3); // Bad hash function should fail blkmk_sha256_impl = bad_sha256; assert(0 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd + 8, &i16, &dataid)); blkmk_sha256_impl = my_sha256; // No more time, fail assert(0 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd + 35, &i16, &dataid)); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"sigoplimit\":100,\"sizelimit\":1000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\",\"required\":true},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1],\"fee\":12,\"required\":false,\"sigops\":4},{\"data\":\"01000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000\"}],\"coinbaseaux\":{\"dummy\":\"deadbeef\"},\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"workid\":\"mywork\",\"expires\":32}", simple_time_rcvd)); // Make sure a non-appendable fails the second get_data assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &first_dataid)); assert(first_dataid == 0); assert(0 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &first_dataid)); // TODO: ensure a scriptsig with <4 bytes cannot be produced through to get_data; but this requires a platform where sizeof(unsigned int) < 4 and no height-in-coinbase... blktmpl_free(tmpl); } static void test_blkmk_get_mdata() { blktemplate_t *tmpl = blktmpl_create(); uint8_t data[76], *cbtxn, *branches; size_t cbextranonceoffset, cbtxnsize; int branchcount; int16_t i16; assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"sigoplimit\":100,\"sizelimit\":1000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\",\"required\":true},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1],\"fee\":12,\"required\":false,\"sigops\":4},{\"data\":\"01000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000\"}],\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"workid\":\"mywork\",\"mutable\":[\"submit/coinbase\",\"submit/truncate\",\"coinbase/append\"],\"expires\":99}", simple_time_rcvd)); assert(blkmk_get_mdata(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, 1, false)); assert(!memcmp(data, "\x03\0\0\0\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\0\0\0\0", 36)); // Skip merkle root assert(!memcmp(&data[68], "\x6d\x03\0\0\xff\x7f\0\x1d", 8)); assert(i16 == 98 || i16 == 99); assert(cbtxnsize == 65); assert(cbextranonceoffset == 49); assert(!memcmp(cbtxn, "\x01\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xff\xff\xff\xff\x08\x01\x04\x04\xde\xad\xbe\xef", 49)); assert(!memcmp(&cbtxn[50], "\x33\x33\x33\x33\x01\0\x10\0\0\x01\x51\0\0\0\0", 65-50)); assert(branchcount == 2); assert(!memcmp(branches, "\x0f\xd2\x7c\x1c\x2c\x93\x7c\0\x21\x2d\x90\x3b\x1d\xb1\x05\xc0\xde\xce\x57\x08\x9c\x7c\x93\x80\xdd\x2c\x2f\xe6\x12\xf2\x69\x1c\x2b\x07\x3c\xb8\x85\xbf\x62\x3b\x1c\xd5\xac\xda\x81\xce\xe8\x9f\xe9\x19\x0e\x10\x85\xff\x54\x98\xc3\x33\x4c\x2c\x63\xf8\xdd\x4d", 64)); free(cbtxn); free(branches); assert(blkmk_get_mdata(tmpl, data, sizeof(data), simple_time_rcvd + 4, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, 3, false)); assert(!memcmp(data, "\x03\0\0\0\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\0\0\0\0", 36)); // Skip merkle root assert(!memcmp(&data[68], "\x71\x03\0\0\xff\x7f\0\x1d", 8)); assert(i16 == 94 || i16 == 95); assert(cbtxnsize == 67); assert(cbextranonceoffset == 49); assert(!memcmp(cbtxn, "\x01\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xff\xff\xff\xff\x0a\x01\x04\x04\xde\xad\xbe\xef", 49)); assert(!memcmp(&cbtxn[52], "\x33\x33\x33\x33\x01\0\x10\0\0\x01\x51\0\0\0\0", 67-52)); assert(branchcount == 2); assert(!memcmp(branches, "\x0f\xd2\x7c\x1c\x2c\x93\x7c\0\x21\x2d\x90\x3b\x1d\xb1\x05\xc0\xde\xce\x57\x08\x9c\x7c\x93\x80\xdd\x2c\x2f\xe6\x12\xf2\x69\x1c\x2b\x07\x3c\xb8\x85\xbf\x62\x3b\x1c\xd5\xac\xda\x81\xce\xe8\x9f\xe9\x19\x0e\x10\x85\xff\x54\x98\xc3\x33\x4c\x2c\x63\xf8\xdd\x4d", 64)); free(cbtxn); free(branches); size_t sizeof_dataid = sizeof(unsigned int); size_t expected_space = sizeof_dataid + 1; assert(blkmk_get_mdata(tmpl, data, sizeof(data), simple_time_rcvd + 8, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, sizeof_dataid, false)); assert(!memcmp(data, "\x03\0\0\0\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\0\0\0\0", 36)); // Skip merkle root assert(!memcmp(&data[68], "\x75\x03\0\0\xff\x7f\0\x1d", 8)); assert(i16 == 90 || i16 == 91); assert(cbtxnsize == 64 + expected_space); assert(cbextranonceoffset == 49); assert(!memcmp(cbtxn, "\x01\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xff\xff\xff\xff", 41)); assert(cbtxn[41] == 7 + expected_space); assert(!memcmp(&cbtxn[42], "\x01\x04\x04\xde\xad\xbe\xef", 7)); assert(!memcmp(&cbtxn[49 + expected_space], "\x33\x33\x33\x33\x01\0\x10\0\0\x01\x51\0\0\0\0", 15)); assert(branchcount == 2); assert(!memcmp(branches, "\x0f\xd2\x7c\x1c\x2c\x93\x7c\0\x21\x2d\x90\x3b\x1d\xb1\x05\xc0\xde\xce\x57\x08\x9c\x7c\x93\x80\xdd\x2c\x2f\xe6\x12\xf2\x69\x1c\x2b\x07\x3c\xb8\x85\xbf\x62\x3b\x1c\xd5\xac\xda\x81\xce\xe8\x9f\xe9\x19\x0e\x10\x85\xff\x54\x98\xc3\x33\x4c\x2c\x63\xf8\xdd\x4d", 64)); free(cbtxn); free(branches); // If hashing fails, so must get_mdata blkmk_sha256_impl = bad_sha256; assert(!blkmk_get_mdata(tmpl, data, sizeof(data) - 1, simple_time_rcvd + 8, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, sizeof_dataid, false)); blkmk_sha256_impl = my_sha256; // Buffer too small must fail assert(!blkmk_get_mdata(tmpl, data, sizeof(data) - 1, simple_time_rcvd + 8, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, sizeof_dataid, false)); // Without cb append/set mutations, we must fail too tmpl->mutations &= ~(BMM_CBAPPEND | BMM_CBSET); assert(!blkmk_get_mdata(tmpl, data, sizeof(data), simple_time_rcvd + 8, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, sizeof_dataid, false)); // ... but only one or the other should be sufficient tmpl->mutations |= BMM_CBAPPEND; assert(blkmk_get_mdata(tmpl, data, sizeof(data), simple_time_rcvd + 8, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, sizeof_dataid, false)); free(cbtxn); free(branches); tmpl->mutations = (tmpl->mutations & ~BMM_CBAPPEND) | BMM_CBSET; assert(blkmk_get_mdata(tmpl, data, sizeof(data), simple_time_rcvd + 8, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, sizeof_dataid, false)); free(cbtxn); free(branches); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"sigoplimit\":100,\"sizelimit\":1000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\",\"required\":true},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1],\"fee\":12,\"required\":false,\"sigops\":4},{\"data\":\"01000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000\"}],\"mutable\":[\"coinbase/append\"]}", simple_time_rcvd)); // No generation transaction, fail assert(!blkmk_get_mdata(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, 1, false)); // Initialising it should make us work though assert(blkmk_init_generation(tmpl, NULL, 0) == 640); assert(blkmk_get_mdata(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, 1, false)); assert(cbtxn[41] >= 4 /* libblkmaker_coinbase_size_minimum */); free(cbtxn); free(branches); blktmpl_free(tmpl); } static const void *my_memmemr(const void * const haystack_p, const size_t haystacklen, const void * const needle, const size_t needlelen) { if (needlelen > haystacklen) return NULL; const uint8_t * const haystack = haystack_p, *p; for (ssize_t i = haystacklen - needlelen; i >= 0; --i) { p = &haystack[i]; if (!memcmp(p, needle, needlelen)) { return p; } } return NULL; } static void test_blkmk_init_generation() { blktemplate_t *tmpl; bool newcb; tmpl = blktmpl_create(); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640}", simple_time_rcvd)); assert(!tmpl->cbtxn); assert(blkmk_init_generation(tmpl, NULL, 0) == 640); assert(tmpl->cbtxn); assert(tmpl->cbtxn->datasz == 62); assert(!memcmp(tmpl->cbtxn->data, "\x01\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xff\xff\xff\xff\x02\x01\x04\xff\xff\xff\xff\x01\x80\x02\0\0\0\0\0\0\0\0\0\0\0", tmpl->cbtxn->datasz)); newcb = false; assert(!blkmk_init_generation3(tmpl, "\0", 1, &newcb)); newcb = true; assert(blkmk_init_generation3(tmpl, "\x04" "test", 5, &newcb)); assert(newcb); assert(tmpl->cbtxn); assert(tmpl->cbtxn->datasz == 67); assert(!memcmp(tmpl->cbtxn->data, "\x01\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xff\xff\xff\xff\x02\x01\x04\xff\xff\xff\xff\x01\x80\x02\0\0\0\0\0\0\x05\x04" "test\0\0\0\0", tmpl->cbtxn->datasz)); assert(!blkmk_init_generation2(tmpl, "\0", 1, &newcb)); assert(!newcb); tmpl->mutations &= ~BMM_GENERATE; newcb = true; assert(!blkmk_init_generation3(tmpl, "\0", 1, &newcb)); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":40000000,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"coinbaseaux\":{\"dummy\":\"aabbccddeeff0011\"}}", simple_time_rcvd)); assert(blkmk_init_generation(tmpl, NULL, 0) == 640); assert(my_memmemr(&tmpl->cbtxn->data[42], tmpl->cbtxn->data[41], "\xaa\xbb\xcc\xdd\xee\xff\0\x11", 8)); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":128,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"coinbaseaux\":{\"dummy\":\"aabbccddeeff0011aabbccddeeff0011aabbccddeeff0011aabbccddeeff0011aabbccddeeff0011aabbccddeeff0011aabbccddeeff0011aabbccddeeff0011aabbccddeeff0011aabbccddeeff0011aabbccddeeff0011aabbccddeeff001199\"}}", simple_time_rcvd)); assert(!blkmk_init_generation(tmpl, NULL, 0)); tmpl->height = 4; assert(blkmk_init_generation(tmpl, NULL, 0) == 640); tmpl->has_cbvalue = false; tmpl->cbvalue = 0; newcb = true; // Unknown cbvalue needs to either fail, or figure it out from an existing cbtxn (which we don't support yet) assert(!blkmk_init_generation3(tmpl, NULL, 0, &newcb)); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":40000000,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":10000000000}", simple_time_rcvd)); newcb = false; assert(blkmk_init_generation3(tmpl, "\x04" "test", 5, &newcb)); assert(newcb); assert(tmpl->cbtxn); assert(tmpl->cbtxn->datasz == 70); assert(!memcmp(tmpl->cbtxn->data, "\x01\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xff\xff\xff\xff\x05\x04\0\x5a\x62\x02\xff\xff\xff\xff\x01\0\xe4\x0b\x54\x02\0\0\0\x05\x04" "test\0\0\0\0", tmpl->cbtxn->datasz)); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":40000000,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000000000\"},\"mutable\":[\"generation\"],\"coinbasevalue\":89064736821248}", simple_time_rcvd)); newcb = false; assert(!blkmk_init_generation3(tmpl, "\x04" "test", 5, &newcb)); assert(!newcb); newcb = true; assert(blkmk_init_generation3(tmpl, "\x04" "test", 5, &newcb)); assert(newcb); assert(tmpl->cbtxn); assert(tmpl->cbtxn->datasz == 70); assert(!memcmp(tmpl->cbtxn->data, "\x01\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xff\xff\xff\xff\x05\x04\0\x5a\x62\x02\xff\xff\xff\xff\x01\0\x10\0\0\x01\x51\0\0\x05\x04" "test\0\0\0\0", tmpl->cbtxn->datasz)); tmpl->sizelimit = 151; assert(blkmk_init_generation3(tmpl, "\x04" "test", 5, &newcb)); assert(!blkmk_init_generation3(tmpl, "\x05" "testx", 6, &newcb)); tmpl->sizelimit = 10000; tmpl->sigoplimit = 1; assert(blkmk_init_generation3(tmpl, "\x05" "testx", 6, &newcb)); assert(blkmk_init_generation3(tmpl, "\x05" "testx\xac", 7, &newcb)); assert(!blkmk_init_generation3(tmpl, "\x05" "testx\xac\xac", 8, &newcb)); assert(blkmk_init_generation3(tmpl, "\x05" "testx\xac\x4c\0", 9, &newcb)); assert(blkmk_init_generation3(tmpl, "\x05" "testx\xac\x4c", 8, &newcb)); assert(blkmk_init_generation3(tmpl, "\x05" "testx\xac\x4d\x01", 9, &newcb)); assert(blkmk_init_generation3(tmpl, "\x05" "testx\xac\x4e\x01", 9, &newcb)); assert(blkmk_init_generation3(tmpl, "\x05" "testx\xac\x4e\0\0\0\0", 12, &newcb)); assert(blkmk_init_generation3(tmpl, "\x4c\x04" "estx\xad", 7, &newcb)); assert(!blkmk_init_generation3(tmpl, "\x4c\x04" "estx\xad\xad", 8, &newcb)); assert(!blkmk_init_generation3(tmpl, "\x4c\x04" "estx\xac\xad", 8, &newcb)); tmpl->sigoplimit = 21; assert(blkmk_init_generation3(tmpl, "\x05" "testx\xac\xac", 8, &newcb)); assert(blkmk_init_generation3(tmpl, "\x05" "testx\xac\xae", 8, &newcb)); assert(!blkmk_init_generation3(tmpl, "\x05" "testx\xac\xae\xac", 9, &newcb)); assert(blkmk_init_generation3(tmpl, "\x4d\x03\0" "stx\xac\xaf", 8, &newcb)); assert(!blkmk_init_generation3(tmpl, "\x4d\x03\0" "stx\xac\xaf\xac", 9, &newcb)); blktmpl_free(tmpl); } static void test_blkmk_append_coinbase_safe() { blktemplate_t *tmpl; bool newcb; static const uint8_t lots_of_zero[100] = {0}; tmpl = blktmpl_create(); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000000000\"}}", simple_time_rcvd)); // Should fail because we lack coinbase/append mutability assert(blkmk_append_coinbase_safe(tmpl, "", 1) <= 0); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000000000\"},\"mutable\":[\"coinbase/append\"]}", simple_time_rcvd)); assert(blkmk_append_coinbase_safe(tmpl, "", 1) >= 1); assert(tmpl->cbtxn); assert(tmpl->cbtxn->datasz == 68); assert(!memcmp(tmpl->cbtxn->data, "\x01\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xff\xff\xff\xff\x08\x01\x04\x04\xde\xad\xbe\xef\0\x33\x33\x33\x33\x01\0\x10\0\0\x01\x51\0\0\0\0\0\0\0", tmpl->cbtxn->datasz)); blktmpl_free(tmpl); tmpl = blktmpl_create(); assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"sigoplimit\":21}", simple_time_rcvd)); assert(blkmk_init_generation(tmpl, NULL, 0) == 640); assert(blkmk_append_coinbase_safe(tmpl, "", 1) >= 1); assert(tmpl->cbtxn); assert(tmpl->cbtxn->datasz == 63); assert(!memcmp(tmpl->cbtxn->data, "\x01\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xff\xff\xff\xff\x03\x01\x04\0\xff\xff\xff\xff\x01\x80\x02\0\0\0\0\0\0\0\0\0\0\0", tmpl->cbtxn->datasz)); // With 99-byte extranonce, we're already beyond the limit assert(blkmk_append_coinbase_safe2(tmpl, "", 1, 99, true) <= 0); // This should just barely break the limit assert(blkmk_append_coinbase_safe2(tmpl, "", 1, 100 - tmpl->cbtxn->data[41], true) == 0); // This should be okay assert(blkmk_append_coinbase_safe2(tmpl, "", 1, 100 - tmpl->cbtxn->data[41] - 1, true) == 1); // Up to 21 sigops is okay assert(blkmk_append_coinbase_safe2(tmpl, "\xae", 1, 3, true) >= 1); assert(blkmk_append_coinbase_safe2(tmpl, "\xac", 1, 3, true) >= 1); // But 22 should hit the limit assert(blkmk_append_coinbase_safe2(tmpl, "\xac", 1, 3, true) < 0); // Non-sigop stuff is fine to continue assert(blkmk_append_coinbase_safe2(tmpl, "", 1, 3, true) >= 1); const uint8_t padsz = 100 - tmpl->cbtxn->data[41] - 3; assert(blkmk_append_coinbase_safe2(tmpl, lots_of_zero, padsz, 3, true) == padsz); // One too many assert(blkmk_append_coinbase_safe2(tmpl, "", 1, 3, true) == 0); // Becomes okay if we reduce extranonce size assert(blkmk_append_coinbase_safe2(tmpl, "", 1, 2, true) == 1); assert(blkmk_append_coinbase_safe2(tmpl, lots_of_zero, 2, 0, true) == 2); // Totally full now assert(blkmk_append_coinbase_safe2(tmpl, "", 1, 0, true) == 0); newcb = true; assert(blkmk_init_generation3(tmpl, NULL, 0, &newcb)); tmpl->sizelimit = tmpl->cbtxn->datasz + 81 + 5; assert(blkmk_append_coinbase_safe2(tmpl, "\x04" "test", 5, 0, true) == 5); assert(blkmk_init_generation3(tmpl, NULL, 0, &newcb)); assert(blkmk_append_coinbase_safe2(tmpl, "\x05" "testx", 6, 0, true) == 5); blktmpl_free(tmpl); tmpl = blktmpl_create(); // Gen tx is cut off immediately after the coinbase. // We don't *really* care that this works since it's not Bitcoin, but we need to make sure it doesn't corrupt memory or crash assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef\"},\"mutable\":[\"coinbase/append\"]}", simple_time_rcvd)); assert(blkmk_append_coinbase_safe(tmpl, "\x58", 1) >= 1); assert(tmpl->cbtxn); assert(tmpl->cbtxn->datasz == 50); assert(!memcmp(tmpl->cbtxn->data, "\x01\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xff\xff\xff\xff\x08\x01\x04\x04\xde\xad\xbe\xef\x58", tmpl->cbtxn->datasz)); blktmpl_free(tmpl); tmpl = blktmpl_create(); // Gen tx is cut off INSIDE the coinbase. // Again, we need to make sure it doesn't corrupt memory or crash assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbe\"},\"mutable\":[\"coinbase/append\"]}", simple_time_rcvd)); assert(blkmk_append_coinbase_safe(tmpl, "\x58", 1) <= 0); assert(tmpl->cbtxn); assert(tmpl->cbtxn->datasz == 48); assert(!memcmp(tmpl->cbtxn->data, "\x01\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xff\xff\xff\xff\x07\x01\x04\x04\xde\xad\xbe", tmpl->cbtxn->datasz)); blktmpl_free(tmpl); tmpl = blktmpl_create(); // Gen tx is cut off BEFORE the coinbase assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff\"},\"mutable\":[\"coinbase/append\"]}", simple_time_rcvd)); assert(blkmk_append_coinbase_safe(tmpl, "\x58", 1) <= 0); assert(tmpl->cbtxn); assert(tmpl->cbtxn->datasz == 41); assert(!memcmp(tmpl->cbtxn->data, "\x01\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xff\xff\xff\xff", tmpl->cbtxn->datasz)); blktmpl_free(tmpl); } int main() { blkmk_sha256_impl = my_sha256; puts("capabilityname"); capabilityname_test(); puts("blktxn"); blktxn_test('\0'); blktxn_test('\xa5'); blktxn_test('\xff'); puts("blktmpl"); blktmpl_test(); puts("blktmpl_request_jansson"); blktmpl_request_jansson_test_old(); blktmpl_request_jansson_test_custom_rulelist(); blktmpl_request_jansson_test_custom_caps(); blktmpl_request_jansson_test_longpoll(); puts("blktmpl_jansson"); blktmpl_jansson_simple(); blktmpl_jansson_bip22_required(); blktmpl_jansson_bip22_longpoll(); blktmpl_jansson_bip23_bpe(); blktmpl_jansson_bip23_mutations(); blktmpl_jansson_bip23_abbrev(); blktmpl_jansson_bip9(); test_blktmpl_jansson_floaty(); blktmpl_jansson_propose(); blktmpl_jansson_submit(); blktmpl_jansson_submitm(); puts("blkmk_varint_encode"); test_blkmk_varint_encode(); puts("blkmk_supports_rule"); test_blkmk_supports_rule(); puts("blkmk_address_to_script"); test_blkmk_address_to_script(); puts("blkmk_*_left"); test_blkmk_x_left(); puts("blkmk_get_data"); test_blkmk_get_data(); puts("blkmk_get_mdata"); test_blkmk_get_mdata(); puts("blkmk_init_generation"); test_blkmk_init_generation(); puts("blkmk_append_coinbase_safe"); test_blkmk_append_coinbase_safe(); }