Compare commits

..

No commits in common. "master" and "0.5.x" have entirely different histories.

16 changed files with 142 additions and 2084 deletions

5
.gitignore vendored
View File

@ -31,8 +31,3 @@ config.*
ii
ar-lib
compile
test-driver
test
test-suite.log
test.log
test.trs

View File

@ -1,129 +0,0 @@
os: linux
language: c
compiler: gcc
sudo: false
env:
global:
- PKG_CONFIG_LIBDIR="$HOME/lib/pkgconfig"
- OPTS="--prefix=$HOME"
matrix:
include:
# Normal build
- addons:
apt:
packages:
- build-essential
- libjansson-dev
- libgcrypt11-dev
env: CFLAGS="-Wall" AM_CFLAGS='-Werror'
# clang
- compiler: clang
addons:
apt:
packages:
- build-essential
- libjansson-dev
- libgcrypt11-dev
env: CFLAGS="-Wall -fsanitize=undefined -fno-sanitize-recover -fsanitize=address"
# w/o libgcrypt
- addons:
apt:
packages:
- build-essential
- libjansson-dev
# Win32
- addons:
apt:
packages:
- gcc-mingw-w64-i686
- binutils-mingw-w64-i686
- mingw-w64-dev
- wine
env:
- CROSS_TARGET=i686-w64-mingw32
EXEEXT=.exe
BUILD_LIBS=1
WINE_TESTS=1
OPTS="$OPTS --disable-static"
JANSSON_VERSION=v2.4
# Win64
- addons:
apt:
packages:
- gcc-mingw-w64-x86-64
- binutils-mingw-w64-x86-64
- mingw-w64-dev
- wine
env:
- CROSS_TARGET=x86_64-w64-mingw32
EXEEXT=.exe
BUILD_LIBS=1
WINE_TESTS=1
OPTS="$OPTS --disable-static"
JANSSON_VERSION=v2.4
exclude:
- compiler: gcc
# TODO: Linux32 (or 64) & OS X
script:
- if [ -n "$CROSS_TARGET" ]; then
unset CC;
TARGET_OPTS="$TARGET_OPTS --host=$CROSS_TARGET";
fi
- if [ -n "$BUILD_LIBS" ]; then
OPTS="$OPTS --with-gpg-error-prefix=$HOME";
git clone git://git.gnupg.org/libgpg-error.git -b libgpg-error-1.13 --depth 1;
pushd libgpg-error;
./autogen.sh;
./configure $TARGET_OPTS $OPTS --disable-languages --disable-doc;
make;
if [ -z "$WINE_TESTS" ]; then
LD_LIBRARY_PATH="$HOME/lib" make check;
fi;
make install;
popd;
OPTS="$OPTS --with-libgcrypt-prefix=$HOME";
git clone git://git.gnupg.org/libgcrypt.git -b libgcrypt-1.5.4 --depth 1;
pushd libgcrypt;
./autogen.sh;
./configure $TARGET_OPTS $OPTS --disable-ciphers --disable-pubkey-ciphers --disable-random --disable-asm;
make;
if [ -z "$WINE_TESTS" ]; then
LD_LIBRARY_PATH="$HOME/lib" make check;
fi;
make install;
popd;
git clone https://github.com/akheron/jansson.git -b "$JANSSON_VERSION" --depth 1;
pushd jansson;
autoreconf -f -i;
./configure $TARGET_OPTS $OPTS;
make AM_CFLAGS= ;
if [ -z "$WINE_TESTS" ]; then
LD_LIBRARY_PATH="$HOME/lib" make check;
fi;
make install;
popd;
fi
- git clone git://github.com/bitcoin/libbase58 -b v0.1.4 --depth 1
- pushd libbase58
- ./autogen.sh
- ./configure $TARGET_OPTS $OPTS
- make
- if [ -z "$WINE_TESTS" ]; then
LD_LIBRARY_PATH="$HOME/lib" make check VERBOSE=1;
fi
- make install
- popd
-
- ./autogen.sh
- ./configure $TARGET_OPTS $OPTS $CONFIGURE_OPTS || { tail -n 1000 config.log; false; };
- make
- make example$EXEEXT
- make test$EXEEXT
- if [ -z "$WINE_TESTS" ]; then
LSAN_OPTIONS=1 LD_LIBRARY_PATH="$HOME/lib" make check VERBOSE=1;
else
ln -s $HOME/bin/*.dll .libs/;
LSAN_OPTIONS=1 WINEDLLPATH="$PWD/.libs" wine .libs/test.exe;
fi
- make install

View File

@ -1,4 +1,2 @@
Luke Dashjr <luke_libblkmaker@dashjr.org>
Andy Alness <andy.alness@gmail.com>
Huang Le <4tarhl@gmail.com>
Cory Fields <cory-nospam-@coryfields.com>

View File

@ -45,25 +45,8 @@ pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = \
libblkmaker_jansson-$(LIBBLKMAKER_API_VERSION).pc
dist_noinst_SCRIPTS = autogen.sh test.sh
dist_noinst_SCRIPTS = autogen.sh
dist_noinst_DATA = \
AUTHORS COPYING README \
example.c \
testinput.c
if HAVE_LIBGCRYPT
check_PROGRAMS = test
test_SOURCES = test.c
test_CFLAGS = $(libbase58_CFLAGS) $(JANSSON_CFLAGS) $(LIBGCRYPT_CFLAGS)
test_LDADD = $(libbase58_LIBS) libblkmaker-@LIBBLKMAKER_API_VERSION@.la libblkmaker_jansson-@LIBBLKMAKER_API_VERSION@.la $(JANSSON_LIBS) $(LIBGCRYPT_LIBS)
TESTS = test.sh
EXTRA_PROGRAMS = example
example_SOURCES = example.c
example_CFLAGS = $(libbase58_CFLAGS) $(JANSSON_CFLAGS) $(LIBGCRYPT_CFLAGS)
example_LDADD = $(libbase58_LIBS) libblkmaker-@LIBBLKMAKER_API_VERSION@.la libblkmaker_jansson-@LIBBLKMAKER_API_VERSION@.la $(JANSSON_LIBS) $(LIBGCRYPT_LIBS)
else
example:
@echo "libgcrypt is required to build the example, but was not found"
.PHONY: example
endif

3
README
View File

@ -5,8 +5,7 @@ Example dependencies:
Jansson 2.1 (to read JSON from stdin)
libgcrypt (for SHA256)
For usage, check out example.c. Run "make example" to build it.
For usage, check out example.c
Note that you must assign blkmk_sha256_impl to a function pointer:
bool mysha256(void *hash_out, const void *data, size_t datasz)
hash_out must be able to overlap with data!

View File

@ -26,7 +26,6 @@
const char *blkmk_supported_rules[] = {
"csv",
"segwit",
NULL
};
@ -62,113 +61,15 @@ 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
char varintEncode(unsigned char *out, uint64_t n) {
if (n < 0xfd)
{
out[0] = n;
return 1;
}
char L;
if (n <= 0xffff)
{
out[0] = '\xfd';
L = 3;
}
else
if (n <= 0xffffffff)
{
out[0] = '\xfe';
L = 5;
}
else
{
out[0] = '\xff';
L = 9;
}
for (unsigned char i = 1; i < L; ++i)
out[i] = (n >> ((i - 1) * 8)) % 256;
return L;
}
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);
}
static
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 */) {
if (script[i] == 0x4c) {
if (i + 1 >= scriptsz) {
break;
}
++i;
}
i += script[i];
} else if (script[i] == 0x4d /* OP_PUSHDATA2 */) {
if (i + 2 >= scriptsz) {
break;
}
i += 2 + upk_u16le(script, i + 1);
} else if (script[i] == 0x4e /* OP_PUSHDATA4 */) {
if (i + 4 >= scriptsz) {
break;
}
i += 4 + upk_u32le(script, i + 1);
} else if (script[i] == 0xac /* OP_CHECKSIG */ || script[i] == 0xad /* OP_CHECKSIGVERIFY */) {
++sigops;
} else if (script[i] == 0xae /* OP_CHECKMULTISIG */ || script[i] == 0xaf /* OP_CHECKMULTISIGVERIFY */) {
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) {
const bool replace_existing = *inout_newcb;
*inout_newcb = false;
@ -178,7 +79,7 @@ uint64_t blkmk_init_generation3(blktemplate_t * const tmpl, const void * const s
return 0;
}
if (!tmpl->has_cbvalue) {
if (!tmpl->cbvalue) {
// TODO: Figure it out from the existing cbtxn
return 0;
}
@ -248,31 +149,24 @@ 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, 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)) {
if (pretx_size + tmpl->txns_datasz + off > tmpl->sizelimit) {
free(data);
return 0;
}
struct blktxn_t *txn = malloc(sizeof(*tmpl->cbtxn));
struct blktxn_t *txn = calloc(1, sizeof(*tmpl->cbtxn));
if (!txn)
{
free(data);
return 0;
}
blktxn_init(txn);
txn->data = data;
txn->datasz = off;
txn->sigops_ = sigops_counted;
txn->weight = gentx_weight;
if (tmpl->cbtxn)
{
blktxn_clean(tmpl->cbtxn);
_blktxn_free(tmpl->cbtxn);
free(tmpl->cbtxn);
}
tmpl->cbtxn = txn;
@ -347,9 +241,7 @@ bool blkmk_build_merkle_branches(blktemplate_t * const tmpl)
for (i = 0; i < tmpl->txncount; ++i)
{
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));
memcpy(&hashes[i + 1], tmpl->txns[i].hash_, sizeof(*hashes));
}
for (i = 0; i < branchcount; ++i)
@ -403,80 +295,10 @@ 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
bool _blkmk_append_cb(blktemplate_t * const tmpl, void * const vout, const void * const append, const size_t appendsz, size_t * const appended_at_offset, int16_t * const sigops_counted_p) {
bool _blkmk_append_cb(blktemplate_t * const tmpl, void * const vout, const void * const append, const size_t appendsz, size_t * const appended_at_offset) {
unsigned char *out = vout;
unsigned char *in = tmpl->cbtxn->data;
size_t insz = tmpl->cbtxn->datasz;
@ -490,11 +312,6 @@ bool _blkmk_append_cb(blktemplate_t * const tmpl, void * const vout, const void
return false;
}
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;
@ -513,21 +330,6 @@ 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], tmpl->_bip141_sigops) - orig_scriptSig_sigops;
if (tmpl->txns_sigops >= 0 && tmpl->txns_sigops + sigops_counted > tmpl->sigoplimit) {
// Overflowed :(
if (out == in) {
// Revert it!
out[cbScriptSigLen] -= appendsz;
memmove(&out[cbPostScriptSig], outPostScriptSig, insz - cbPostScriptSig);
}
return false;
}
if (sigops_counted_p) {
*sigops_counted_p = sigops_counted;
}
return true;
}
@ -545,9 +347,6 @@ ssize_t blkmk_append_coinbase_safe2(blktemplate_t * const tmpl, const void * con
if (extranoncesz < sizeof(unsigned int))
extranoncesz = sizeof(unsigned int);
}
if (tmpl->cbtxn->datasz <= cbScriptSigLen || tmpl->cbtxn->datasz <= cbScriptSigLen + tmpl->cbtxn->data[cbScriptSigLen]) {
return -6;
}
if (extranoncesz > libblkmaker_coinbase_size_limit || tmpl->cbtxn->data[cbScriptSigLen] > libblkmaker_coinbase_size_limit || extranoncesz + tmpl->cbtxn->data[cbScriptSigLen] > libblkmaker_coinbase_size_limit) {
return -5;
}
@ -563,16 +362,6 @@ 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;
@ -581,10 +370,9 @@ ssize_t blkmk_append_coinbase_safe2(blktemplate_t * const tmpl, const void * con
return -2;
tmpl->cbtxn->data = newp;
if (!_blkmk_append_cb(tmpl, newp, append, appendsz, NULL, &tmpl->cbtxn->sigops_))
if (!_blkmk_append_cb(tmpl, newp, append, appendsz, NULL))
return -3;
tmpl->cbtxn->datasz += appendsz;
tmpl->cbtxn->weight += appendsz * 4;
return availsz;
}
@ -604,7 +392,7 @@ bool _blkmk_extranonce(blktemplate_t *tmpl, void *vout, unsigned int workid, siz
return true;
}
if (!_blkmk_append_cb(tmpl, vout, &workid, sizeof(workid), NULL, NULL))
if (!_blkmk_append_cb(tmpl, vout, &workid, sizeof(workid), NULL))
return false;
*offs += insz + sizeof(workid);
@ -612,70 +400,6 @@ 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)
{
@ -702,13 +426,10 @@ 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) + max_witness_commitment_insert];
unsigned char cbtxndata[tmpl->cbtxn->datasz + sizeof(dataid)];
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;
@ -772,20 +493,16 @@ 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 + max_witness_commitment_insert);
*out_cbtxn = malloc(*out_cbtxnsz);
if (!*out_cbtxn)
return false;
unsigned char dummy[extranoncesz];
memset(dummy, 0, extranoncesz);
if (!_blkmk_append_cb(tmpl, *out_cbtxn, dummy, extranoncesz, cbextranonceoffset, NULL))
if (!_blkmk_append_cb(tmpl, *out_cbtxn, dummy, extranoncesz, cbextranonceoffset))
{
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);
@ -798,9 +515,7 @@ bool blkmk_get_mdata(blktemplate_t * const tmpl, void * const buf, const size_t
free(*out_cbtxn);
return false;
}
if (branches_bytesz) {
memcpy(*out_branches, tmpl->_mrklbranch, branches_bytesz);
}
memcpy(*out_branches, tmpl->_mrklbranch, branches_bytesz);
return true;
}
@ -820,6 +535,35 @@ unsigned long blkmk_work_left(const blktemplate_t *tmpl) {
return UINT_MAX - tmpl->next_dataid;
}
static
char varintEncode(unsigned char *out, uint64_t n) {
if (n < 0xfd)
{
out[0] = n;
return 1;
}
char L;
if (n <= 0xffff)
{
out[0] = '\xfd';
L = 3;
}
else
if (n <= 0xffffffff)
{
out[0] = '\xfe';
L = 5;
}
else
{
out[0] = '\xff';
L = 9;
}
for (unsigned char i = 1; i < L; ++i)
out[i] = (n >> ((i - 1) * 8)) % 256;
return L;
}
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)
{
const bool incl_gentxn = (foreign || (!(tmpl->mutations & BMAb_TRUNCATE && !extranoncesz)));
@ -828,7 +572,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 + (max_varint_size - 1) /* possible enlargement to txout count when adding commitment output */ + commitment_txout_size;
blkbuf_sz += tmpl->cbtxn->datasz + extranoncesz;
if (incl_alltxn) {
blkbuf_sz += tmpl->txns_datasz;
}
@ -839,32 +583,26 @@ static char *blkmk_assemble_submission2_internal(blktemplate_t * const tmpl, con
return NULL;
}
const size_t header_before_nonce_sz = libblkmaker_blkheader_size - sizeof(nonce);
memcpy(blk, data, header_before_nonce_sz);
memcpy(blk, data, 76);
nonce = htonl(nonce);
memcpy(&blk[header_before_nonce_sz], &nonce, sizeof(nonce));
size_t offs = libblkmaker_blkheader_size;
memcpy(&blk[76], &nonce, 4);
size_t offs = 80;
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)) {
if (!_blkmk_append_cb(tmpl, &blk[offs], extranonce, extranoncesz, NULL)) {
free(blk);
return NULL;
}
cbtxnlen += tmpl->cbtxn->datasz + extranoncesz;
offs += tmpl->cbtxn->datasz + extranoncesz;
} else {
memcpy(&blk[offs], tmpl->cbtxn->data, tmpl->cbtxn->datasz);
cbtxnlen += tmpl->cbtxn->datasz;
offs += 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)

View File

@ -11,7 +11,7 @@
extern "C" {
#endif
#define BLKMAKER_VERSION (8L)
#define BLKMAKER_VERSION (7L)
#define BLKMAKER_MAX_BLOCK_VERSION (0x3fffffff)
#define BLKMAKER_MAX_PRERULES_BLOCK_VERSION (4)

View File

@ -8,7 +8,6 @@
#define _BSD_SOURCE
#define _DEFAULT_SOURCE
#include <limits.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@ -186,11 +185,9 @@ json_t *blktmpl_request_jansson(const uint32_t caps, const char * const lpid) {
static void my_flip(void *, size_t);
static
const char *parse_txn(struct blktxn_t *txn, json_t *txnj, size_t my_tx_index) {
const char *parse_txn(struct blktxn_t *txn, json_t *txnj) {
json_t *vv;
blktxn_init(txn);
if (!((vv = json_object_get(txnj, "data")) && json_is_string(vv)))
return "Missing or invalid type for transaction data";
const char *hexdata = json_string_value(vv);
@ -213,80 +210,7 @@ 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) {
json_t *v;
long i;
double f;
unsigned long ul;
txn->depends = malloc(sizeof(*txn->depends) * depcount);
for (i = 0; i < depcount; ++i) {
v = json_array_get(vv, i);
if (!json_is_number(v)) {
break;
}
f = json_number_value(v);
ul = f;
if (f != ul || ul >= my_tx_index) {
// Out of range for storage type, fractional number, forward dependency, etc
break;
}
txn->depends[i] = ul;
}
if (i != depcount) {
// We failed somewhere
free(txn->depends);
txn->depends = NULL;
} else {
// Success, finish up with storing the count
txn->dependscount = depcount;
}
}
}
if ((vv = json_object_get(txnj, "fee")) && json_is_number(vv)) {
double f;
int64_t i64;
f = json_number_value(vv);
i64 = f;
if (i64 == f && i64 >= 0) {
txn->fee_ = i64;
}
}
if ((vv = json_object_get(txnj, "required")) && json_is_true(vv)) {
txn->required = true;
}
if ((vv = json_object_get(txnj, "sigops")) && json_is_number(vv)) {
const double f = json_number_value(vv);
int16_t i16 = f;
if (i16 == f && i16 >= 0) {
txn->sigops_ = i16;
}
}
// TODO: dependcount/depends, fee, required, sigops
return NULL;
}
@ -328,9 +252,74 @@ 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;
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)))) {
return s;
}
tmpl->txns_datasz += txn->datasz;
}
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)))
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--; )
@ -366,9 +355,6 @@ 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");
@ -416,95 +402,6 @@ 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";
}
if ((v = json_object_get(json, "coinbasevalue")) && json_is_number(v)) {
const double tmpd = json_number_value(v);
const uint64_t tmp = tmpd;
if (tmpd == tmp) {
tmpl->has_cbvalue = true;
tmpl->cbvalue = tmp;
}
}
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->has_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;

View File

@ -7,7 +7,6 @@
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
@ -50,10 +49,10 @@ const char *blktmpl_capabilityname(gbt_capabilities_t caps) {
return NULL;
}
uint32_t blktmpl_getcapability(const char *n) {
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 ((uint32_t)1) << i;
return 1 << i;
if (!strcasecmp(n, "time")) {
// multi-capability
return BMM_TIMEINC | BMM_TIMEDEC;
@ -63,22 +62,6 @@ uint32_t blktmpl_getcapability(const char *n) {
return 0;
}
void blktxn_init(struct blktxn_t * const txn) {
txn->data = NULL;
txn->datasz = 0;
txn->hash = NULL;
txn->hash_ = NULL;
txn->txid = NULL;
txn->dependscount = -1;
txn->depends = NULL;
txn->fee_ = -1;
txn->required = false;
txn->sigops_ = -1;
txn->weight = -1;
}
blktemplate_t *blktmpl_create() {
blktemplate_t *tmpl;
tmpl = calloc(1, sizeof(*tmpl));
@ -87,11 +70,11 @@ blktemplate_t *blktmpl_create() {
tmpl->sigoplimit = USHRT_MAX;
tmpl->sizelimit = ULONG_MAX;
tmpl->weightlimit = INT64_MAX;
tmpl->maxtime = 0xffffffff;
tmpl->maxtimeoff = 0x7fff;
tmpl->mintimeoff = -0x7fff;
tmpl->maxnonce = 0xffffffff;
tmpl->expires = 0x7fff;
return tmpl;
@ -115,13 +98,13 @@ bool blktmpl_get_submitold(blktemplate_t *tmpl) {
return tmpl->submitold;
}
void blktxn_clean(struct blktxn_t * const bt) {
void _blktxn_free(struct blktxn_t *bt) {
free(bt->data);
free(bt->hash);
free(bt->hash_);
free(bt->depends);
free(bt->txid);
}
#define blktxn_free _blktxn_free
static
void blkaux_clean(struct blkaux_t * const aux) {
@ -131,15 +114,14 @@ void blkaux_clean(struct blkaux_t * const aux) {
void blktmpl_free(blktemplate_t *tmpl) {
for (unsigned long i = 0; i < tmpl->txncount; ++i)
blktxn_clean(&tmpl->txns[i]);
blktxn_free(&tmpl->txns[i]);
free(tmpl->txns);
if (tmpl->cbtxn)
{
blktxn_clean(tmpl->cbtxn);
blktxn_free(tmpl->cbtxn);
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);

View File

@ -34,16 +34,14 @@ struct blktxn_t {
// NOTE: The byte order of hash is backward; use hash_ instead
txnhash_t *hash;
signed long dependscount;
signed long dependcount;
unsigned long *depends;
int64_t fee_;
uint64_t fee;
bool required;
int16_t sigops_;
int32_t weight;
int16_t sigops;
txnhash_t *hash_;
txnhash_t *txid;
};
struct blkaux_t {
@ -91,8 +89,8 @@ typedef enum {
extern const char *blktmpl_capabilityname(gbt_capabilities_t);
#define BLKTMPL_LONGEST_CAPABILITY_NAME (16)
// NOTE: blktmpl_getcapability("time") yields a combination of gbt_capabilities_t
extern uint32_t blktmpl_getcapability(const char *);
// ABI FIXME: return uint32_t since "time" can yield a combination gbt_capabilities_t
extern gbt_capabilities_t blktmpl_getcapability(const char *);
typedef gbt_capabilities_t blkmutations_t;
@ -137,6 +135,10 @@ typedef struct {
blktime_t mintime;
blktime_diff_t mintimeoff;
// Note these never were and are NOT supported, but retained merely for ABI compatibility; they will be removed without an API version bump in 0.6!
blknonce_t minnonce;
blknonce_t maxnonce;
// TEMPORARY HACK
libblkmaker_hash_t *_mrklbranch;
int _mrklbranchcount;
@ -146,25 +148,13 @@ typedef struct {
struct blkaux_t *auxs;
unsigned long txns_datasz;
signed long txns_sigops;
char **rules;
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;
bool has_cbvalue;
} blktemplate_t;
extern void blktxn_init(struct blktxn_t *);
extern void blktxn_clean(struct blktxn_t *);
extern blktemplate_t *blktmpl_create();
extern uint32_t blktmpl_addcaps(const blktemplate_t *);
extern const struct blktmpl_longpoll_req *blktmpl_get_longpoll(blktemplate_t *);

View File

@ -5,7 +5,7 @@ dnl * under the terms of the standard MIT license. See COPYING for more details
AC_INIT(
[libblkmaker],
[0.6.0],
[0.5.3],
[luke_libblkmaker@dashjr.org],
[libblkmaker],
[http://gitorious.org/bitcoin/libblkmaker])
@ -19,7 +19,7 @@ m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
LT_INIT([disable-static])
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
AC_SUBST([LIBBLKMAKER_SO_VERSION], [8:0:0])
AC_SUBST([LIBBLKMAKER_SO_VERSION], [7:0:1])
AC_SUBST([LIBBLKMAKER_API_VERSION], [0.1])
AC_CONFIG_FILES([Makefile
@ -51,18 +51,4 @@ PKG_CHECK_MODULES([libbase58],[libbase58])
AC_CHECK_LIB([ws2_32], [strchr])
dnl libgcrypt necessary to build tests and example
dnl check for libgcrypt:
m4_ifdef([AM_PATH_LIBGCRYPT], [
AM_PATH_LIBGCRYPT([],
[
have_libgcrypt=yes
],[
have_libgcrypt=no
])
],[
m4_warn([syntax], [AM_PATH_LIBGCRYPT missing; example and tests will not be available])
])
AM_CONDITIONAL([HAVE_LIBGCRYPT], [test x$have_libgcrypt = xyes])
AC_OUTPUT

View File

@ -9,11 +9,7 @@
#include <inttypes.h>
#include <stdint.h>
#ifndef WIN32
#include <arpa/inet.h>
#else
#include <winsock2.h>
#endif
#include <gcrypt.h>
#include <libbase58.h>
@ -131,5 +127,4 @@ int main(int argc, char**argv) {
send_json(req);
}
blktmpl_free(tmpl);
return 0;
}

View File

@ -7,7 +7,6 @@ Name: @PACKAGE_NAME@_jansson
Description: Bitcoin block maker library.
Version: @PACKAGE_VERSION@
URL: @PACKAGE_URL@
Libs: -L${libdir} -lblkmaker_jansson-@LIBBLKMAKER_API_VERSION@ -lblkmaker-@LIBBLKMAKER_API_VERSION@
Libs: -L${libdir} -lblkmaker-@LIBBLKMAKER_API_VERSION@ -lblkmaker_jansson-@LIBBLKMAKER_API_VERSION@
Cflags: -I${includedir}/libblkmaker-@LIBBLKMAKER_API_VERSION@
Requires: jansson
Requires.private: libbase58

View File

@ -11,6 +11,9 @@ extern bool _blkmk_dblsha256(void *hash, const void *data, size_t datasz);
extern bool blkmk_sample_data_(blktemplate_t *, uint8_t *, unsigned int dataid);
extern char *blkmk_assemble_submission2_(blktemplate_t *, const unsigned char *data, const void *extranonce, size_t extranoncesz, unsigned int dataid, blknonce_t nonce, bool foreign);
// blktemplate.c
extern void _blktxn_free(struct blktxn_t *);
// hex.c
extern void _blkmk_bin2hex(char *out, const void *data, size_t datasz);
extern bool _blkmk_hex2bin(void *o, const char *x, size_t len);
@ -27,36 +30,4 @@ int blkmk_flsl(unsigned long n)
return i;
}
static inline
uint16_t upk_u16le(const void * const bufp, const int offset)
{
const uint8_t * const buf = bufp;
return (((uint16_t)buf[offset+0]) << 0)
| (((uint16_t)buf[offset+1]) << 8);
}
static inline
uint32_t upk_u32le(const void * const bufp, const int offset)
{
const uint8_t * const buf = bufp;
return (((uint32_t)buf[offset+0]) << 0)
| (((uint32_t)buf[offset+1]) << 8)
| (((uint32_t)buf[offset+2]) << 0x10)
| (((uint32_t)buf[offset+3]) << 0x18);
}
static inline
uint64_t upk_u64le(const void * const bufp, const int offset)
{
const uint8_t * const buf = bufp;
return (((uint64_t)buf[offset+0]) << 0)
| (((uint64_t)buf[offset+1]) << 8)
| (((uint64_t)buf[offset+2]) << 0x10)
| (((uint64_t)buf[offset+3]) << 0x18)
| (((uint64_t)buf[offset+4]) << 0x20)
| (((uint64_t)buf[offset+5]) << 0x28)
| (((uint64_t)buf[offset+6]) << 0x30)
| (((uint64_t)buf[offset+7]) << 0x38);
}
#endif

1343
test.c

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +0,0 @@
#!/bin/sh
# To avoid exit codes other than 0 or 1
./test || exit 1