From e1a1b1bd0793829a8397947432239e70b82243ae Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 26 Jul 2016 23:56:13 +0000 Subject: [PATCH 01/15] assemble_submission: Avoid magic number constants for sizes --- blkmaker.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/blkmaker.c b/blkmaker.c index cc25e05..417fb1f 100644 --- a/blkmaker.c +++ b/blkmaker.c @@ -585,10 +585,11 @@ static char *blkmk_assemble_submission2_internal(blktemplate_t * const tmpl, con return NULL; } - memcpy(blk, data, 76); + const size_t header_before_nonce_sz = libblkmaker_blkheader_size - sizeof(nonce); + memcpy(blk, data, header_before_nonce_sz); nonce = htonl(nonce); - memcpy(&blk[76], &nonce, 4); - size_t offs = 80; + memcpy(&blk[header_before_nonce_sz], &nonce, sizeof(nonce)); + size_t offs = libblkmaker_blkheader_size; if (incl_gentxn) { offs += varintEncode(&blk[offs], 1 + tmpl->txncount); From 1ff98a11993c0683567d5d47e21a02afaa63983a Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sat, 30 Jul 2016 22:19:35 +0000 Subject: [PATCH 02/15] gitignore autotools compile wrapper --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c2e17c6..6200e5f 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ autom4te.cache config.* ii ar-lib +compile From 723a7e543be5862dc5499f787cc99b3242fe8eb5 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 10 Aug 2016 22:04:41 +0000 Subject: [PATCH 03/15] Bugfix: Correctly parse "generation" and "time" mutations --- blktemplate.c | 6 +++++- blktemplate.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/blktemplate.c b/blktemplate.c index be4bfe6..5899bac 100644 --- a/blktemplate.c +++ b/blktemplate.c @@ -19,7 +19,7 @@ static const char *capnames[] = { "coinbase/append", "coinbase", - "generate", + "generation", "time/increment", "time/decrement", "transactions/add", @@ -46,6 +46,10 @@ gbt_capabilities_t blktmpl_getcapability(const char *n) { for (int i = 0; i < GBT_CAPABILITY_COUNT; ++i) if (capnames[i] && !strcasecmp(n, capnames[i])) return 1 << i; + if (!strcasecmp(n, "time")) { + // multi-capability + return BMM_TIMEINC | BMM_TIMEDEC; + } if (!strcasecmp(n, "transactions")) return BMM_TXNADD; // Odd one as it's overloaded w/"transactions/add" per spec return 0; diff --git a/blktemplate.h b/blktemplate.h index da737a4..209a1a3 100644 --- a/blktemplate.h +++ b/blktemplate.h @@ -65,6 +65,7 @@ typedef enum { extern const char *blktmpl_capabilityname(gbt_capabilities_t); #define BLKTMPL_LONGEST_CAPABILITY_NAME (16) +// ABI FIXME: return uint32_t since "time" can yield a combination gbt_capabilities_t extern gbt_capabilities_t blktmpl_getcapability(const char *); From 339f436170c580e5df9573b7216239564b4efe79 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 10 Aug 2016 23:37:02 +0000 Subject: [PATCH 04/15] Bugfix: Close memory leak in blktmpl_propose_jansson --- blkmaker_jansson.c | 1 + 1 file changed, 1 insertion(+) diff --git a/blkmaker_jansson.c b/blkmaker_jansson.c index 668a47c..7f63c73 100644 --- a/blkmaker_jansson.c +++ b/blkmaker_jansson.c @@ -280,6 +280,7 @@ json_t *blktmpl_propose_jansson(blktemplate_t * const tmpl, const gbt_capabiliti goto err; if (!(ja = json_string(blkhex))) goto err; + free(blkhex); if (json_object_set_new(jparams, "data", ja)) goto err; From ebd42b2461801828f344e564dd420189deb79e47 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 11 Aug 2016 03:49:35 +0000 Subject: [PATCH 05/15] Bugfix: Correct blkmk_work_left for single-work templates that have been used --- blkmaker.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/blkmaker.c b/blkmaker.c index d5d84cf..ee2a8eb 100644 --- a/blkmaker.c +++ b/blkmaker.c @@ -126,7 +126,6 @@ unsigned long blkmk_work_left(const blktemplate_t *tmpl) { if (!tmpl->version) return 0; if (!(tmpl->mutations & (BMM_CBAPPEND | BMM_CBSET))) - return 1; + return (tmpl->next_dataid) ? 0 : 1; return UINT_MAX - tmpl->next_dataid; - return BLKMK_UNLIMITED_WORK_COUNT; } From 4a01674cd089d3c6bfac6092d2e803c80ed15230 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 11 Aug 2016 03:51:07 +0000 Subject: [PATCH 06/15] Bugfix: blkmk_get_mdata must fail if we cannot append the coinbase --- blkmaker.c | 1 + 1 file changed, 1 insertion(+) diff --git a/blkmaker.c b/blkmaker.c index a5035f3..c0c1457 100644 --- a/blkmaker.c +++ b/blkmaker.c @@ -339,6 +339,7 @@ bool blkmk_get_mdata(blktemplate_t * const tmpl, void * const buf, const size_t && tmpl->cbtxn && blkmk_build_merkle_branches(tmpl) && bufsz >= 76 + && (tmpl->mutations & (BMM_CBAPPEND | BMM_CBSET)) )) return false; From 15745d4a5fa42ed50254a0430f0b0a0c960c42e8 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 11 Aug 2016 05:49:43 +0000 Subject: [PATCH 07/15] Bugfix: Ensure coinbase is always at least 4 bytes long --- blkmaker.c | 15 +++++++++++++++ blktemplate.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/blkmaker.c b/blkmaker.c index 13810f7..b367e47 100644 --- a/blkmaker.c +++ b/blkmaker.c @@ -323,6 +323,17 @@ size_t blkmk_get_data(blktemplate_t *tmpl, void *buf, size_t bufsz, time_t useti if (bufsz < 76) return 76; + if (tmpl->cbtxn->datasz > cbScriptSigLen && tmpl->cbtxn->data[cbScriptSigLen] + sizeof(*out_dataid) < libblkmaker_coinbase_size_minimum) { + // Add some padding + const size_t padding_required = libblkmaker_coinbase_size_minimum - (tmpl->cbtxn->data[cbScriptSigLen] + sizeof(*out_dataid)); + uint8_t padding[padding_required]; + static const uint8_t opcode_nop = '\x61'; + memset(padding, opcode_nop, padding_required); + if (padding_required != blkmk_append_coinbase_safe2(tmpl, padding, padding_required, 0, false)) { + return 0; + } + } + unsigned char *cbuf = buf; my_htole32(&cbuf[0], tmpl->version); @@ -359,6 +370,10 @@ bool blkmk_get_mdata(blktemplate_t * const tmpl, void * const buf, const size_t // Avoid overlapping with blkmk_get_data use ++extranoncesz; + if (tmpl->cbtxn->datasz > cbScriptSigLen && tmpl->cbtxn->data[cbScriptSigLen] + extranoncesz < libblkmaker_coinbase_size_minimum) { + extranoncesz = libblkmaker_coinbase_size_minimum - tmpl->cbtxn->data[cbScriptSigLen]; + } + void ** const out_branches = _out_branches; void ** const out_cbtxn = _out_cbtxn; unsigned char *cbuf = buf; diff --git a/blktemplate.h b/blktemplate.h index 8b832c5..eb7f73e 100644 --- a/blktemplate.h +++ b/blktemplate.h @@ -20,6 +20,8 @@ typedef uint32_t blktime_t; typedef int16_t blktime_diff_t; typedef uint32_t blknonce_t; +#define libblkmaker_coinbase_size_minimum (4) + struct blktxn_t { unsigned char *data; size_t datasz; From 2cad5fdadb7409be8e0011b55c014a010862115a Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 11 Aug 2016 06:57:22 +0000 Subject: [PATCH 08/15] Bugfix: Refuse to accept a template with neither coinbasetxn nor coinbasevalue --- blkmaker_jansson.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/blkmaker_jansson.c b/blkmaker_jansson.c index 06c97b3..08e2676 100644 --- a/blkmaker_jansson.c +++ b/blkmaker_jansson.c @@ -197,6 +197,8 @@ const char *blktmpl_add_jansson(blktemplate_t *tmpl, json_t *json, time_t time_r tmpl->cbtxn = calloc(1, sizeof(*tmpl->cbtxn)); if ((s = parse_txn(tmpl->cbtxn, v))) return s; + } else if (!tmpl->cbvalue) { + return "Missing either coinbasetxn or coinbasevalue"; } // TODO: coinbaseaux From 4be60421c81ece44c8cc0cf27a82b024eb359579 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 11 Aug 2016 06:57:42 +0000 Subject: [PATCH 09/15] Bugfix: Refuse to accept an unparsable vbrequired --- blkmaker_jansson.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/blkmaker_jansson.c b/blkmaker_jansson.c index cbce12f..d3507cf 100644 --- a/blkmaker_jansson.c +++ b/blkmaker_jansson.c @@ -305,7 +305,11 @@ const char *blktmpl_add_jansson(blktemplate_t *tmpl, const json_t *json, time_t v = json_object_get(json, "vbrequired"); if (v && json_is_number(v)) { - tmpl->vbrequired = json_number_value(v); + double tmpd = json_number_value(v); + tmpl->vbrequired = tmpd; + if (tmpl->vbrequired != tmpd) { + return "Unparsable vbrequired"; + } } } else From 7b1113110aea93afa6af06154e3478127a2c4356 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 11 Aug 2016 07:02:17 +0000 Subject: [PATCH 10/15] Bugfix: Correct return type for blkmk_append_coinbase_safe2 hitting sizelimit --- blkmaker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blkmaker.c b/blkmaker.c index f0b8974..b529240 100644 --- a/blkmaker.c +++ b/blkmaker.c @@ -307,7 +307,7 @@ ssize_t blkmk_append_coinbase_safe2(blktemplate_t * const tmpl, const void * con { const size_t current_blocksize = tmpl->cbtxn->datasz + tmpl->txns_datasz; if (current_blocksize > tmpl->sizelimit) { - return false; + return -4; } const size_t availsz2 = tmpl->sizelimit - current_blocksize; if (availsz2 < availsz) { From 81f7ae1d1afb858c4fb11e9333007933e9f007c4 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 11 Aug 2016 06:42:16 +0000 Subject: [PATCH 11/15] jansson: When parsing, ignore fractional parts of times --- blkmaker_jansson.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/blkmaker_jansson.c b/blkmaker_jansson.c index d374a14..74bc3e5 100644 --- a/blkmaker_jansson.c +++ b/blkmaker_jansson.c @@ -116,6 +116,17 @@ err: tmpl->key = tmp; \ } while(0) +#define GETNUM_T(key, type) do { \ + GET(key, number); \ + const double tmpd = json_number_value(v); \ + const type tmp = tmpd; \ + /* This checks if it's merely being truncated, and tolerates it */ \ + if (tmpd != tmp && !((tmpd < 0) ? (tmpd < tmp && tmpd + 1 > tmp) : (tmpd > tmp && tmpd - 1 < tmp))) { \ + return "Invalid number value for '" #key "'"; \ + } \ + tmpl->key = tmp; \ +} while(0) + #define GETNUM_O2(key, skey, type) do { \ if ((v = json_object_get(json, #skey)) && json_is_number(v)) { \ const double tmpd = json_number_value(v); \ @@ -128,6 +139,17 @@ err: #define GETNUM_O(key, type) GETNUM_O2(key, key, type) +#define GETNUM_OT(key, type) do { \ + if ((v = json_object_get(json, #key)) && json_is_number(v)) { \ + const double tmpd = json_number_value(v); \ + const type tmp = tmpd; \ + /* This checks if it's merely being truncated, and tolerates it */ \ + if (tmpd == tmp || ((tmpd < 0) ? (tmpd < tmp && tmpd + 1 > tmp) : (tmpd > tmp && tmpd - 1 < tmp))) { \ + tmpl->key = tmp; \ + } \ + } \ +} while(0) + #define GETSTR(key, skey) do { \ if ((v = json_object_get(json, #key)) && json_is_string(v)) \ if (!(tmpl->skey = strdup(json_string_value(v)))) \ @@ -192,7 +214,7 @@ const char *blktmpl_add_jansson(blktemplate_t *tmpl, const json_t *json, time_t GETHEX(bits, diffbits); my_flip(tmpl->diffbits, 4); - GETNUM(curtime, blktime_t); + GETNUM_T(curtime, blktime_t); GETNUM(height, blkheight_t); GETHEX(previousblockhash, prevblk); my_flip(tmpl->prevblk, 32); @@ -204,11 +226,11 @@ const char *blktmpl_add_jansson(blktemplate_t *tmpl, const json_t *json, time_t GETSTR(workid, workid); - GETNUM_O(expires, int16_t); - GETNUM_O(maxtime, blktime_t); - GETNUM_O(maxtimeoff, blktime_diff_t); - GETNUM_O(mintime, blktime_t); - GETNUM_O(mintimeoff, blktime_diff_t); + GETNUM_OT(expires, int16_t); + GETNUM_OT(maxtime, blktime_t); + GETNUM_OT(maxtimeoff, blktime_diff_t); + GETNUM_OT(mintime, blktime_t); + GETNUM_OT(mintimeoff, blktime_diff_t); GETSTR(longpollid, lp.id); GETSTR(longpolluri, lp.uri); From f692fddffad9963da5539e72ed71c392bb442aba Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 11 Aug 2016 07:49:24 +0000 Subject: [PATCH 12/15] ABI break: Return uint32_t from blktmpl_getcapability since "time" yields a combination of gbt_capabilities_t --- blktemplate.c | 4 ++-- blktemplate.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/blktemplate.c b/blktemplate.c index cefa928..d19f575 100644 --- a/blktemplate.c +++ b/blktemplate.c @@ -49,10 +49,10 @@ const char *blktmpl_capabilityname(gbt_capabilities_t caps) { return NULL; } -gbt_capabilities_t blktmpl_getcapability(const char *n) { +uint32_t blktmpl_getcapability(const char *n) { for (unsigned int i = 0; i < GBT_CAPABILITY_COUNT; ++i) if (capnames[i] && !strcasecmp(n, capnames[i])) - return 1 << i; + return ((uint32_t)1) << i; if (!strcasecmp(n, "time")) { // multi-capability return BMM_TIMEINC | BMM_TIMEDEC; diff --git a/blktemplate.h b/blktemplate.h index ee90eca..624ad62 100644 --- a/blktemplate.h +++ b/blktemplate.h @@ -89,8 +89,8 @@ typedef enum { extern const char *blktmpl_capabilityname(gbt_capabilities_t); #define BLKTMPL_LONGEST_CAPABILITY_NAME (16) -// ABI FIXME: return uint32_t since "time" can yield a combination gbt_capabilities_t -extern gbt_capabilities_t blktmpl_getcapability(const char *); +// NOTE: blktmpl_getcapability("time") yields a combination of gbt_capabilities_t +extern uint32_t blktmpl_getcapability(const char *); typedef gbt_capabilities_t blkmutations_t; From 3280aab1745a5140922f888f41bbf2d252f3b0da Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 11 Aug 2016 09:12:35 +0000 Subject: [PATCH 13/15] ABI break: Remove blktemplate_t.{min,max}nonce, since it was never supported and is unlikely to ever be useful --- blktemplate.c | 1 - blktemplate.h | 2 -- 2 files changed, 3 deletions(-) diff --git a/blktemplate.c b/blktemplate.c index d19f575..eb7a679 100644 --- a/blktemplate.c +++ b/blktemplate.c @@ -88,7 +88,6 @@ blktemplate_t *blktmpl_create() { tmpl->maxtime = 0xffffffff; tmpl->maxtimeoff = 0x7fff; tmpl->mintimeoff = -0x7fff; - tmpl->maxnonce = 0xffffffff; tmpl->expires = 0x7fff; return tmpl; diff --git a/blktemplate.h b/blktemplate.h index 624ad62..fb055ae 100644 --- a/blktemplate.h +++ b/blktemplate.h @@ -134,8 +134,6 @@ typedef struct { blktime_diff_t maxtimeoff; blktime_t mintime; blktime_diff_t mintimeoff; - blknonce_t minnonce; - blknonce_t maxnonce; // TEMPORARY HACK libblkmaker_hash_t *_mrklbranch; From 981b1dc4feb0b9d47c6603e79b5f995e1ccd65d5 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 11 Aug 2016 23:35:58 +0000 Subject: [PATCH 14/15] Bugfix: Include block header and transaction count in sizelimit checks --- blkmaker.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/blkmaker.c b/blkmaker.c index b529240..5c5f377 100644 --- a/blkmaker.c +++ b/blkmaker.c @@ -49,6 +49,13 @@ bool _blkmk_dblsha256(void *hash, const void *data, size_t datasz) { #define max_varint_size (9) +static char varintEncode(unsigned char *, uint64_t); + +static uint8_t blkmk_varint_encode_size(const uint64_t n) { + uint8_t dummy[max_varint_size]; + return varintEncode(dummy, n); +} + uint64_t blkmk_init_generation3(blktemplate_t * const tmpl, const void * const script, const size_t scriptsz, bool * const inout_newcb) { if (tmpl->cbtxn && !(*inout_newcb && (tmpl->mutations & BMM_GENERATE))) { @@ -120,7 +127,8 @@ uint64_t blkmk_init_generation3(blktemplate_t * const tmpl, const void * const s memset(&data[off], 0, 4); // lock time off += 4; - if (tmpl->txns_datasz + off > tmpl->sizelimit) { + const unsigned long pretx_size = libblkmaker_blkheader_size + blkmk_varint_encode_size(1 + tmpl->txncount); + if (pretx_size + tmpl->txns_datasz + off > tmpl->sizelimit) { free(data); return 0; } @@ -264,7 +272,8 @@ bool _blkmk_append_cb(blktemplate_t * const tmpl, void * const vout, const void if (in[cbScriptSigLen] > libblkmaker_coinbase_size_limit - appendsz) return false; - if (tmpl->cbtxn->datasz + tmpl->txns_datasz + appendsz > tmpl->sizelimit) { + const unsigned long pretx_size = libblkmaker_blkheader_size + blkmk_varint_encode_size(1 + tmpl->txncount); + if (pretx_size + tmpl->cbtxn->datasz + tmpl->txns_datasz + appendsz > tmpl->sizelimit) { return false; } @@ -305,7 +314,8 @@ ssize_t blkmk_append_coinbase_safe2(blktemplate_t * const tmpl, const void * con } size_t availsz = libblkmaker_coinbase_size_limit - extranoncesz - tmpl->cbtxn->data[cbScriptSigLen]; { - const size_t current_blocksize = tmpl->cbtxn->datasz + tmpl->txns_datasz; + const unsigned long pretx_size = libblkmaker_blkheader_size + blkmk_varint_encode_size(1 + tmpl->txncount); + const size_t current_blocksize = pretx_size + tmpl->cbtxn->datasz + tmpl->txns_datasz; if (current_blocksize > tmpl->sizelimit) { return -4; } From 5a88bc541ae8a262519d18a58852e2baac38ebe5 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Fri, 12 Aug 2016 01:02:08 +0000 Subject: [PATCH 15/15] Allocate heap space for hashes, rather than use the (potentially too small) stack --- blkmaker.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/blkmaker.c b/blkmaker.c index 2a6eaf3..94c6c4b 100644 --- a/blkmaker.c +++ b/blkmaker.c @@ -162,31 +162,43 @@ bool blkmk_build_merkle_branches(blktemplate_t * const tmpl) } branches = malloc(branchcount * sizeof(*branches)); + if (!branches) { + return false; + } size_t hashcount = tmpl->txncount + 1; - unsigned char hashes[(hashcount + 1) * 32]; + libblkmaker_hash_t * const hashes = malloc((hashcount + 1) * sizeof(*hashes)); // +1 for when the last needs duplicating + if (!hashes) { + free(branches); + return false; + } for (i = 0; i < tmpl->txncount; ++i) - memcpy(&hashes[0x20 * (i + 1)], tmpl->txns[i].hash_, 0x20); + { + memcpy(&hashes[i + 1], tmpl->txns[i].hash_, sizeof(*hashes)); + } for (i = 0; i < branchcount; ++i) { - memcpy(&branches[i], &hashes[0x20], 0x20); + memcpy(&branches[i], &hashes[1], sizeof(*hashes)); if (hashcount % 2) { - memcpy(&hashes[32 * hashcount], &hashes[32 * (hashcount - 1)], 32); + memcpy(&hashes[hashcount], &hashes[hashcount - 1], sizeof(*hashes)); ++hashcount; } for (size_t i = 2; i < hashcount; i += 2) // This is where we overlap input and output, on the first pair - if (!dblsha256(&hashes[i / 2 * 32], &hashes[32 * i], 64)) + if (!dblsha256(&hashes[i / 2], &hashes[i], sizeof(*hashes) * 2)) { free(branches); + free(hashes); return false; } hashcount /= 2; } + free(hashes); + tmpl->_mrklbranch = branches; tmpl->_mrklbranchcount = branchcount;