Compare commits
109 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
365df024bc | ||
|
|
c7388aacf8 | ||
|
|
c1392f15be | ||
|
|
05a975a424 | ||
|
|
2049056cfd | ||
|
|
721ce42f57 | ||
|
|
c7a1c1278b | ||
|
|
c2785585dc | ||
|
|
f94c40ff5c | ||
|
|
47a494e113 | ||
|
|
5e409f22fb | ||
|
|
7f103073ad | ||
|
|
2a37933698 | ||
|
|
15f79c6f71 | ||
|
|
b8055bd495 | ||
|
|
7605755747 | ||
|
|
8b28f02857 | ||
|
|
f093ad8ee7 | ||
|
|
fdb2a280b0 | ||
|
|
bea591911d | ||
|
|
498221e0b1 | ||
|
|
76db08733f | ||
|
|
9d6b0d0649 | ||
|
|
0dcc8d8697 | ||
|
|
f3659638d7 | ||
|
|
18ece76f77 | ||
|
|
30ba82f339 | ||
|
|
cdb5841c88 | ||
|
|
31c1d2c168 | ||
|
|
970017ab38 | ||
|
|
793d180847 | ||
|
|
fd04e03c5d | ||
|
|
9bb03c6cf3 | ||
|
|
c1a159d417 | ||
|
|
4572fcb97b | ||
|
|
07ce01f57a | ||
|
|
04753c7257 | ||
|
|
bdb9519f1b | ||
|
|
cf8d325b30 | ||
|
|
0d94076671 | ||
|
|
136f2b5457 | ||
|
|
5c471cb3fe | ||
|
|
c0f590e889 | ||
|
|
70a022e944 | ||
|
|
bfd7d9469a | ||
|
|
5a6bc0caec | ||
|
|
6c56da6a04 | ||
|
|
f333f3c662 | ||
|
|
5889aeab25 | ||
|
|
130cfbdb3e | ||
|
|
963262af08 | ||
|
|
147e86b466 | ||
|
|
a9b3541a60 | ||
|
|
aa74130c59 | ||
|
|
28f39f440c | ||
|
|
3280aab174 | ||
|
|
f692fddffa | ||
|
|
aaaa53e7d9 | ||
|
|
c9030312dc | ||
|
|
e1a1b1bd07 | ||
|
|
3ff3604939 | ||
|
|
86c6f760bf | ||
|
|
7e10567263 | ||
|
|
c524b0160d | ||
|
|
2e0cc834fe | ||
|
|
28a2bb7f6b | ||
|
|
5307b027f6 | ||
|
|
b5c6d97be7 | ||
|
|
048483d97c | ||
|
|
1250b472f0 | ||
|
|
871871ddd5 | ||
|
|
8f8110a7e4 | ||
|
|
80c85d212a | ||
|
|
016aa307f5 | ||
|
|
1ba845f671 | ||
|
|
861bd066fe | ||
|
|
5ee6256cb4 | ||
|
|
aef9cbc5a5 | ||
|
|
72d0d641b4 | ||
|
|
c651bc036f | ||
|
|
2d822c6bbc | ||
|
|
651323c7c1 | ||
|
|
7364be59db | ||
|
|
4a1dcb5cb6 | ||
|
|
df9c3e9303 | ||
|
|
3c7889fa23 | ||
|
|
e37ae9022b | ||
|
|
1cf20a8348 | ||
|
|
1a3cdfd792 | ||
|
|
cd1ae36d0d | ||
|
|
56187b6710 | ||
|
|
ba398a34e7 | ||
|
|
b05c2c50de | ||
|
|
4babc68a5f | ||
|
|
12db22114d | ||
|
|
5016f8d86a | ||
|
|
3be2fadaca | ||
|
|
7e0d27119c | ||
|
|
d5a43949b1 | ||
|
|
382e864589 | ||
|
|
d0a9367017 | ||
|
|
9a5799891e | ||
|
|
15e2c35bf6 | ||
|
|
22f6e42844 | ||
|
|
c70cc4f116 | ||
|
|
29f6df9585 | ||
|
|
a1dbe722fa | ||
|
|
74e674632e | ||
|
|
a336d9a70c |
5
.gitignore
vendored
5
.gitignore
vendored
@ -31,3 +31,8 @@ config.*
|
||||
ii
|
||||
ar-lib
|
||||
compile
|
||||
test-driver
|
||||
test
|
||||
test-suite.log
|
||||
test.log
|
||||
test.trs
|
||||
|
||||
129
.travis.yml
Normal file
129
.travis.yml
Normal file
@ -0,0 +1,129 @@
|
||||
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
|
||||
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>
|
||||
|
||||
19
Makefile.am
19
Makefile.am
@ -45,8 +45,25 @@ pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = \
|
||||
libblkmaker_jansson-$(LIBBLKMAKER_API_VERSION).pc
|
||||
|
||||
dist_noinst_SCRIPTS = autogen.sh
|
||||
dist_noinst_SCRIPTS = autogen.sh test.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
3
README
@ -5,7 +5,8 @@ Example dependencies:
|
||||
Jansson 2.1 (to read JSON from stdin)
|
||||
libgcrypt (for SHA256)
|
||||
|
||||
For usage, check out example.c
|
||||
For usage, check out example.c. Run "make example" to build it.
|
||||
|
||||
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!
|
||||
|
||||
360
blkmaker.c
360
blkmaker.c
@ -26,6 +26,7 @@
|
||||
|
||||
const char *blkmk_supported_rules[] = {
|
||||
"csv",
|
||||
"segwit",
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -61,15 +62,113 @@ 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 *, uint64_t);
|
||||
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 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;
|
||||
@ -79,7 +178,7 @@ uint64_t blkmk_init_generation3(blktemplate_t * const tmpl, const void * const s
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!tmpl->cbvalue) {
|
||||
if (!tmpl->has_cbvalue) {
|
||||
// TODO: Figure it out from the existing cbtxn
|
||||
return 0;
|
||||
}
|
||||
@ -149,24 +248,31 @@ 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);
|
||||
if (pretx_size + tmpl->txns_datasz + off > tmpl->sizelimit) {
|
||||
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;
|
||||
}
|
||||
|
||||
struct blktxn_t *txn = calloc(1, sizeof(*tmpl->cbtxn));
|
||||
struct blktxn_t *txn = malloc(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_free(tmpl->cbtxn);
|
||||
blktxn_clean(tmpl->cbtxn);
|
||||
free(tmpl->cbtxn);
|
||||
}
|
||||
tmpl->cbtxn = txn;
|
||||
@ -241,7 +347,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)
|
||||
@ -295,10 +403,80 @@ 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) {
|
||||
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) {
|
||||
unsigned char *out = vout;
|
||||
unsigned char *in = tmpl->cbtxn->data;
|
||||
size_t insz = tmpl->cbtxn->datasz;
|
||||
@ -312,6 +490,11 @@ 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;
|
||||
@ -330,6 +513,21 @@ 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;
|
||||
}
|
||||
|
||||
@ -347,6 +545,9 @@ 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;
|
||||
}
|
||||
@ -362,6 +563,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;
|
||||
|
||||
@ -370,9 +581,10 @@ 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))
|
||||
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;
|
||||
}
|
||||
@ -392,7 +604,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))
|
||||
if (!_blkmk_append_cb(tmpl, vout, &workid, sizeof(workid), NULL, NULL))
|
||||
return false;
|
||||
|
||||
*offs += insz + sizeof(workid);
|
||||
@ -400,6 +612,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)
|
||||
{
|
||||
@ -426,10 +702,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;
|
||||
|
||||
@ -493,16 +772,20 @@ 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];
|
||||
memset(dummy, 0, extranoncesz);
|
||||
if (!_blkmk_append_cb(tmpl, *out_cbtxn, dummy, extranoncesz, cbextranonceoffset))
|
||||
if (!_blkmk_append_cb(tmpl, *out_cbtxn, dummy, extranoncesz, cbextranonceoffset, NULL))
|
||||
{
|
||||
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);
|
||||
@ -515,7 +798,9 @@ bool blkmk_get_mdata(blktemplate_t * const tmpl, void * const buf, const size_t
|
||||
free(*out_cbtxn);
|
||||
return false;
|
||||
}
|
||||
memcpy(*out_branches, tmpl->_mrklbranch, branches_bytesz);
|
||||
if (branches_bytesz) {
|
||||
memcpy(*out_branches, tmpl->_mrklbranch, branches_bytesz);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -535,35 +820,6 @@ 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)));
|
||||
@ -572,7 +828,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;
|
||||
}
|
||||
@ -583,26 +839,32 @@ static char *blkmk_assemble_submission2_internal(blktemplate_t * const tmpl, con
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(blk, data, 76);
|
||||
const size_t header_before_nonce_sz = libblkmaker_blkheader_size - sizeof(nonce);
|
||||
memcpy(blk, data, header_before_nonce_sz);
|
||||
nonce = htonl(nonce);
|
||||
memcpy(&blk[76], &nonce, 4);
|
||||
size_t offs = 80;
|
||||
memcpy(&blk[header_before_nonce_sz], &nonce, sizeof(nonce));
|
||||
size_t offs = libblkmaker_blkheader_size;
|
||||
|
||||
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)) {
|
||||
if (!_blkmk_append_cb(tmpl, &blk[offs], extranonce, extranoncesz, NULL, NULL)) {
|
||||
free(blk);
|
||||
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)
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BLKMAKER_VERSION (7L)
|
||||
#define BLKMAKER_VERSION (8L)
|
||||
#define BLKMAKER_MAX_BLOCK_VERSION (0x3fffffff)
|
||||
#define BLKMAKER_MAX_PRERULES_BLOCK_VERSION (4)
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#define _BSD_SOURCE
|
||||
#define _DEFAULT_SOURCE
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -185,9 +186,11 @@ 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) {
|
||||
const char *parse_txn(struct blktxn_t *txn, json_t *txnj, size_t my_tx_index) {
|
||||
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);
|
||||
@ -210,7 +213,80 @@ const char *parse_txn(struct blktxn_t *txn, json_t *txnj) {
|
||||
my_flip(*txn->hash_, sizeof(*txn->hash_));
|
||||
}
|
||||
|
||||
// TODO: dependcount/depends, fee, required, sigops
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -252,74 +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;
|
||||
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--; )
|
||||
@ -355,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");
|
||||
@ -402,6 +416,95 @@ 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;
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
@ -49,10 +50,10 @@ const char *blktmpl_capabilityname(gbt_capabilities_t caps) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gbt_capabilities_t blktmpl_getcapability(const char *n) {
|
||||
uint32_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;
|
||||
return ((uint32_t)1) << i;
|
||||
if (!strcasecmp(n, "time")) {
|
||||
// multi-capability
|
||||
return BMM_TIMEINC | BMM_TIMEDEC;
|
||||
@ -62,6 +63,22 @@ gbt_capabilities_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));
|
||||
@ -70,11 +87,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;
|
||||
@ -98,13 +115,13 @@ bool blktmpl_get_submitold(blktemplate_t *tmpl) {
|
||||
return tmpl->submitold;
|
||||
}
|
||||
|
||||
void _blktxn_free(struct blktxn_t *bt) {
|
||||
void blktxn_clean(struct blktxn_t * const 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) {
|
||||
@ -114,14 +131,15 @@ void blkaux_clean(struct blkaux_t * const aux) {
|
||||
|
||||
void blktmpl_free(blktemplate_t *tmpl) {
|
||||
for (unsigned long i = 0; i < tmpl->txncount; ++i)
|
||||
blktxn_free(&tmpl->txns[i]);
|
||||
blktxn_clean(&tmpl->txns[i]);
|
||||
free(tmpl->txns);
|
||||
if (tmpl->cbtxn)
|
||||
{
|
||||
blktxn_free(tmpl->cbtxn);
|
||||
blktxn_clean(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);
|
||||
|
||||
@ -34,14 +34,16 @@ struct blktxn_t {
|
||||
// NOTE: The byte order of hash is backward; use hash_ instead
|
||||
txnhash_t *hash;
|
||||
|
||||
signed long dependcount;
|
||||
signed long dependscount;
|
||||
unsigned long *depends;
|
||||
|
||||
uint64_t fee;
|
||||
int64_t fee_;
|
||||
bool required;
|
||||
int16_t sigops;
|
||||
int16_t sigops_;
|
||||
int32_t weight;
|
||||
|
||||
txnhash_t *hash_;
|
||||
txnhash_t *txid;
|
||||
};
|
||||
|
||||
struct blkaux_t {
|
||||
@ -89,8 +91,8 @@ 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 *);
|
||||
// NOTE: blktmpl_getcapability("time") yields a combination of gbt_capabilities_t
|
||||
extern uint32_t blktmpl_getcapability(const char *);
|
||||
|
||||
|
||||
typedef gbt_capabilities_t blkmutations_t;
|
||||
@ -135,10 +137,6 @@ 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;
|
||||
@ -148,13 +146,25 @@ 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 *);
|
||||
|
||||
18
configure.ac
18
configure.ac
@ -5,7 +5,7 @@ dnl * under the terms of the standard MIT license. See COPYING for more details
|
||||
|
||||
AC_INIT(
|
||||
[libblkmaker],
|
||||
[0.5.3],
|
||||
[0.6.0],
|
||||
[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], [7:0:1])
|
||||
AC_SUBST([LIBBLKMAKER_SO_VERSION], [8:0:0])
|
||||
AC_SUBST([LIBBLKMAKER_API_VERSION], [0.1])
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
@ -51,4 +51,18 @@ 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
|
||||
|
||||
@ -9,7 +9,11 @@
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <arpa/inet.h>
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#include <gcrypt.h>
|
||||
#include <libbase58.h>
|
||||
@ -127,4 +131,5 @@ int main(int argc, char**argv) {
|
||||
send_json(req);
|
||||
}
|
||||
blktmpl_free(tmpl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ Name: @PACKAGE_NAME@_jansson
|
||||
Description: Bitcoin block maker library.
|
||||
Version: @PACKAGE_VERSION@
|
||||
URL: @PACKAGE_URL@
|
||||
Libs: -L${libdir} -lblkmaker-@LIBBLKMAKER_API_VERSION@ -lblkmaker_jansson-@LIBBLKMAKER_API_VERSION@
|
||||
Libs: -L${libdir} -lblkmaker_jansson-@LIBBLKMAKER_API_VERSION@ -lblkmaker-@LIBBLKMAKER_API_VERSION@
|
||||
Cflags: -I${includedir}/libblkmaker-@LIBBLKMAKER_API_VERSION@
|
||||
Requires: jansson
|
||||
Requires.private: libbase58
|
||||
|
||||
35
private.h
35
private.h
@ -11,9 +11,6 @@ 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);
|
||||
@ -30,4 +27,36 @@ 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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user