Support for extranonce using BIP 23 coinbase/append mutation

This commit is contained in:
Luke Dashjr
2012-09-11 15:07:32 +00:00
parent 2f25202ed0
commit 26d76947f6
7 changed files with 61 additions and 18 deletions

View File

@@ -24,14 +24,11 @@ bool dblsha256(void *hash, const void *data, size_t datasz) {
}
static
bool build_merkle_root(unsigned char *mrklroot_out, blktemplate_t *tmpl) {
if (!tmpl->cbtxn)
return false;
bool build_merkle_root(unsigned char *mrklroot_out, blktemplate_t *tmpl, unsigned char *cbtxndata, size_t cbtxndatasz) {
size_t hashcount = tmpl->txncount + 1;
unsigned char hashes[(hashcount + 1) * 32];
if (!dblsha256(&hashes[0], tmpl->cbtxn->data, tmpl->cbtxn->datasz))
if (!dblsha256(&hashes[0], cbtxndata, cbtxndatasz))
return false;
for (int i = 0; i < tmpl->txncount; ++i)
if (!dblsha256(&hashes[32 * (i + 1)], tmpl->txns[i].data, tmpl->txns[i].datasz))
@@ -56,7 +53,31 @@ bool build_merkle_root(unsigned char *mrklroot_out, blktemplate_t *tmpl) {
return true;
}
size_t blkmk_get_data(blktemplate_t *tmpl, void *buf, size_t bufsz, time_t usetime, int16_t *out_expire) {
static const int cbScriptSigLen = 4 + 1 + 36;
bool _blkmk_extranonce(void *vout, void *vin, size_t insz, unsigned int workid) {
unsigned char *out = vout;
unsigned char *in = vin;
if (in[cbScriptSigLen] > 100 - sizeof(workid))
return false;
int cbPostScriptSig = cbScriptSigLen + 1 + in[cbScriptSigLen];
memcpy(out, in, cbPostScriptSig+1);
out[cbScriptSigLen] += sizeof(workid);
unsigned char *outPostScriptSig = &out[cbPostScriptSig];
unsigned int *outExtranonce = (void*)outPostScriptSig;
outPostScriptSig += sizeof(workid);
*outExtranonce = workid;
memcpy(outPostScriptSig, &in[cbPostScriptSig], insz - cbPostScriptSig);
return true;
}
size_t blkmk_get_data(blktemplate_t *tmpl, void *buf, size_t bufsz, time_t usetime, int16_t *out_expire, unsigned int *out_dataid) {
if (!(blkmk_time_left(tmpl, usetime) && blkmk_work_left(tmpl)))
return 0;
if (bufsz < 76)
@@ -66,8 +87,21 @@ size_t blkmk_get_data(blktemplate_t *tmpl, void *buf, size_t bufsz, time_t useti
my_htole32(&cbuf[0], tmpl->version);
memcpy(&cbuf[4], &tmpl->prevblk, 32);
if (!build_merkle_root(&cbuf[36], tmpl))
unsigned char cbtxndata[tmpl->cbtxn->datasz + sizeof(*out_dataid)];
size_t cbtxndatasz = tmpl->cbtxn->datasz;
*out_dataid = tmpl->next_dataid++;
if (*out_dataid)
{
if (!_blkmk_extranonce(cbtxndata, tmpl->cbtxn->data, tmpl->cbtxn->datasz, *out_dataid))
return 0;
cbtxndatasz += sizeof(*out_dataid);
}
else
memcpy(cbtxndata, tmpl->cbtxn->data, cbtxndatasz);
if (!build_merkle_root(&cbuf[36], tmpl, cbtxndata, cbtxndatasz))
return 0;
blktime_t timehdr = tmpl->curtime + difftime(usetime, tmpl->_time_rcvd);
if (timehdr > tmpl->maxtime)
timehdr = tmpl->maxtime;
@@ -89,8 +123,10 @@ blktime_diff_t blkmk_time_left(const blktemplate_t *tmpl, time_t nowtime) {
}
unsigned long blkmk_work_left(const blktemplate_t *tmpl) {
// TODO
// TEMPORARY HACK
return (tmpl->version && !tmpl->_mrklroot[0]) ? 1 : 0;
if (!tmpl->version)
return 0;
if (!(tmpl->mutations & (BMM_CBAPPEND | BMM_CBSET)))
return 1;
return UINT_MAX - tmpl->next_dataid;
return BLKMK_UNLIMITED_WORK_COUNT;
}

View File

@@ -10,7 +10,7 @@
extern bool (*blkmk_sha256_impl)(void *hash_out, const void *data, size_t datasz);
extern size_t blkmk_get_data(blktemplate_t *, void *buf, size_t bufsz, time_t usetime, int16_t *out_expire);
extern size_t blkmk_get_data(blktemplate_t *, void *buf, size_t bufsz, time_t usetime, int16_t *out_expire, unsigned int *out_dataid);
extern blktime_diff_t blkmk_time_left(const blktemplate_t *, time_t nowtime);
extern unsigned long blkmk_work_left(const blktemplate_t *);
#define BLKMK_UNLIMITED_WORK_COUNT ULONG_MAX

View File

@@ -267,18 +267,23 @@ void my_bin2hex(char *out, const void *data, size_t datasz) {
}
}
json_t *blkmk_submit_jansson(blktemplate_t *tmpl, const unsigned char *data, blknonce_t nonce) {
json_t *blkmk_submit_jansson(blktemplate_t *tmpl, const unsigned char *data, unsigned int dataid, blknonce_t nonce) {
unsigned char blk[80 + 8 + 1000000];
memcpy(blk, data, 76);
*(uint32_t*)(&blk[76]) = htonl(nonce);
size_t offs = 80;
if (!(tmpl->mutations & BMAb_TRUNCATE))
if (!(tmpl->mutations & BMAb_TRUNCATE && !dataid))
{
offs += varintEncode(&blk[offs], 1 + tmpl->txncount);
memcpy(&blk[offs], tmpl->cbtxn->data, tmpl->cbtxn->datasz);
offs += tmpl->cbtxn->datasz;
if (dataid)
{
*(int*)&blk[offs] = dataid;
offs += sizeof(dataid);
}
if (!(tmpl->mutations & BMAb_COINBASE))
for (int i = 0; i < tmpl->txncount; ++i)

View File

@@ -7,6 +7,6 @@
extern json_t *blktmpl_request_jansson(gbt_capabilities_t extracaps);
extern const char *blktmpl_add_jansson(blktemplate_t *, const json_t *, time_t time_rcvd);
extern json_t *blkmk_submit_jansson(blktemplate_t *, const unsigned char *data, blknonce_t);
extern json_t *blkmk_submit_jansson(blktemplate_t *, const unsigned char *data, unsigned int dataid, blknonce_t);
#endif

View File

@@ -67,7 +67,7 @@ gbt_capabilities_t blktmpl_addcaps(const blktemplate_t *tmpl) {
// For now, it's a simple "filled" vs "not filled"
if (tmpl->version)
return 0;
return GBT_CBTXN | GBT_WORKID | BMM_TIMEINC;
return GBT_CBTXN | GBT_WORKID | BMM_TIMEINC | BMM_CBAPPEND;
}
static

View File

@@ -111,6 +111,7 @@ typedef struct {
// TEMPORARY HACK
libblkmaker_hash_t _mrklroot;
unsigned int next_dataid;
} blktemplate_t;
extern blktemplate_t *blktmpl_create();

View File

@@ -60,10 +60,11 @@ int main(int argc, char**argv) {
{
unsigned char data[80], hash[32];
size_t datasz;
unsigned int dataid;
uint32_t nonce;
datasz = blkmk_get_data(tmpl, data, sizeof(data), time(NULL), NULL);
assert(datasz <= sizeof(data));
datasz = blkmk_get_data(tmpl, data, sizeof(data), time(NULL), NULL, &dataid);
assert(datasz >= 76 && datasz <= sizeof(data));
// mine the right nonce
// this is iterating in native order, even though SHA256 is big endian, because we don't implement noncerange
@@ -84,7 +85,7 @@ int main(int argc, char**argv) {
printf("Found nonce: 0x%8" PRIx32 " \n", nonce);
nonce = ntohl(nonce);
req = blkmk_submit_jansson(tmpl, data, nonce);
req = blkmk_submit_jansson(tmpl, data, dataid, nonce);
assert(req);
// send req to server
send_json(req);