Merge branch 'segwit' into tmp2
This commit is contained in:
commit
c6f774a02d
2
AUTHORS
2
AUTHORS
@ -1,2 +1,4 @@
|
||||
Luke Dashjr <luke_libblkmaker@dashjr.org>
|
||||
Andy Alness <andy.alness@gmail.com>
|
||||
Huang Le <4tarhl@gmail.com>
|
||||
Cory Fields <cory-nospam-@coryfields.com>
|
||||
|
||||
227
blkmaker.c
227
blkmaker.c
@ -26,6 +26,7 @@
|
||||
|
||||
const char *blkmk_supported_rules[] = {
|
||||
"csv",
|
||||
"segwit",
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -61,6 +62,32 @@ bool _blkmk_dblsha256(void *hash, const void *data, size_t datasz) {
|
||||
|
||||
#define dblsha256 _blkmk_dblsha256
|
||||
|
||||
static
|
||||
size_t varintDecode(const uint8_t *p, size_t size, uint64_t *n)
|
||||
{
|
||||
if (size > 8 && p[0] == 0xff)
|
||||
{
|
||||
*n = upk_u64le(p, 1);
|
||||
return 9;
|
||||
}
|
||||
if (size > 4 && p[0] == 0xfe)
|
||||
{
|
||||
*n = upk_u32le(p, 1);
|
||||
return 5;
|
||||
}
|
||||
if (size > 2 && p[0] == 0xfd)
|
||||
{
|
||||
*n = upk_u16le(p, 1);
|
||||
return 3;
|
||||
}
|
||||
if (size > 0 && p[0] <= 0xfc)
|
||||
{
|
||||
*n = p[0];
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define max_varint_size (9)
|
||||
|
||||
static
|
||||
@ -98,7 +125,7 @@ static uint8_t blkmk_varint_encode_size(const uint64_t n) {
|
||||
}
|
||||
|
||||
static
|
||||
int16_t blkmk_count_sigops(const uint8_t * const script, const size_t scriptsz) {
|
||||
int16_t blkmk_count_sigops(const uint8_t * const script, const size_t scriptsz, const bool bip141) {
|
||||
int16_t sigops = 0;
|
||||
for (size_t i = 0; i < scriptsz; ++i) {
|
||||
if (script[i] <= 0x4c /* OP_PUSHDATA1 */) {
|
||||
@ -125,9 +152,23 @@ int16_t blkmk_count_sigops(const uint8_t * const script, const size_t scriptsz)
|
||||
sigops += 20;
|
||||
}
|
||||
}
|
||||
if (bip141) {
|
||||
sigops *= 4;
|
||||
}
|
||||
return sigops;
|
||||
}
|
||||
|
||||
static int64_t blkmk_calc_gentx_weight(const void * const data, const size_t datasz) {
|
||||
return (datasz * 4) + 2 /* marker & flag */ + 1 /* witness stack count */ + 1 /* stack item size */ + 32 /* stack item: nonce */;
|
||||
}
|
||||
|
||||
static int64_t blktxn_set_gentx_weight(struct blktxn_t * const gentx) {
|
||||
if (gentx->weight < 0) {
|
||||
gentx->weight = blkmk_calc_gentx_weight(gentx->data, gentx->datasz);
|
||||
}
|
||||
return gentx->weight;
|
||||
}
|
||||
|
||||
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)))
|
||||
{
|
||||
@ -206,8 +247,10 @@ uint64_t blkmk_init_generation3(blktemplate_t * const tmpl, const void * const s
|
||||
off += 4;
|
||||
|
||||
const unsigned long pretx_size = libblkmaker_blkheader_size + blkmk_varint_encode_size(1 + tmpl->txncount);
|
||||
const int16_t sigops_counted = blkmk_count_sigops(script, scriptsz);
|
||||
const int16_t sigops_counted = blkmk_count_sigops(script, scriptsz, tmpl->_bip141_sigops);
|
||||
const int64_t gentx_weight = blkmk_calc_gentx_weight(data, off);
|
||||
if (pretx_size + tmpl->txns_datasz + off > tmpl->sizelimit
|
||||
|| (tmpl->txns_weight >= 0 && tmpl->txns_weight + gentx_weight > tmpl->weightlimit)
|
||||
|| (tmpl->txns_sigops >= 0 && tmpl->txns_sigops + sigops_counted > tmpl->sigoplimit)) {
|
||||
free(data);
|
||||
return 0;
|
||||
@ -224,6 +267,7 @@ uint64_t blkmk_init_generation3(blktemplate_t * const tmpl, const void * const s
|
||||
txn->data = data;
|
||||
txn->datasz = off;
|
||||
txn->sigops_ = sigops_counted;
|
||||
txn->weight = gentx_weight;
|
||||
|
||||
if (tmpl->cbtxn)
|
||||
{
|
||||
@ -301,7 +345,9 @@ bool blkmk_build_merkle_branches(blktemplate_t * const tmpl)
|
||||
|
||||
for (i = 0; i < tmpl->txncount; ++i)
|
||||
{
|
||||
memcpy(&hashes[i + 1], tmpl->txns[i].hash_, sizeof(*hashes));
|
||||
struct blktxn_t * const txn = &tmpl->txns[i];
|
||||
txnhash_t * const txid = txn->txid ? txn->txid : txn->hash_;
|
||||
memcpy(&hashes[i + 1], txid, sizeof(*hashes));
|
||||
}
|
||||
|
||||
for (i = 0; i < branchcount; ++i)
|
||||
@ -355,6 +401,76 @@ bool build_merkle_root(unsigned char *mrklroot_out, blktemplate_t *tmpl, unsigne
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
bool _blkmk_calculate_witness_mrklroot(blktemplate_t * const tmpl, libblkmaker_hash_t * const out, bool * const witness_needed) {
|
||||
if (!blkmk_hash_transactions(tmpl))
|
||||
return false;
|
||||
|
||||
// Step 1: Populate hashes with the witness hashes for all transactions
|
||||
size_t hashcount = tmpl->txncount + 1;
|
||||
libblkmaker_hash_t * const hashes = malloc((hashcount + 1) * sizeof(*hashes)); // +1 for when the last needs duplicating
|
||||
if (!hashes) {
|
||||
return false;
|
||||
}
|
||||
memset(&hashes[0], 0, sizeof(hashes[0])); // Gen tx gets a null entry
|
||||
*witness_needed = false;
|
||||
for (unsigned long i = 0; i < tmpl->txncount; ++i) {
|
||||
struct blktxn_t * const txn = &tmpl->txns[i];
|
||||
if (txn->txid && memcmp(txn->hash_, txn->txid, sizeof(*txn->txid))) {
|
||||
*witness_needed = true;
|
||||
}
|
||||
memcpy(&hashes[i + 1], txn->hash_, sizeof(*hashes));
|
||||
}
|
||||
if (!*witness_needed) {
|
||||
free(hashes);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Step 2: Reduce it to a merkle root
|
||||
for ( ; hashcount > 1 ; hashcount /= 2) {
|
||||
if (hashcount % 2 == 1) {
|
||||
// Odd number, duplicate the last
|
||||
memcpy(&hashes[hashcount], &hashes[hashcount - 1], sizeof(*hashes));
|
||||
++hashcount;
|
||||
}
|
||||
for (size_t i = 0; i < hashcount; i += 2) {
|
||||
// We overlap input and output here, on the first pair
|
||||
if (!dblsha256(&hashes[i / 2], &hashes[i], sizeof(*hashes) * 2)) {
|
||||
free(hashes);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(out, hashes, sizeof(*out));
|
||||
free(hashes);
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
bool _blkmk_witness_mrklroot(blktemplate_t * const tmpl) {
|
||||
if (tmpl->_calculated_witness) {
|
||||
// Already calculated
|
||||
return true;
|
||||
}
|
||||
tmpl->_witnessmrklroot = malloc(sizeof(libblkmaker_hash_t));
|
||||
if (!tmpl->_witnessmrklroot) {
|
||||
return false;
|
||||
}
|
||||
bool witness_needed;
|
||||
if (!_blkmk_calculate_witness_mrklroot(tmpl, tmpl->_witnessmrklroot, &witness_needed)) {
|
||||
free(tmpl->_witnessmrklroot);
|
||||
tmpl->_witnessmrklroot = NULL;
|
||||
return false;
|
||||
}
|
||||
if (!witness_needed) {
|
||||
free(tmpl->_witnessmrklroot);
|
||||
tmpl->_witnessmrklroot = NULL;
|
||||
}
|
||||
tmpl->_calculated_witness = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static const int cbScriptSigLen = 4 + 1 + 36;
|
||||
|
||||
static
|
||||
@ -372,7 +488,11 @@ bool _blkmk_append_cb(blktemplate_t * const tmpl, void * const vout, const void
|
||||
return false;
|
||||
}
|
||||
|
||||
const int16_t orig_scriptSig_sigops = blkmk_count_sigops(&in[cbScriptSigLen + 1], in[cbScriptSigLen]);
|
||||
if (tmpl->txns_weight >= 0 && (blktxn_set_gentx_weight(tmpl->cbtxn) + tmpl->txns_weight + (appendsz * 4) > tmpl->weightlimit)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int16_t orig_scriptSig_sigops = blkmk_count_sigops(&in[cbScriptSigLen + 1], in[cbScriptSigLen], tmpl->_bip141_sigops);
|
||||
int cbPostScriptSig = cbScriptSigLen + 1 + in[cbScriptSigLen];
|
||||
if (appended_at_offset)
|
||||
*appended_at_offset = cbPostScriptSig;
|
||||
@ -391,7 +511,7 @@ bool _blkmk_append_cb(blktemplate_t * const tmpl, void * const vout, const void
|
||||
out[cbScriptSigLen] += appendsz;
|
||||
memcpy(outExtranonce, append, appendsz);
|
||||
|
||||
const int16_t sigops_counted = tmpl->cbtxn->sigops_ + blkmk_count_sigops(&out[cbScriptSigLen + 1], out[cbScriptSigLen]) - orig_scriptSig_sigops;
|
||||
const int16_t sigops_counted = tmpl->cbtxn->sigops_ + blkmk_count_sigops(&out[cbScriptSigLen + 1], out[cbScriptSigLen], tmpl->_bip141_sigops) - orig_scriptSig_sigops;
|
||||
if (tmpl->txns_sigops >= 0 && tmpl->txns_sigops + sigops_counted > tmpl->sigoplimit) {
|
||||
// Overflowed :(
|
||||
if (out == in) {
|
||||
@ -438,6 +558,16 @@ ssize_t blkmk_append_coinbase_safe2(blktemplate_t * const tmpl, const void * con
|
||||
availsz = availsz2;
|
||||
}
|
||||
}
|
||||
if (tmpl->txns_weight >= 0) {
|
||||
const size_t current_blockweight = blktxn_set_gentx_weight(tmpl->cbtxn) + tmpl->txns_weight;
|
||||
if (current_blockweight > tmpl->weightlimit) {
|
||||
return false;
|
||||
}
|
||||
const size_t availsz2 = (tmpl->weightlimit - current_blockweight) / 4;
|
||||
if (availsz2 < availsz) {
|
||||
availsz = availsz2;
|
||||
}
|
||||
}
|
||||
if (appendsz > availsz)
|
||||
return availsz;
|
||||
|
||||
@ -449,6 +579,7 @@ ssize_t blkmk_append_coinbase_safe2(blktemplate_t * const tmpl, const void * con
|
||||
if (!_blkmk_append_cb(tmpl, newp, append, appendsz, NULL, &tmpl->cbtxn->sigops_))
|
||||
return -3;
|
||||
tmpl->cbtxn->datasz += appendsz;
|
||||
tmpl->cbtxn->weight += appendsz * 4;
|
||||
|
||||
return availsz;
|
||||
}
|
||||
@ -476,6 +607,70 @@ bool _blkmk_extranonce(blktemplate_t *tmpl, void *vout, unsigned int workid, siz
|
||||
return true;
|
||||
}
|
||||
|
||||
static const unsigned char witness_magic[] = { 0x6a /* OP_RETURN */, 0x24, 0xaa, 0x21, 0xa9, 0xed };
|
||||
#define commitment_spk_size (sizeof(witness_magic) + sizeof(libblkmaker_hash_t) /* witness mrklroot */)
|
||||
#define commitment_txout_size (8 /* value */ + 1 /* scriptPubKey length */ + commitment_spk_size)
|
||||
static const size_t max_witness_commitment_insert = max_varint_size + commitment_txout_size - 1;
|
||||
static const libblkmaker_hash_t witness_nonce = { 0 };
|
||||
|
||||
static
|
||||
bool _blkmk_insert_witness_commitment(blktemplate_t * const tmpl, unsigned char * const gentxdata, size_t * const gentxsize) {
|
||||
if (!_blkmk_witness_mrklroot(tmpl)) {
|
||||
return false;
|
||||
}
|
||||
if (!tmpl->_witnessmrklroot) {
|
||||
// No commitment needed
|
||||
return true;
|
||||
}
|
||||
|
||||
libblkmaker_hash_t merkle_with_nonce[2];
|
||||
libblkmaker_hash_t commitment;
|
||||
memcpy(&merkle_with_nonce[0], tmpl->_witnessmrklroot, sizeof(*tmpl->_witnessmrklroot));
|
||||
memcpy(&merkle_with_nonce[1], &witness_nonce, sizeof(witness_nonce));
|
||||
if(!dblsha256(&commitment, &merkle_with_nonce[0], sizeof(merkle_with_nonce)))
|
||||
return false;
|
||||
|
||||
if (cbScriptSigLen >= *gentxsize) {
|
||||
return false;
|
||||
}
|
||||
const uint8_t coinbasesz = gentxdata[cbScriptSigLen];
|
||||
const size_t offset_of_txout_count = cbScriptSigLen + coinbasesz + sizeof(coinbasesz) + 4 /* nSequence */;
|
||||
if (offset_of_txout_count >= *gentxsize) {
|
||||
return false;
|
||||
}
|
||||
uint64_t txout_count;
|
||||
const size_t in_txout_count_size = varintDecode(&gentxdata[offset_of_txout_count], *gentxsize - offset_of_txout_count, &txout_count);
|
||||
if (!in_txout_count_size) {
|
||||
return false;
|
||||
}
|
||||
++txout_count;
|
||||
unsigned char insertbuf[max_varint_size + commitment_txout_size];
|
||||
const size_t out_txout_count_size = varintEncode(insertbuf, txout_count);
|
||||
unsigned char * const commitment_txout = &insertbuf[out_txout_count_size];
|
||||
memset(commitment_txout, 0, 8); // value
|
||||
commitment_txout[8] = commitment_spk_size;
|
||||
memcpy(&commitment_txout[9], witness_magic, sizeof(witness_magic));
|
||||
memcpy(&commitment_txout[9 + sizeof(witness_magic)], &commitment, sizeof(commitment));
|
||||
|
||||
const size_t offset_of_txout_data = (offset_of_txout_count + in_txout_count_size);
|
||||
const size_t new_offset_of_preexisting_txout_data = (offset_of_txout_count + out_txout_count_size);
|
||||
const size_t length_of_txtail = 4;
|
||||
const size_t length_of_preexisting_txout_data = (*gentxsize - length_of_txtail) - offset_of_txout_data;
|
||||
const size_t offset_of_txtail_i = *gentxsize - length_of_txtail; // just the lock time
|
||||
const size_t offset_of_txtail_o = offset_of_txtail_i + (out_txout_count_size - in_txout_count_size) + commitment_txout_size;
|
||||
memmove(&gentxdata[offset_of_txtail_o], &gentxdata[offset_of_txtail_i], length_of_txtail);
|
||||
if (offset_of_txout_data != new_offset_of_preexisting_txout_data) {
|
||||
memmove(&gentxdata[new_offset_of_preexisting_txout_data], &gentxdata[offset_of_txout_data], length_of_preexisting_txout_data);
|
||||
}
|
||||
memcpy(&gentxdata[offset_of_txout_count], insertbuf, out_txout_count_size);
|
||||
const size_t offset_of_commitment_txout_o = new_offset_of_preexisting_txout_data + length_of_preexisting_txout_data;
|
||||
memcpy(&gentxdata[offset_of_commitment_txout_o], commitment_txout, commitment_txout_size);
|
||||
|
||||
*gentxsize = offset_of_txtail_o + length_of_txtail;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
void blkmk_set_times(blktemplate_t *tmpl, void * const out_hdrbuf, const time_t usetime, int16_t * const out_expire, const bool can_roll_ntime)
|
||||
{
|
||||
@ -502,10 +697,13 @@ bool blkmk_sample_data_(blktemplate_t * const tmpl, uint8_t * const cbuf, const
|
||||
my_htole32(&cbuf[0], tmpl->version);
|
||||
memcpy(&cbuf[4], &tmpl->prevblk, 32);
|
||||
|
||||
unsigned char cbtxndata[tmpl->cbtxn->datasz + sizeof(dataid)];
|
||||
unsigned char cbtxndata[tmpl->cbtxn->datasz + sizeof(dataid) + max_witness_commitment_insert];
|
||||
size_t cbtxndatasz = 0;
|
||||
if (!_blkmk_extranonce(tmpl, cbtxndata, dataid, &cbtxndatasz))
|
||||
return false;
|
||||
if (!_blkmk_insert_witness_commitment(tmpl, cbtxndata, &cbtxndatasz)) {
|
||||
return false;
|
||||
}
|
||||
if (!build_merkle_root(&cbuf[36], tmpl, cbtxndata, cbtxndatasz))
|
||||
return false;
|
||||
|
||||
@ -569,7 +767,7 @@ bool blkmk_get_mdata(blktemplate_t * const tmpl, void * const buf, const size_t
|
||||
memcpy(&cbuf[4], &tmpl->prevblk, 32);
|
||||
|
||||
*out_cbtxnsz = tmpl->cbtxn->datasz + extranoncesz;
|
||||
*out_cbtxn = malloc(*out_cbtxnsz);
|
||||
*out_cbtxn = malloc(*out_cbtxnsz + max_witness_commitment_insert);
|
||||
if (!*out_cbtxn)
|
||||
return false;
|
||||
unsigned char dummy[extranoncesz];
|
||||
@ -579,6 +777,10 @@ bool blkmk_get_mdata(blktemplate_t * const tmpl, void * const buf, const size_t
|
||||
free(*out_cbtxn);
|
||||
return false;
|
||||
}
|
||||
if (!_blkmk_insert_witness_commitment(tmpl, *out_cbtxn, out_cbtxnsz)) {
|
||||
free(*out_cbtxn);
|
||||
return false;
|
||||
}
|
||||
|
||||
blkmk_set_times(tmpl, &cbuf[68], usetime, out_expire, can_roll_ntime);
|
||||
memcpy(&cbuf[72], &tmpl->diffbits, 4);
|
||||
@ -619,7 +821,7 @@ static char *blkmk_assemble_submission2_internal(blktemplate_t * const tmpl, con
|
||||
size_t blkbuf_sz = libblkmaker_blkheader_size;
|
||||
if (incl_gentxn) {
|
||||
blkbuf_sz += max_varint_size /* tx count */;
|
||||
blkbuf_sz += tmpl->cbtxn->datasz + extranoncesz;
|
||||
blkbuf_sz += tmpl->cbtxn->datasz + extranoncesz + (max_varint_size - 1) /* possible enlargement to txout count when adding commitment output */ + commitment_txout_size;
|
||||
if (incl_alltxn) {
|
||||
blkbuf_sz += tmpl->txns_datasz;
|
||||
}
|
||||
@ -639,6 +841,7 @@ static char *blkmk_assemble_submission2_internal(blktemplate_t * const tmpl, con
|
||||
if (incl_gentxn) {
|
||||
offs += varintEncode(&blk[offs], 1 + tmpl->txncount);
|
||||
|
||||
size_t cbtxnlen = 0;
|
||||
// Essentially _blkmk_extranonce
|
||||
if (extranoncesz) {
|
||||
if (!_blkmk_append_cb(tmpl, &blk[offs], extranonce, extranoncesz, NULL, NULL)) {
|
||||
@ -646,11 +849,15 @@ static char *blkmk_assemble_submission2_internal(blktemplate_t * const tmpl, con
|
||||
return NULL;
|
||||
}
|
||||
|
||||
offs += tmpl->cbtxn->datasz + extranoncesz;
|
||||
cbtxnlen += tmpl->cbtxn->datasz + extranoncesz;
|
||||
} else {
|
||||
memcpy(&blk[offs], tmpl->cbtxn->data, tmpl->cbtxn->datasz);
|
||||
offs += tmpl->cbtxn->datasz;
|
||||
cbtxnlen += tmpl->cbtxn->datasz;
|
||||
}
|
||||
if (!_blkmk_insert_witness_commitment(tmpl, &blk[offs], &cbtxnlen)) {
|
||||
return NULL;
|
||||
}
|
||||
offs += cbtxnlen;
|
||||
|
||||
if (incl_alltxn) {
|
||||
for (unsigned long i = 0; i < tmpl->txncount; ++i)
|
||||
|
||||
@ -213,6 +213,25 @@ const char *parse_txn(struct blktxn_t *txn, json_t *txnj, size_t my_tx_index) {
|
||||
my_flip(*txn->hash_, sizeof(*txn->hash_));
|
||||
}
|
||||
|
||||
if ((vv = json_object_get(txnj, "txid")) && json_is_string(vv)) {
|
||||
hexdata = json_string_value(vv);
|
||||
txn->txid = malloc(sizeof(*txn->txid));
|
||||
if (!my_hex2bin(*txn->txid, hexdata, sizeof(*txn->txid))) {
|
||||
return "Error decoding txid field";
|
||||
} else {
|
||||
my_flip(*txn->txid, sizeof(*txn->txid));
|
||||
}
|
||||
}
|
||||
|
||||
txn->weight = -1;
|
||||
if ((vv = json_object_get(txnj, "weight")) && json_is_number(vv)) {
|
||||
const double f = json_number_value(txnj);
|
||||
const int32_t i32 = f;
|
||||
if (f == i32) {
|
||||
txn->weight = i32;
|
||||
}
|
||||
}
|
||||
|
||||
if ((vv = json_object_get(txnj, "depends")) && json_is_array(vv)) {
|
||||
size_t depcount = json_array_size(vv);
|
||||
if (depcount <= LONG_MAX) {
|
||||
@ -309,82 +328,9 @@ const char *blktmpl_add_jansson(blktemplate_t *tmpl, const json_t *json, time_t
|
||||
my_flip(tmpl->prevblk, 32);
|
||||
GETNUM_O(sigoplimit, unsigned short);
|
||||
GETNUM_O(sizelimit, unsigned long);
|
||||
GETNUM_O(weightlimit, int64_t);
|
||||
GETNUM(version, uint32_t);
|
||||
|
||||
GETNUM_O2(cbvalue, coinbasevalue, uint64_t);
|
||||
|
||||
GETSTR(workid, workid);
|
||||
|
||||
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);
|
||||
GETBOOL(submitold, submitold, true);
|
||||
|
||||
v = json_object_get(json, "transactions");
|
||||
size_t txns = tmpl->txncount = json_array_size(v);
|
||||
tmpl->txns = calloc(txns, sizeof(*tmpl->txns));
|
||||
tmpl->txns_datasz = 0;
|
||||
tmpl->txns_sigops = 0;
|
||||
for (size_t i = 0; i < txns; ++i)
|
||||
{
|
||||
struct blktxn_t * const txn = &tmpl->txns[i];
|
||||
if ((s = parse_txn(txn, json_array_get(v, i), i + 1))) {
|
||||
return s;
|
||||
}
|
||||
tmpl->txns_datasz += txn->datasz;
|
||||
if (tmpl->txns_sigops == -1) {
|
||||
; // Impossible to tally the unknown
|
||||
} else if (txn->sigops_ == -1) {
|
||||
tmpl->txns_sigops = -1;
|
||||
} else {
|
||||
tmpl->txns_sigops += txn->sigops_;
|
||||
}
|
||||
}
|
||||
|
||||
if ((v = json_object_get(json, "coinbasetxn")) && json_is_object(v))
|
||||
{
|
||||
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))
|
||||
{
|
||||
tmpl->aux_count = json_object_size(v);
|
||||
tmpl->auxs = calloc(tmpl->aux_count, sizeof(*tmpl->auxs));
|
||||
unsigned i = 0;
|
||||
for (void *iter = json_object_iter(v); iter; (iter = json_object_iter_next(v, iter)), ++i)
|
||||
{
|
||||
v2 = json_object_iter_value(iter);
|
||||
s = json_string_value(v2);
|
||||
if (!s)
|
||||
continue;
|
||||
size_t sz = strlen(s) / 2;
|
||||
tmpl->auxs[i] = (struct blkaux_t){
|
||||
.auxname = strdup(json_object_iter_key(iter)),
|
||||
.data = malloc(sz),
|
||||
.datasz = sz,
|
||||
};
|
||||
if (!my_hex2bin(tmpl->auxs[i].data, s, sz)) {
|
||||
return "Error decoding 'coinbaseaux' data";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((v = json_object_get(json, "target")) && json_is_string(v))
|
||||
{
|
||||
tmpl->target = malloc(sizeof(*tmpl->target));
|
||||
if (!my_hex2bin(tmpl->target, json_string_value(v), sizeof(*tmpl->target)))
|
||||
return "Error decoding 'target'";
|
||||
}
|
||||
|
||||
if ((v = json_object_get(json, "mutable")) && json_is_array(v))
|
||||
{
|
||||
for (size_t i = json_array_size(v); i--; )
|
||||
@ -420,6 +366,9 @@ const char *blktmpl_add_jansson(blktemplate_t *tmpl, const json_t *json, time_t
|
||||
if (!tmpl->rules[i]) {
|
||||
return "Memory allocation error parsing rules";
|
||||
}
|
||||
if (!strcmp(s, "segwit")) {
|
||||
tmpl->_bip141_sigops = true;
|
||||
}
|
||||
}
|
||||
|
||||
v = json_object_get(json, "vbavailable");
|
||||
@ -467,6 +416,88 @@ const char *blktmpl_add_jansson(blktemplate_t *tmpl, const json_t *json, time_t
|
||||
return "Unrecognized block version, and not allowed to reduce or force it";
|
||||
}
|
||||
|
||||
GETNUM_O2(cbvalue, coinbasevalue, uint64_t);
|
||||
|
||||
GETSTR(workid, workid);
|
||||
|
||||
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);
|
||||
GETBOOL(submitold, submitold, true);
|
||||
|
||||
v = json_object_get(json, "transactions");
|
||||
size_t txns = tmpl->txncount = json_array_size(v);
|
||||
tmpl->txns = calloc(txns, sizeof(*tmpl->txns));
|
||||
tmpl->txns_datasz = 0;
|
||||
tmpl->txns_sigops = 0;
|
||||
tmpl->txns_weight = 0;
|
||||
for (size_t i = 0; i < txns; ++i)
|
||||
{
|
||||
struct blktxn_t * const txn = &tmpl->txns[i];
|
||||
if ((s = parse_txn(txn, json_array_get(v, i), i + 1))) {
|
||||
return s;
|
||||
}
|
||||
tmpl->txns_datasz += txn->datasz;
|
||||
if (tmpl->txns_sigops == -1) {
|
||||
; // Impossible to tally the unknown
|
||||
} else if (txn->sigops_ == -1) {
|
||||
tmpl->txns_sigops = -1;
|
||||
} else {
|
||||
tmpl->txns_sigops += txn->sigops_;
|
||||
}
|
||||
if (tmpl->txns_weight == -1) {
|
||||
; // Impossible to tally the unknown
|
||||
} else if (txn->weight == -1) {
|
||||
tmpl->txns_weight = -1;
|
||||
} else {
|
||||
tmpl->txns_weight += txn->weight;
|
||||
}
|
||||
}
|
||||
|
||||
if ((v = json_object_get(json, "coinbasetxn")) && json_is_object(v))
|
||||
{
|
||||
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))
|
||||
{
|
||||
tmpl->aux_count = json_object_size(v);
|
||||
tmpl->auxs = calloc(tmpl->aux_count, sizeof(*tmpl->auxs));
|
||||
unsigned i = 0;
|
||||
for (void *iter = json_object_iter(v); iter; (iter = json_object_iter_next(v, iter)), ++i)
|
||||
{
|
||||
v2 = json_object_iter_value(iter);
|
||||
s = json_string_value(v2);
|
||||
if (!s)
|
||||
continue;
|
||||
size_t sz = strlen(s) / 2;
|
||||
tmpl->auxs[i] = (struct blkaux_t){
|
||||
.auxname = strdup(json_object_iter_key(iter)),
|
||||
.data = malloc(sz),
|
||||
.datasz = sz,
|
||||
};
|
||||
if (!my_hex2bin(tmpl->auxs[i].data, s, sz)) {
|
||||
return "Error decoding 'coinbaseaux' data";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((v = json_object_get(json, "target")) && json_is_string(v))
|
||||
{
|
||||
tmpl->target = malloc(sizeof(*tmpl->target));
|
||||
if (!my_hex2bin(tmpl->target, json_string_value(v), sizeof(*tmpl->target)))
|
||||
return "Error decoding 'target'";
|
||||
}
|
||||
|
||||
tmpl->_time_rcvd = time_rcvd;
|
||||
|
||||
return NULL;
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
@ -67,6 +68,7 @@ void blktxn_init(struct blktxn_t * const txn) {
|
||||
txn->datasz = 0;
|
||||
txn->hash = NULL;
|
||||
txn->hash_ = NULL;
|
||||
txn->txid = NULL;
|
||||
|
||||
txn->dependscount = -1;
|
||||
txn->depends = NULL;
|
||||
@ -74,6 +76,7 @@ void blktxn_init(struct blktxn_t * const txn) {
|
||||
txn->fee_ = -1;
|
||||
txn->required = false;
|
||||
txn->sigops_ = -1;
|
||||
txn->weight = -1;
|
||||
}
|
||||
|
||||
blktemplate_t *blktmpl_create() {
|
||||
@ -84,6 +87,7 @@ blktemplate_t *blktmpl_create() {
|
||||
|
||||
tmpl->sigoplimit = USHRT_MAX;
|
||||
tmpl->sizelimit = ULONG_MAX;
|
||||
tmpl->weightlimit = INT64_MAX;
|
||||
|
||||
tmpl->maxtime = 0xffffffff;
|
||||
tmpl->maxtimeoff = 0x7fff;
|
||||
@ -116,6 +120,7 @@ void blktxn_clean(struct blktxn_t * const bt) {
|
||||
free(bt->hash);
|
||||
free(bt->hash_);
|
||||
free(bt->depends);
|
||||
free(bt->txid);
|
||||
}
|
||||
|
||||
static
|
||||
@ -134,6 +139,7 @@ void blktmpl_free(blktemplate_t *tmpl) {
|
||||
free(tmpl->cbtxn);
|
||||
}
|
||||
free(tmpl->_mrklbranch);
|
||||
free(tmpl->_witnessmrklroot);
|
||||
for (unsigned i = 0; i < tmpl->aux_count; ++i)
|
||||
blkaux_clean(&tmpl->auxs[i]);
|
||||
free(tmpl->auxs);
|
||||
|
||||
@ -40,8 +40,10 @@ struct blktxn_t {
|
||||
int64_t fee_;
|
||||
bool required;
|
||||
int16_t sigops_;
|
||||
int32_t weight;
|
||||
|
||||
txnhash_t *hash_;
|
||||
txnhash_t *txid;
|
||||
};
|
||||
|
||||
struct blkaux_t {
|
||||
@ -150,6 +152,12 @@ typedef struct {
|
||||
bool unsupported_rule;
|
||||
struct blktmpl_vbassoc **vbavailable;
|
||||
uint32_t vbrequired;
|
||||
|
||||
bool _bip141_sigops;
|
||||
bool _calculated_witness;
|
||||
libblkmaker_hash_t *_witnessmrklroot;
|
||||
int64_t weightlimit;
|
||||
int64_t txns_weight;
|
||||
} blktemplate_t;
|
||||
|
||||
extern void blktxn_init(struct blktxn_t *);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user