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 diff --git a/blkmaker.c b/blkmaker.c index 417fb1f..8b34436 100644 --- a/blkmaker.c +++ b/blkmaker.c @@ -401,7 +401,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) { @@ -491,6 +491,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; *out_dataid = tmpl->next_dataid++; @@ -508,6 +519,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; @@ -515,6 +527,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; @@ -561,9 +577,8 @@ 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; } static char *blkmk_assemble_submission2_internal(blktemplate_t * const tmpl, const unsigned char * const data, const void * const extranonce, const size_t extranoncesz, blknonce_t nonce, const bool foreign) diff --git a/blkmaker_jansson.c b/blkmaker_jansson.c index 3df5d05..fee4321 100644 --- a/blkmaker_jansson.c +++ b/blkmaker_jansson.c @@ -135,6 +135,17 @@ json_t *blktmpl_request_jansson(const uint32_t caps, const char * const lpid) { 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); \ @@ -147,6 +158,17 @@ json_t *blktmpl_request_jansson(const uint32_t caps, const char * const lpid) { #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)))) \ @@ -281,7 +303,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); @@ -293,11 +315,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); @@ -329,6 +351,8 @@ const char *blktmpl_add_jansson(blktemplate_t *tmpl, const json_t *json, time_t tmpl->cbtxn = calloc(1, sizeof(*tmpl->cbtxn)); if ((s = parse_txn(tmpl->cbtxn, v, 0))) return s; + } else if (!tmpl->cbvalue) { + return "Missing either coinbasetxn or coinbasevalue"; } if ((v = json_object_get(json, "coinbaseaux")) && json_is_object(v)) @@ -426,7 +450,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 @@ -477,6 +505,7 @@ json_t *blktmpl_propose_jansson(blktemplate_t * const tmpl, const uint32_t caps, goto err; if (!(ja = json_string(blkhex))) goto err; + free(blkhex); if (json_object_set_new(jparams, "data", ja)) goto err; diff --git a/blktemplate.c b/blktemplate.c index efeec0b..cefa928 100644 --- a/blktemplate.c +++ b/blktemplate.c @@ -26,7 +26,7 @@ static const char *capnames[] = { "coinbase/append", "coinbase", - "generate", + "generation", "time/increment", "time/decrement", "transactions/add", @@ -53,6 +53,10 @@ gbt_capabilities_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; + 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 40c4275..ee90eca 100644 --- a/blktemplate.h +++ b/blktemplate.h @@ -25,6 +25,7 @@ typedef int16_t blktime_diff_t; typedef uint32_t blknonce_t; #define libblkmaker_blkheader_size (80) +#define libblkmaker_coinbase_size_minimum (4) #define libblkmaker_coinbase_size_limit (100) struct blktxn_t { @@ -88,6 +89,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 *);