Optimise merkle root creation by reusing a merkle branch

This commit is contained in:
Luke Dashjr
2014-02-27 00:17:17 +00:00
parent 0299bfc068
commit 83daccfeef
4 changed files with 80 additions and 8 deletions

View File

@@ -124,30 +124,87 @@ uint64_t blkmk_init_generation(blktemplate_t *tmpl, void *script, size_t scripts
}
static
bool build_merkle_root(unsigned char *mrklroot_out, blktemplate_t *tmpl, unsigned char *cbtxndata, size_t cbtxndatasz) {
bool blkmk_hash_transactions(blktemplate_t * const tmpl)
{
for (unsigned long i = 0; i < tmpl->txncount; ++i)
{
struct blktxn_t * const txn = &tmpl->txns[i];
if (txn->hash_)
continue;
txn->hash_ = malloc(sizeof(*txn->hash_));
if (!dblsha256(txn->hash_, txn->data, txn->datasz))
{
free(txn->hash_);
return false;
}
}
return true;
}
static
bool blkmk_build_merkle_branches(blktemplate_t * const tmpl)
{
int branchcount, i;
libblkmaker_hash_t *branches;
if (tmpl->_mrklbranch)
return true;
if (!blkmk_hash_transactions(tmpl))
return false;
branchcount = blkmk_flsl(tmpl->txncount);
branches = malloc(branchcount * sizeof(*branches));
size_t hashcount = tmpl->txncount + 1;
unsigned char hashes[(hashcount + 1) * 32];
if (!dblsha256(&hashes[0], cbtxndata, cbtxndatasz))
return false;
for (unsigned long i = 0; i < tmpl->txncount; ++i)
if (!dblsha256(&hashes[32 * (i + 1)], tmpl->txns[i].data, tmpl->txns[i].datasz))
return false;
for (i = 0; i < tmpl->txncount; ++i)
memcpy(&hashes[0x20 * (i + 1)], tmpl->txns[i].hash_, 0x20);
while (hashcount > 1)
for (i = 0; i < branchcount; ++i)
{
memcpy(&branches[i], &hashes[0x20], 0x20);
if (hashcount % 2)
{
memcpy(&hashes[32 * hashcount], &hashes[32 * (hashcount - 1)], 32);
++hashcount;
}
for (size_t i = 0; i < hashcount; i += 2)
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))
{
free(branches);
return false;
}
hashcount /= 2;
}
tmpl->_mrklbranch = branches;
tmpl->_mrklbranchcount = branchcount;
return true;
}
static
bool build_merkle_root(unsigned char *mrklroot_out, blktemplate_t *tmpl, unsigned char *cbtxndata, size_t cbtxndatasz) {
int i;
libblkmaker_hash_t hashes[0x40];
if (!blkmk_build_merkle_branches(tmpl))
return false;
if (!dblsha256(&hashes[0], cbtxndata, cbtxndatasz))
return false;
for (i = 0; i < tmpl->_mrklbranchcount; ++i)
{
memcpy(&hashes[1], tmpl->_mrklbranch[i], 0x20);
// This is where we overlap input and output, on the first pair
if (!dblsha256(&hashes[0], &hashes[0], 0x40))
return false;
}
memcpy(mrklroot_out, &hashes[0], 32);
return true;

View File

@@ -110,6 +110,7 @@ void blktmpl_free(blktemplate_t *tmpl) {
blktxn_free(tmpl->cbtxn);
free(tmpl->cbtxn);
}
free(tmpl->_mrklbranch);
// TODO: maybe free auxnames[0..n]? auxdata too
free(tmpl->auxnames);
free(tmpl->auxdata);

View File

@@ -120,6 +120,8 @@ typedef struct {
blknonce_t maxnonce;
// TEMPORARY HACK
libblkmaker_hash_t *_mrklbranch;
int _mrklbranchcount;
libblkmaker_hash_t _mrklroot;
unsigned int next_dataid;
} blktemplate_t;

View File

@@ -18,4 +18,16 @@ extern bool _blkmk_hex2bin(void *o, const char *x, size_t len);
extern bool _blkmk_b58tobin(void *bin, size_t binsz, const char *b58, size_t b58sz);
extern int _blkmk_b58check(void *bin, size_t binsz, const char *b58);
// inline
// NOTE: This must return 0 for 0
static inline
int blkmk_flsl(unsigned long n)
{
int i;
for (i = 0; n; ++i)
n >>= 1;
return i;
}
#endif