Compare commits

..

1 Commits

Author SHA1 Message Date
Luke Dashjr
6b90a10686 This stable branch is no longer maintained.
Please upgrade.
2014-11-18 21:35:03 +00:00
20 changed files with 304 additions and 2835 deletions

13
.gitignore vendored
View File

@ -1,10 +1,3 @@
*.gcov
*.gcda
*.gcno
vgcore*
core*
*.orig
*.rej
*~ *~
*.so *.so
*.o *.o
@ -30,9 +23,3 @@ autom4te.cache
config.* config.*
ii ii
ar-lib 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 @@
Luke Dashjr <luke_libblkmaker@dashjr.org> Luke Dashjr <luke_libblkmaker@dashjr.org>
Andy Alness <andy.alness@gmail.com>
Huang Le <4tarhl@gmail.com>
Cory Fields <cory-nospam-@coryfields.com>

2
END-OF-LIFE Normal file
View File

@ -0,0 +1,2 @@
This stable branch is no longer maintained.
Please upgrade.

View File

@ -15,12 +15,7 @@ libblkmaker_@LIBBLKMAKER_API_VERSION@_la_SOURCES = \
hex.c \ hex.c \
private.h private.h
libblkmaker_@LIBBLKMAKER_API_VERSION@_la_CFLAGS = \ libblkmaker_@LIBBLKMAKER_API_VERSION@_la_LDFLAGS = -version-info $(LIBBLKMAKER_SO_VERSION) -no-undefined
$(libbase58_CFLAGS)
libblkmaker_@LIBBLKMAKER_API_VERSION@_la_LDFLAGS = \
$(libbase58_LIBS) \
-no-undefined \
-version-info $(LIBBLKMAKER_SO_VERSION)
libblkmaker_includedir = $(includedir)/libblkmaker-$(LIBBLKMAKER_API_VERSION) libblkmaker_includedir = $(includedir)/libblkmaker-$(LIBBLKMAKER_API_VERSION)
libblkmaker_include_HEADERS = \ libblkmaker_include_HEADERS = \
@ -45,25 +40,8 @@ pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = \ pkgconfig_DATA = \
libblkmaker_jansson-$(LIBBLKMAKER_API_VERSION).pc libblkmaker_jansson-$(LIBBLKMAKER_API_VERSION).pc
dist_noinst_SCRIPTS = autogen.sh test.sh dist_noinst_SCRIPTS = autogen.sh
dist_noinst_DATA = \ dist_noinst_DATA = \
AUTHORS COPYING README \ AUTHORS COPYING README \
example.c \ example.c \
testinput.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

17
README
View File

@ -5,19 +5,12 @@ Example dependencies:
Jansson 2.1 (to read JSON from stdin) Jansson 2.1 (to read JSON from stdin)
libgcrypt (for SHA256) 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: Note that you must assign blkmk_sha256_impl to a function pointer:
bool mysha256(void *hash_out, const void *data, size_t datasz) bool mysha256(void *hash_out, const void *data, size_t datasz)
hash_out must be able to overlap with data! hash_out must be able to overlap with data!
Also note that you should NOT roll ntime for data retrieved without explicitly Also note that you should NOT roll ntime for data retrieved; while it will
checking that it falls within the template's limitations (mintime, maxtime, probably work, there is no guarantee it won't fall outside the maxtime limits
mintimeoff, and maxtimeoff); read the BIP 23 specification in detail to for the blocktemplate. It is usually best to simply get more data as often
understand how they work. It is usually best to simply get more data as often as it is needed.
as it is needed. For blkmk_get_mdata, you may specify that you intend to roll
the ntime header exactly once per second past usetime - it will then set
*out_expires such that the expiration occurs before you roll beyond any ntime
limits. If you are rolling ntime at any rate other than once per second, you
should NOT specify can_roll_ntime to blkmk_get_mdata, and must check that your
usage falls within the explicit template limits yourself.

View File

@ -9,3 +9,4 @@ if test -z "$srcdir"; then
fi fi
fi fi
autoreconf --force --install --verbose "$srcdir" autoreconf --force --install --verbose "$srcdir"
test -n "$NOCONFIGURE" || "$srcdir/configure" "$@"

101
base58.c
View File

@ -15,35 +15,112 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <libbase58.h>
#include <blkmaker.h> #include <blkmaker.h>
#include "private.h" #include "private.h"
static const int8_t b58digits[] = {
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1,
-1, 9,10,11,12,13,14,15, 16,-1,17,18,19,20,21,-1,
22,23,24,25,26,27,28,29, 30,31,32,-1,-1,-1,-1,-1,
-1,33,34,35,36,37,38,39, 40,41,42,43,-1,44,45,46,
47,48,49,50,51,52,53,54, 55,56,57,-1,-1,-1,-1,-1,
};
bool _blkmk_b58tobin(void *bin, size_t binsz, const char *b58, size_t b58sz) { bool _blkmk_b58tobin(void *bin, size_t binsz, const char *b58, size_t b58sz) {
return b58tobin(bin, &binsz, b58, b58sz); const unsigned char *b58u = (void*)b58;
unsigned char *binu = bin;
size_t outisz = (binsz + 3) / 4;
uint32_t outi[outisz];
uint64_t t;
uint32_t c;
size_t i, j;
uint8_t bytesleft = binsz % 4;
uint32_t zeromask = ~((1 << ((bytesleft ?: 4) * 8)) - 1);
if (!b58sz)
b58sz = strlen(b58);
memset(outi, 0, outisz * sizeof(*outi));
for (i = 0; i < b58sz; ++i)
{
if (b58u[i] & 0x80)
// High-bit set on invalid digit
return false;
if (b58digits[b58u[i]] == -1)
// Invalid base58 digit
return false;
c = b58digits[b58u[i]];
for (j = outisz; j--; )
{
t = ((uint64_t)outi[j]) * 58 + c;
c = (t & 0x3f00000000) >> 32;
outi[j] = t & 0xffffffff;
}
if (c)
// Output number too big (carry to the next int32)
return false;
if (outi[0] & zeromask)
// Output number too big (last int32 filled too far)
return false;
}
j = 0;
switch (bytesleft) {
case 3:
*(binu++) = (outi[0] & 0xff0000) >> 16;
case 2:
*(binu++) = (outi[0] & 0xff00) >> 8;
case 1:
*(binu++) = (outi[0] & 0xff);
++j;
default:
break;
}
for (; j < outisz; ++j)
{
*(binu++) = outi[j] >> 0x18;
*(binu++) = outi[j] >> 0x10;
*(binu++) = outi[j] >> 8;
*(binu++) = outi[j];
}
return true;
} }
int _blkmk_b58check(void *bin, size_t binsz, const char *base58str) { int _blkmk_b58check(void *bin, size_t binsz, const char *base58str) {
if (!b58_sha256_impl) unsigned char buf[32];
b58_sha256_impl = blkmk_sha256_impl; unsigned char *binc = bin;
return b58check(bin, binsz, base58str, 34); unsigned i;
if (binsz < 4)
return -4;
if (!_blkmk_dblsha256(buf, bin, binsz - 4))
return -2;
if (memcmp(&binc[binsz - 4], buf, 4))
return -1;
// Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str beyond the end)
for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i)
{} // Just finding the end of zeros, nothing to do in loop
if (binc[i] == '\0' || base58str[i] == '1')
return -3;
return binc[0];
} }
size_t blkmk_address_to_script(void *out, size_t outsz, const char *addr) { size_t blkmk_address_to_script(void *out, size_t outsz, const char *addr) {
unsigned char addrbin[25]; unsigned char addrbin[25];
unsigned char *cout = out; unsigned char *cout = out;
const size_t b58sz = strlen(addr);
int addrver; int addrver;
size_t rv; size_t rv;
rv = sizeof(addrbin); if (!_blkmk_b58tobin(addrbin, sizeof(addrbin), addr, 0))
if (!b58_sha256_impl)
b58_sha256_impl = blkmk_sha256_impl;
if (!b58tobin(addrbin, &rv, addr, b58sz))
return 0; return 0;
addrver = b58check(addrbin, sizeof(addrbin), addr, b58sz); addrver = _blkmk_b58check(addrbin, sizeof(addrbin), addr);
switch (addrver) { switch (addrver) {
case 0: // Bitcoin pubkey hash case 0: // Bitcoin pubkey hash
case 111: // Testnet pubkey hash case 111: // Testnet pubkey hash

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2016 Luke Dashjr * Copyright 2012 Luke Dashjr
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the standard MIT license. See COPYING for more details. * under the terms of the standard MIT license. See COPYING for more details.
@ -13,32 +13,11 @@
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#ifndef WIN32
#include <arpa/inet.h>
#else
#include <winsock2.h>
#endif
#include <blkmaker.h> #include <blkmaker.h>
#include <blktemplate.h> #include <blktemplate.h>
#include "private.h" #include "private.h"
const char *blkmk_supported_rules[] = {
"csv",
"segwit",
NULL
};
bool blkmk_supports_rule(const char * const rulename) {
for (const char **r = blkmk_supported_rules; *r; ++r) {
if (!strcmp(rulename, *r)) {
return true;
}
}
return false;
}
static inline static inline
void my_htole32(unsigned char *buf, uint32_t n) { void my_htole32(unsigned char *buf, uint32_t n) {
buf[0] = (n >> 0) % 256; buf[0] = (n >> 0) % 256;
@ -62,131 +41,22 @@ bool _blkmk_dblsha256(void *hash, const void *data, size_t datasz) {
#define dblsha256 _blkmk_dblsha256 #define dblsha256 _blkmk_dblsha256
static uint64_t blkmk_init_generation2(blktemplate_t *tmpl, void *script, size_t scriptsz, bool *out_newcb) {
size_t varintDecode(const uint8_t *p, size_t size, uint64_t *n) if (tmpl->cbtxn)
{
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 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;
if (tmpl->cbtxn && !(replace_existing && (tmpl->mutations & BMM_GENERATE)))
{ {
if (out_newcb)
*out_newcb = false;
return 0; return 0;
} }
if (!tmpl->has_cbvalue) { if (out_newcb)
// TODO: Figure it out from the existing cbtxn *out_newcb = true;
return 0;
}
if (scriptsz >= 0xfd) if (scriptsz >= 0xfd)
return 0; return 0;
unsigned char *data = malloc(168 + scriptsz); size_t datasz = 62 + sizeof(blkheight_t) + scriptsz;
unsigned char *data = malloc(datasz);
size_t off = 0; size_t off = 0;
if (!data) if (!data)
return 0; return 0;
@ -211,27 +81,6 @@ uint64_t blkmk_init_generation3(blktemplate_t * const tmpl, const void * const s
data[off++] = h; data[off++] = h;
data[42] = data[41] - 1; data[42] = data[41] - 1;
if (tmpl->aux_count)
{
unsigned auxsz = off++;
data[auxsz] = 0;
++data[41];
for (unsigned i = 0; i < tmpl->aux_count; ++i)
{
struct blkaux_t * const aux = &tmpl->auxs[i];
if ((size_t)data[41] + aux->datasz > libblkmaker_coinbase_size_limit)
{
free(data);
return 0;
}
memcpy(&data[off], tmpl->auxs[i].data, aux->datasz);
data[41] += aux->datasz;
data[auxsz] += aux->datasz;
off += aux->datasz;
}
}
memcpy(&data[off], memcpy(&data[off],
"\xff\xff\xff\xff" // sequence "\xff\xff\xff\xff" // sequence
"\x01" // output count "\x01" // output count
@ -240,162 +89,55 @@ uint64_t blkmk_init_generation3(blktemplate_t * const tmpl, const void * const s
my_htole64(&data[off], tmpl->cbvalue); my_htole64(&data[off], tmpl->cbvalue);
off += 8; off += 8;
data[off++] = scriptsz; data[off++] = scriptsz;
if (scriptsz) { memcpy(&data[off], script, scriptsz);
memcpy(&data[off], script, scriptsz); off += scriptsz;
off += scriptsz;
}
memset(&data[off], 0, 4); // lock time memset(&data[off], 0, 4); // lock time
off += 4; off += 4;
const unsigned long pretx_size = libblkmaker_blkheader_size + blkmk_varint_encode_size(1 + tmpl->txncount); struct blktxn_t *txn = calloc(1, sizeof(*tmpl->cbtxn));
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 = malloc(sizeof(*tmpl->cbtxn));
if (!txn) if (!txn)
{ {
free(data); free(data);
return 0; return 0;
} }
blktxn_init(txn);
txn->data = data; txn->data = data;
txn->datasz = off; txn->datasz = off;
txn->sigops_ = sigops_counted;
txn->weight = gentx_weight;
if (tmpl->cbtxn)
{
blktxn_clean(tmpl->cbtxn);
free(tmpl->cbtxn);
}
tmpl->cbtxn = txn; tmpl->cbtxn = txn;
tmpl->mutations |= BMM_CBAPPEND | BMM_CBSET | BMM_GENERATE; tmpl->mutations |= BMM_CBAPPEND | BMM_CBSET | BMM_GENERATE;
*inout_newcb = true;
return tmpl->cbvalue; return tmpl->cbvalue;
} }
uint64_t blkmk_init_generation2(blktemplate_t *tmpl, void *script, size_t scriptsz, bool *out_newcb) {
bool tmp;
if (!out_newcb)
out_newcb = &tmp;
*out_newcb = false;
return blkmk_init_generation3(tmpl, script, scriptsz, out_newcb);
}
uint64_t blkmk_init_generation(blktemplate_t *tmpl, void *script, size_t scriptsz) { uint64_t blkmk_init_generation(blktemplate_t *tmpl, void *script, size_t scriptsz) {
return blkmk_init_generation2(tmpl, script, scriptsz, NULL); return blkmk_init_generation2(tmpl, script, scriptsz, NULL);
} }
static
bool blkmk_hash_transactions(blktemplate_t * const tmpl)
{
for (unsigned long i = 0; i < tmpl->txncount; ++i)
{
struct blktxn_t * const txn = &tmpl->txns[i];
if (txn->hash_)
continue;
txn->hash_ = malloc(sizeof(*txn->hash_));
if (!dblsha256(txn->hash_, txn->data, txn->datasz))
{
free(txn->hash_);
return false;
}
}
return true;
}
static
bool blkmk_build_merkle_branches(blktemplate_t * const tmpl)
{
int branchcount, i;
libblkmaker_hash_t *branches;
if (tmpl->_mrklbranch)
return true;
if (!blkmk_hash_transactions(tmpl))
return false;
branchcount = blkmk_flsl(tmpl->txncount);
if (!branchcount)
{
tmpl->_mrklbranchcount = 0;
tmpl->_mrklbranch = NULL;
return true;
}
branches = malloc(branchcount * sizeof(*branches));
if (!branches) {
return false;
}
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) {
free(branches);
return false;
}
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));
}
for (i = 0; i < branchcount; ++i)
{
memcpy(&branches[i], &hashes[1], sizeof(*hashes));
if (hashcount % 2)
{
memcpy(&hashes[hashcount], &hashes[hashcount - 1], sizeof(*hashes));
++hashcount;
}
for (size_t i = 2; i < hashcount; i += 2)
// This is where we overlap input and output, on the first pair
if (!dblsha256(&hashes[i / 2], &hashes[i], sizeof(*hashes) * 2))
{
free(branches);
free(hashes);
return false;
}
hashcount /= 2;
}
free(hashes);
tmpl->_mrklbranch = branches;
tmpl->_mrklbranchcount = branchcount;
return true;
}
static static
bool build_merkle_root(unsigned char *mrklroot_out, blktemplate_t *tmpl, unsigned char *cbtxndata, size_t cbtxndatasz) { bool build_merkle_root(unsigned char *mrklroot_out, blktemplate_t *tmpl, unsigned char *cbtxndata, size_t cbtxndatasz) {
int i; size_t hashcount = tmpl->txncount + 1;
libblkmaker_hash_t hashes[0x40]; unsigned char hashes[(hashcount + 1) * 32];
if (!blkmk_build_merkle_branches(tmpl))
return false;
if (!dblsha256(&hashes[0], cbtxndata, cbtxndatasz)) if (!dblsha256(&hashes[0], cbtxndata, cbtxndatasz))
return false; return false;
for (unsigned long i = 0; i < tmpl->txncount; ++i)
for (i = 0; i < tmpl->_mrklbranchcount; ++i) if (!dblsha256(&hashes[32 * (i + 1)], tmpl->txns[i].data, tmpl->txns[i].datasz))
{
memcpy(&hashes[1], tmpl->_mrklbranch[i], 0x20);
// This is where we overlap input and output, on the first pair
if (!dblsha256(&hashes[0], &hashes[0], 0x40))
return false; return false;
while (hashcount > 1)
{
if (hashcount % 2)
{
memcpy(&hashes[32 * hashcount], &hashes[32 * (hashcount - 1)], 32);
++hashcount;
}
for (size_t i = 0; i < hashcount; i += 2)
// This is where we overlap input and output, on the first pair
if (!dblsha256(&hashes[i / 2 * 32], &hashes[32 * i], 64))
return false;
hashcount /= 2;
} }
memcpy(mrklroot_out, &hashes[0], 32); memcpy(mrklroot_out, &hashes[0], 32);
@ -403,101 +145,18 @@ bool build_merkle_root(unsigned char *mrklroot_out, blktemplate_t *tmpl, unsigne
return true; 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 const int cbScriptSigLen = 4 + 1 + 36;
static 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 *tmpl, void *vout, const void *append, size_t appendsz) {
unsigned char *out = vout; unsigned char *out = vout;
unsigned char *in = tmpl->cbtxn->data; unsigned char *in = tmpl->cbtxn->data;
size_t insz = tmpl->cbtxn->datasz; size_t insz = tmpl->cbtxn->datasz;
if (appendsz > libblkmaker_coinbase_size_limit || in[cbScriptSigLen] > libblkmaker_coinbase_size_limit - appendsz) { if (in[cbScriptSigLen] > 100 - appendsz)
return false; return false;
}
const unsigned long pretx_size = libblkmaker_blkheader_size + blkmk_varint_encode_size(1 + tmpl->txncount);
if (pretx_size + tmpl->cbtxn->datasz + tmpl->txns_datasz + appendsz > tmpl->sizelimit) {
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]; int cbPostScriptSig = cbScriptSigLen + 1 + in[cbScriptSigLen];
if (appended_at_offset)
*appended_at_offset = cbPostScriptSig;
unsigned char *outPostScriptSig = &out[cbPostScriptSig]; unsigned char *outPostScriptSig = &out[cbPostScriptSig];
void *outExtranonce = (void*)outPostScriptSig; void *outExtranonce = (void*)outPostScriptSig;
outPostScriptSig += appendsz; outPostScriptSig += appendsz;
@ -513,66 +172,15 @@ bool _blkmk_append_cb(blktemplate_t * const tmpl, void * const vout, const void
out[cbScriptSigLen] += appendsz; out[cbScriptSigLen] += appendsz;
memcpy(outExtranonce, append, 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; return true;
} }
ssize_t blkmk_append_coinbase_safe2(blktemplate_t * const tmpl, const void * const append, const size_t appendsz, int extranoncesz, const bool merkle_only) ssize_t blkmk_append_coinbase_safe(blktemplate_t *tmpl, const void *append, size_t appendsz) {
{
if (!(tmpl->mutations & (BMM_CBAPPEND | BMM_CBSET))) if (!(tmpl->mutations & (BMM_CBAPPEND | BMM_CBSET)))
return -1; return -1;
size_t datasz = tmpl->cbtxn->datasz; size_t datasz = tmpl->cbtxn->datasz;
if (extranoncesz == sizeof(unsigned int)) { size_t availsz = 100 - sizeof(unsigned int) - tmpl->cbtxn->data[cbScriptSigLen];
++extranoncesz;
} else
if (!merkle_only)
{
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;
}
size_t availsz = libblkmaker_coinbase_size_limit - extranoncesz - tmpl->cbtxn->data[cbScriptSigLen];
{
const unsigned long pretx_size = libblkmaker_blkheader_size + blkmk_varint_encode_size(1 + tmpl->txncount);
const size_t current_blocksize = pretx_size + tmpl->cbtxn->datasz + tmpl->txns_datasz;
if (current_blocksize > tmpl->sizelimit) {
return -4;
}
const size_t availsz2 = tmpl->sizelimit - current_blocksize;
if (availsz2 < availsz) {
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) if (appendsz > availsz)
return availsz; return availsz;
@ -581,18 +189,13 @@ ssize_t blkmk_append_coinbase_safe2(blktemplate_t * const tmpl, const void * con
return -2; return -2;
tmpl->cbtxn->data = newp; tmpl->cbtxn->data = newp;
if (!_blkmk_append_cb(tmpl, newp, append, appendsz, NULL, &tmpl->cbtxn->sigops_)) if (!_blkmk_append_cb(tmpl, newp, append, appendsz))
return -3; return -3;
tmpl->cbtxn->datasz += appendsz; tmpl->cbtxn->datasz += appendsz;
tmpl->cbtxn->weight += appendsz * 4;
return availsz; return availsz;
} }
ssize_t blkmk_append_coinbase_safe(blktemplate_t * const tmpl, const void * const append, const size_t appendsz) {
return blkmk_append_coinbase_safe2(tmpl, append, appendsz, 0, false);
}
bool _blkmk_extranonce(blktemplate_t *tmpl, void *vout, unsigned int workid, size_t *offs) { bool _blkmk_extranonce(blktemplate_t *tmpl, void *vout, unsigned int workid, size_t *offs) {
unsigned char *in = tmpl->cbtxn->data; unsigned char *in = tmpl->cbtxn->data;
size_t insz = tmpl->cbtxn->datasz; size_t insz = tmpl->cbtxn->datasz;
@ -604,7 +207,7 @@ bool _blkmk_extranonce(blktemplate_t *tmpl, void *vout, unsigned int workid, siz
return true; return true;
} }
if (!_blkmk_append_cb(tmpl, vout, &workid, sizeof(workid), NULL, NULL)) if (!_blkmk_append_cb(tmpl, vout, &workid, sizeof(workid)))
return false; return false;
*offs += insz + sizeof(workid); *offs += insz + sizeof(workid);
@ -612,197 +215,38 @@ bool _blkmk_extranonce(blktemplate_t *tmpl, void *vout, unsigned int workid, siz
return true; 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)
{
double time_passed = difftime(usetime, tmpl->_time_rcvd);
blktime_t timehdr = tmpl->curtime + time_passed;
if (timehdr > tmpl->maxtime)
timehdr = tmpl->maxtime;
my_htole32(out_hdrbuf, timehdr);
if (out_expire)
{
*out_expire = tmpl->expires - time_passed - 1;
if (can_roll_ntime)
{
// If the caller can roll the time header, we need to expire before reaching the maxtime
int16_t maxtime_expire_limit = (tmpl->maxtime - timehdr) + 1;
if (*out_expire > maxtime_expire_limit)
*out_expire = maxtime_expire_limit;
}
}
}
bool blkmk_sample_data_(blktemplate_t * const tmpl, uint8_t * const cbuf, const unsigned int dataid) {
my_htole32(&cbuf[0], tmpl->version);
memcpy(&cbuf[4], &tmpl->prevblk, 32);
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;
my_htole32(&cbuf[0x44], tmpl->curtime);
memcpy(&cbuf[72], &tmpl->diffbits, 4);
return true;
}
size_t blkmk_get_data(blktemplate_t *tmpl, void *buf, size_t bufsz, time_t usetime, int16_t *out_expire, unsigned int *out_dataid) { size_t blkmk_get_data(blktemplate_t *tmpl, void *buf, size_t bufsz, time_t usetime, int16_t *out_expire, unsigned int *out_dataid) {
if (!(blkmk_time_left(tmpl, usetime) && blkmk_work_left(tmpl) && tmpl->cbtxn)) if (!(blkmk_time_left(tmpl, usetime) && blkmk_work_left(tmpl) && tmpl->cbtxn))
return 0; return 0;
if (bufsz < 76) if (bufsz < 76)
return 76; return 76;
if (tmpl->cbtxn->datasz > cbScriptSigLen && tmpl->cbtxn->data[cbScriptSigLen] + sizeof(*out_dataid) < libblkmaker_coinbase_size_minimum) {
// Add some padding
const size_t padding_required = libblkmaker_coinbase_size_minimum - (tmpl->cbtxn->data[cbScriptSigLen] + sizeof(*out_dataid));
uint8_t padding[padding_required];
static const uint8_t opcode_nop = '\x61';
memset(padding, opcode_nop, padding_required);
if (padding_required != blkmk_append_coinbase_safe2(tmpl, padding, padding_required, 0, false)) {
return 0;
}
}
unsigned char *cbuf = buf;
*out_dataid = tmpl->next_dataid++;
if (!blkmk_sample_data_(tmpl, cbuf, *out_dataid))
return 0;
blkmk_set_times(tmpl, &cbuf[68], usetime, out_expire, false);
return 76;
}
bool blkmk_get_mdata(blktemplate_t * const tmpl, void * const buf, const size_t bufsz, const time_t usetime, int16_t * const out_expire, void * const _out_cbtxn, size_t * const out_cbtxnsz, size_t * const cbextranonceoffset, int * const out_branchcount, void * const _out_branches, size_t extranoncesz, const bool can_roll_ntime)
{
if (!(true
&& blkmk_time_left(tmpl, usetime)
&& tmpl->cbtxn
&& blkmk_build_merkle_branches(tmpl)
&& bufsz >= 76
&& (tmpl->mutations & (BMM_CBAPPEND | BMM_CBSET))
))
return false;
if (extranoncesz == sizeof(unsigned int))
// Avoid overlapping with blkmk_get_data use
++extranoncesz;
if (tmpl->cbtxn->datasz > cbScriptSigLen && tmpl->cbtxn->data[cbScriptSigLen] + extranoncesz < libblkmaker_coinbase_size_minimum) {
extranoncesz = libblkmaker_coinbase_size_minimum - tmpl->cbtxn->data[cbScriptSigLen];
}
void ** const out_branches = _out_branches;
void ** const out_cbtxn = _out_cbtxn;
unsigned char *cbuf = buf; unsigned char *cbuf = buf;
my_htole32(&cbuf[0], tmpl->version); my_htole32(&cbuf[0], tmpl->version);
memcpy(&cbuf[4], &tmpl->prevblk, 32); memcpy(&cbuf[4], &tmpl->prevblk, 32);
*out_cbtxnsz = tmpl->cbtxn->datasz + extranoncesz; unsigned char cbtxndata[tmpl->cbtxn->datasz + sizeof(*out_dataid)];
*out_cbtxn = malloc(*out_cbtxnsz + max_witness_commitment_insert); size_t cbtxndatasz = 0;
if (!*out_cbtxn) *out_dataid = tmpl->next_dataid++;
return false; if (!_blkmk_extranonce(tmpl, cbtxndata, *out_dataid, &cbtxndatasz))
unsigned char dummy[extranoncesz]; return 0;
memset(dummy, 0, extranoncesz); if (!build_merkle_root(&cbuf[36], tmpl, cbtxndata, cbtxndatasz))
if (!_blkmk_append_cb(tmpl, *out_cbtxn, dummy, extranoncesz, cbextranonceoffset, NULL)) return 0;
{
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); double time_passed = difftime(usetime, tmpl->_time_rcvd);
blktime_t timehdr = tmpl->curtime + time_passed;
if (timehdr > tmpl->maxtime)
timehdr = tmpl->maxtime;
my_htole32(&cbuf[68], timehdr);
memcpy(&cbuf[72], &tmpl->diffbits, 4); memcpy(&cbuf[72], &tmpl->diffbits, 4);
if (out_expire)
*out_expire = tmpl->expires - time_passed - 1;
*out_branchcount = tmpl->_mrklbranchcount; // TEMPORARY HACK:
const size_t branches_bytesz = (sizeof(libblkmaker_hash_t) * tmpl->_mrklbranchcount); memcpy(tmpl->_mrklroot, &cbuf[36], 32);
*out_branches = malloc(branches_bytesz);
if (!*out_branches)
{
free(*out_cbtxn);
return false;
}
if (branches_bytesz) {
memcpy(*out_branches, tmpl->_mrklbranch, branches_bytesz);
}
return true; return 76;
} }
blktime_diff_t blkmk_time_left(const blktemplate_t *tmpl, time_t nowtime) { blktime_diff_t blkmk_time_left(const blktemplate_t *tmpl, time_t nowtime) {
@ -816,87 +260,7 @@ unsigned long blkmk_work_left(const blktemplate_t *tmpl) {
if (!tmpl->version) if (!tmpl->version)
return 0; return 0;
if (!(tmpl->mutations & (BMM_CBAPPEND | BMM_CBSET))) if (!(tmpl->mutations & (BMM_CBAPPEND | BMM_CBSET)))
return (tmpl->next_dataid) ? 0 : 1; return 1;
return UINT_MAX - tmpl->next_dataid; return UINT_MAX - tmpl->next_dataid;
} return BLKMK_UNLIMITED_WORK_COUNT;
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)));
const bool incl_alltxn = (foreign || !(tmpl->mutations & BMAb_COINBASE));
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;
if (incl_alltxn) {
blkbuf_sz += tmpl->txns_datasz;
}
}
unsigned char * const blk = malloc(blkbuf_sz);
if (!blk) {
return NULL;
}
const size_t header_before_nonce_sz = libblkmaker_blkheader_size - sizeof(nonce);
memcpy(blk, data, header_before_nonce_sz);
nonce = htonl(nonce);
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, NULL)) {
free(blk);
return NULL;
}
cbtxnlen += tmpl->cbtxn->datasz + extranoncesz;
} else {
memcpy(&blk[offs], tmpl->cbtxn->data, 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)
{
memcpy(&blk[offs], tmpl->txns[i].data, tmpl->txns[i].datasz);
offs += tmpl->txns[i].datasz;
}
}
}
char *blkhex = malloc((offs * 2) + 1);
_blkmk_bin2hex(blkhex, blk, offs);
free(blk);
return blkhex;
}
char *blkmk_assemble_submission2_(blktemplate_t * const tmpl, const unsigned char * const data, const void *extranonce, size_t extranoncesz, const unsigned int dataid, const blknonce_t nonce, const bool foreign)
{
if (dataid) {
if (extranoncesz) {
// Cannot specify both!
return NULL;
}
extranonce = &dataid;
extranoncesz = sizeof(dataid);
} else if (extranoncesz == sizeof(unsigned int)) {
// Avoid overlapping with blkmk_get_data use
unsigned char extended_extranonce[extranoncesz + 1];
memcpy(extended_extranonce, extranonce, extranoncesz);
extended_extranonce[extranoncesz] = 0;
return blkmk_assemble_submission2_internal(tmpl, data, extended_extranonce, extranoncesz + 1, nonce, foreign);
}
return blkmk_assemble_submission2_internal(tmpl, data, extranonce, extranoncesz, nonce, foreign);
} }

View File

@ -7,35 +7,20 @@
#include <blktemplate.h> #include <blktemplate.h>
#ifdef __cplusplus #define BLKMAKER_VERSION (4L)
extern "C" { #define BLKMAKER_MAX_BLOCK_VERSION (2)
#endif
#define BLKMAKER_VERSION (8L)
#define BLKMAKER_MAX_BLOCK_VERSION (0x3fffffff)
#define BLKMAKER_MAX_PRERULES_BLOCK_VERSION (4)
extern const char *blkmk_supported_rules[];
extern bool blkmk_supports_rule(const char *rulename);
extern bool (*blkmk_sha256_impl)(void *hash_out, const void *data, size_t datasz); extern bool (*blkmk_sha256_impl)(void *hash_out, const void *data, size_t datasz);
extern uint64_t blkmk_init_generation(blktemplate_t *, void *script, size_t scriptsz); extern uint64_t blkmk_init_generation(blktemplate_t *, void *script, size_t scriptsz);
extern uint64_t blkmk_init_generation2(blktemplate_t *, void *script, size_t scriptsz, bool *out_newcb); extern uint64_t blkmk_init_generation2(blktemplate_t *, void *script, size_t scriptsz, bool *out_newcb);
extern uint64_t blkmk_init_generation3(blktemplate_t *, const void *script, size_t scriptsz, bool *inout_newcb);
extern ssize_t blkmk_append_coinbase_safe(blktemplate_t *, const void *append, size_t appendsz); extern ssize_t blkmk_append_coinbase_safe(blktemplate_t *, const void *append, size_t appendsz);
extern ssize_t blkmk_append_coinbase_safe2(blktemplate_t *, const void *append, size_t appendsz, int extranoncesz, bool merkle_only);
extern bool _blkmk_extranonce(blktemplate_t *tmpl, void *vout, unsigned int workid, size_t *offs); extern bool _blkmk_extranonce(blktemplate_t *tmpl, void *vout, unsigned int workid, size_t *offs);
extern size_t blkmk_get_data(blktemplate_t *, void *buf, size_t bufsz, time_t usetime, int16_t *out_expire, unsigned int *out_dataid); extern size_t blkmk_get_data(blktemplate_t *, void *buf, size_t bufsz, time_t usetime, int16_t *out_expire, unsigned int *out_dataid);
extern bool blkmk_get_mdata(blktemplate_t *, void *buf, size_t bufsz, time_t usetime, int16_t *out_expire, void *out_cbtxn, size_t *out_cbtxnsz, size_t *cbextranonceoffset, int *out_branchcount, void *out_branches, size_t extranoncesz, bool can_roll_ntime);
extern blktime_diff_t blkmk_time_left(const blktemplate_t *, time_t nowtime); extern blktime_diff_t blkmk_time_left(const blktemplate_t *, time_t nowtime);
extern unsigned long blkmk_work_left(const blktemplate_t *); extern unsigned long blkmk_work_left(const blktemplate_t *);
#define BLKMK_UNLIMITED_WORK_COUNT ULONG_MAX #define BLKMK_UNLIMITED_WORK_COUNT ULONG_MAX
extern size_t blkmk_address_to_script(void *out, size_t outsz, const char *addr); extern size_t blkmk_address_to_script(void *out, size_t outsz, const char *addr);
#ifdef __cplusplus
}
#endif
#endif #endif

View File

@ -1,18 +1,21 @@
/* /*
* Copyright 2012-2016 Luke Dashjr * Copyright 2012-2014 Luke Dashjr
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the standard MIT license. See COPYING for more details. * under the terms of the standard MIT license. See COPYING for more details.
*/ */
#define _BSD_SOURCE #define _BSD_SOURCE
#define _DEFAULT_SOURCE
#include <limits.h>
#include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifndef WIN32
#include <arpa/inet.h>
#else
#include <winsock2.h>
#endif
#include <jansson.h> #include <jansson.h>
#include <blkmaker.h> #include <blkmaker.h>
@ -24,7 +27,7 @@
# error "Jansson 2.0 with long long support required!" # error "Jansson 2.0 with long long support required!"
#endif #endif
json_t *blktmpl_request_jansson2(const uint32_t caps, const char * const lpid, const char * const * const rulelist) { json_t *blktmpl_request_jansson(gbt_capabilities_t caps, const char *lpid) {
json_t *req, *jcaps, *jstr, *reqf, *reqa; json_t *req, *jcaps, *jstr, *reqf, *reqa;
if (!(req = json_object())) if (!(req = json_object()))
return NULL; return NULL;
@ -63,26 +66,6 @@ json_t *blktmpl_request_jansson2(const uint32_t caps, const char * const lpid, c
if (json_object_set_new(req, "longpollid", jstr)) if (json_object_set_new(req, "longpollid", jstr))
goto err; goto err;
} }
jstr = NULL;
// Add rules list
if (!(jcaps = json_array())) {
goto err;
}
for (const char * const *currule = rulelist; *currule; ++currule) {
if (!(jstr = json_string(*currule))) {
goto err;
}
if (json_array_append_new(jcaps, jstr)) {
goto err;
}
}
jstr = NULL;
if (json_object_set_new(req, "rules", jcaps))
goto err;
jcaps = NULL;
// Put together main JSON-RPC request Object
if (!(jstr = json_string("getblocktemplate"))) if (!(jstr = json_string("getblocktemplate")))
goto err; goto err;
if (json_object_set_new(reqf, "method", jstr)) if (json_object_set_new(reqf, "method", jstr))
@ -105,10 +88,6 @@ err:
return NULL; return NULL;
} }
json_t *blktmpl_request_jansson(const uint32_t caps, const char * const lpid) {
return blktmpl_request_jansson2(caps, lpid, blkmk_supported_rules);
}
#define my_hex2bin _blkmk_hex2bin #define my_hex2bin _blkmk_hex2bin
@ -125,49 +104,17 @@ json_t *blktmpl_request_jansson(const uint32_t caps, const char * const lpid) {
return "Error decoding '" #key "'"; \ return "Error decoding '" #key "'"; \
} while(0) } while(0)
#define GETNUM(key, type) do { \ #define GETNUM(key) do { \
GET(key, number); \ GET(key, number); \
const double tmpd = json_number_value(v); \ tmpl->key = json_integer_value(v); \
const type tmp = tmpd; \
if (tmpd != tmp) { \
return "Invalid number value for '" #key "'"; \
} \
tmpl->key = tmp; \
} while(0) } while(0)
#define GETNUM_T(key, type) do { \ #define GETNUM_O2(key, skey) do { \
GET(key, number); \ if ((v = json_object_get(json, #skey)) && json_is_number(v)) \
const double tmpd = json_number_value(v); \ tmpl->key = json_integer_value(v); \
const type tmp = tmpd; \
/* This checks if it's merely being truncated, and tolerates it */ \
if (tmpd != tmp && !((tmpd < 0) ? (tmpd < tmp && tmpd + 1 > tmp) : (tmpd > tmp && tmpd - 1 < tmp))) { \
return "Invalid number value for '" #key "'"; \
} \
tmpl->key = tmp; \
} while(0) } while(0)
#define GETNUM_O2(key, skey, type) do { \ #define GETNUM_O(key) GETNUM_O2(key, key)
if ((v = json_object_get(json, #skey)) && json_is_number(v)) { \
const double tmpd = json_number_value(v); \
const type tmp = tmpd; \
if (tmpd == tmp) { \
tmpl->key = tmp; \
} \
} \
} while(0)
#define GETNUM_O(key, type) GETNUM_O2(key, key, type)
#define GETNUM_OT(key, type) do { \
if ((v = json_object_get(json, #key)) && json_is_number(v)) { \
const double tmpd = json_number_value(v); \
const type tmp = tmpd; \
/* This checks if it's merely being truncated, and tolerates it */ \
if (tmpd == tmp || ((tmpd < 0) ? (tmpd < tmp && tmpd + 1 > tmp) : (tmpd > tmp && tmpd - 1 < tmp))) { \
tmpl->key = tmp; \
} \
} \
} while(0)
#define GETSTR(key, skey) do { \ #define GETSTR(key, skey) do { \
if ((v = json_object_get(json, #key)) && json_is_string(v)) \ if ((v = json_object_get(json, #key)) && json_is_string(v)) \
@ -183,14 +130,10 @@ json_t *blktmpl_request_jansson(const uint32_t caps, const char * const lpid) {
tmpl->skey = true; \ tmpl->skey = true; \
} while(0) } while(0)
static void my_flip(void *, size_t);
static 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; json_t *vv;
blktxn_init(txn);
if (!((vv = json_object_get(txnj, "data")) && json_is_string(vv))) if (!((vv = json_object_get(txnj, "data")) && json_is_string(vv)))
return "Missing or invalid type for transaction data"; return "Missing or invalid type for transaction data";
const char *hexdata = json_string_value(vv); const char *hexdata = json_string_value(vv);
@ -203,90 +146,15 @@ const char *parse_txn(struct blktxn_t *txn, json_t *txnj, size_t my_tx_index) {
if ((vv = json_object_get(txnj, "hash")) && json_is_string(vv)) if ((vv = json_object_get(txnj, "hash")) && json_is_string(vv))
{ {
hexdata = json_string_value(vv); hexdata = json_string_value(vv);
txn->hash_ = malloc(sizeof(*txn->hash_)); txn->hash = malloc(sizeof(*txn->hash));
if (!my_hex2bin(*txn->hash_, hexdata, sizeof(*txn->hash_))) if (!my_hex2bin(*txn->hash, hexdata, sizeof(*txn->hash)))
{ {
free(txn->hash_); free(txn->hash);
txn->hash_ = NULL; txn->hash = NULL;
}
else
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; // TODO: dependcount/depends, fee, required, sigops
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; return NULL;
} }
@ -322,14 +190,39 @@ const char *blktmpl_add_jansson(blktemplate_t *tmpl, const json_t *json, time_t
GETHEX(bits, diffbits); GETHEX(bits, diffbits);
my_flip(tmpl->diffbits, 4); my_flip(tmpl->diffbits, 4);
GETNUM_T(curtime, blktime_t); GETNUM(curtime);
GETNUM(height, blkheight_t); GETNUM(height);
GETHEX(previousblockhash, prevblk); GETHEX(previousblockhash, prevblk);
my_flip(tmpl->prevblk, 32); my_flip(tmpl->prevblk, 32);
GETNUM_O(sigoplimit, unsigned short); GETNUM_O(sigoplimit);
GETNUM_O(sizelimit, unsigned long); GETNUM_O(sizelimit);
GETNUM_O(weightlimit, int64_t); GETNUM(version);
GETNUM(version, uint32_t);
GETNUM_O2(cbvalue, coinbasevalue);
GETSTR(workid, workid);
GETNUM_O(expires);
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));
for (size_t i = 0; i < txns; ++i)
if ((s = parse_txn(&tmpl->txns[i], json_array_get(v, i))))
return s;
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;
}
// TODO: coinbaseaux
if ((v = json_object_get(json, "mutable")) && json_is_array(v)) if ((v = json_object_get(json, "mutable")) && json_is_array(v))
{ {
@ -342,230 +235,80 @@ const char *blktmpl_add_jansson(blktemplate_t *tmpl, const json_t *json, time_t
} }
} }
if ((tmpl->version & 0xe0000000) == 0x20000000 && (v = json_object_get(json, "vbavailable")) && json_is_object(v) && (v = json_object_get(json, "rules")) && json_is_array(v)) { if (tmpl->version > 2 || (tmpl->version == 2 && !tmpl->height))
// calloc so that a failure doesn't result in freeing a random pointer
size_t n = json_array_size(v);
tmpl->rules = calloc(n + 1, sizeof(*tmpl->rules));
for (size_t i = 0; i < n; ++i) {
v2 = json_array_get(v, i);
if (!json_is_string(v2)) {
return "Non-String data in template rules list";
}
s = json_string_value(v2);
if (s[0] == '!') {
++s;
if (!blkmk_supports_rule(s)) {
return "Unsupported rule strictly required by template";
}
} else {
if (!blkmk_supports_rule(s)) {
tmpl->unsupported_rule = true;
}
}
tmpl->rules[i] = strdup(s);
if (!tmpl->rules[i]) {
return "Memory allocation error parsing rules";
}
if (!strcmp(s, "segwit")) {
tmpl->_bip141_sigops = true;
}
}
v = json_object_get(json, "vbavailable");
n = json_object_size(v);
tmpl->vbavailable = calloc(n + 1, sizeof(*tmpl->vbavailable));
struct blktmpl_vbassoc **cur_vbassoc = tmpl->vbavailable;
for (void *iter = json_object_iter(v); iter; (iter = json_object_iter_next(v, iter)), ++cur_vbassoc) {
v2 = json_object_iter_value(iter);
if (!json_is_number(v2)) {
return "Invalid type for vbavailable bit";
}
double bitnum = json_number_value(v2);
if (bitnum < 0 || bitnum > 28 || (unsigned)bitnum != bitnum) {
return "Invalid bit number in vbavailable";
}
*cur_vbassoc = malloc(sizeof(**cur_vbassoc));
if (!*cur_vbassoc) {
return "Memory allocation error for struct blktmpl_vbassoc";
}
**cur_vbassoc = (struct blktmpl_vbassoc){
.name = strdup(json_object_iter_key(iter)),
.bitnum = bitnum,
};
if (!(*cur_vbassoc)->name) {
return "Memory allocation error for vbavailable name";
}
}
v = json_object_get(json, "vbrequired");
if (v && json_is_number(v)) {
double tmpd = json_number_value(v);
tmpl->vbrequired = tmpd;
if (tmpl->vbrequired != tmpd) {
return "Unparsable vbrequired";
}
}
}
else
if (tmpl->version > BLKMAKER_MAX_PRERULES_BLOCK_VERSION || (tmpl->version >= 2 && !tmpl->height))
{ {
if (tmpl->mutations & BMM_VERDROP) if (tmpl->mutations & BMM_VERDROP)
tmpl->version = tmpl->height ? BLKMAKER_MAX_PRERULES_BLOCK_VERSION : 1; tmpl->version = tmpl->height ? 2 : 1;
else else
if (!(tmpl->mutations & BMM_VERFORCE)) if (!(tmpl->mutations & BMM_VERFORCE))
return "Unrecognized block version, and not allowed to reduce or force it"; 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; tmpl->_time_rcvd = time_rcvd;
return NULL; return NULL;
} }
json_t *blktmpl_propose_jansson(blktemplate_t * const tmpl, const uint32_t caps, const bool foreign) { static
json_t *jreq = blktmpl_request_jansson(caps, NULL), *ja = NULL, *jparams; char varintEncode(unsigned char *out, uint64_t n) {
if (!(jreq && json_is_object(jreq))) if (n < 0xfd)
goto err;
jparams = json_array_get(json_object_get(jreq, "params"), 0);
if (!(jparams && json_is_object(jparams)))
goto err;
if (!(ja = json_string("proposal")))
goto err;
if (json_object_set_new(jparams, "mode", ja))
goto err;
if (tmpl->workid && !foreign)
{ {
if (!(ja = json_string(tmpl->workid))) out[0] = n;
goto err; return 1;
if (json_object_set_new(jparams, "workid", ja))
goto err;
} }
ja = NULL; char L;
if (n <= 0xffff)
unsigned int dataid = (tmpl->mutations & (BMM_CBAPPEND | BMM_CBSET) ? 1 : 0); {
out[0] = '\xfd';
uint8_t sdata[0x4c]; L = 3;
if (!blkmk_sample_data_(tmpl, sdata, dataid)) }
goto err; else
char *blkhex = blkmk_assemble_submission2_(tmpl, sdata, NULL, 0, dataid, 0, foreign); if (n <= 0xffffffff)
if (!blkhex) {
goto err; out[0] = '\xfe';
if (!(ja = json_string(blkhex))) L = 5;
goto err; }
free(blkhex); else
if (json_object_set_new(jparams, "data", ja)) {
goto err; out[0] = '\xff';
L = 9;
return jreq; }
for (unsigned char i = 1; i < L; ++i)
err: out[i] = (n >> ((i - 1) * 8)) % 256;
if (jreq) json_decref(jreq); return L;
if (ja) json_decref(ja);
return NULL;
} }
#define my_bin2hex _blkmk_bin2hex
static static
json_t *_blkmk_submit_jansson(blktemplate_t *tmpl, const unsigned char *data, const void * const extranonce, const size_t extranoncesz, unsigned int dataid, blknonce_t nonce, bool foreign) { json_t *_blkmk_submit_jansson(blktemplate_t *tmpl, const unsigned char *data, unsigned int dataid, blknonce_t nonce, bool foreign) {
char *blkhex = blkmk_assemble_submission2_(tmpl, data, extranonce, extranoncesz, dataid, nonce, foreign); unsigned char blk[80 + 8 + 1000000];
if (!blkhex) memcpy(blk, data, 76);
return NULL; nonce = htonl(nonce);
memcpy(&blk[76], &nonce, 4);
size_t offs = 80;
if (foreign || (!(tmpl->mutations & BMAb_TRUNCATE && !dataid)))
{
offs += varintEncode(&blk[offs], 1 + tmpl->txncount);
if (!_blkmk_extranonce(tmpl, &blk[offs], dataid, &offs))
return NULL;
if (foreign || !(tmpl->mutations & BMAb_COINBASE))
for (unsigned long i = 0; i < tmpl->txncount; ++i)
{
memcpy(&blk[offs], tmpl->txns[i].data, tmpl->txns[i].datasz);
offs += tmpl->txns[i].datasz;
}
}
char blkhex[(offs * 2) + 1];
my_bin2hex(blkhex, blk, offs);
json_t *rv = json_array(), *ja, *jb; json_t *rv = json_array(), *ja, *jb;
jb = NULL; jb = NULL;
ja = json_string(blkhex); if (!(ja = json_string(blkhex)))
free(blkhex);
if (!ja)
goto err; goto err;
if (json_array_append_new(rv, ja)) if (json_array_append_new(rv, ja))
goto err; goto err;
@ -606,13 +349,9 @@ err:
} }
json_t *blkmk_submit_jansson(blktemplate_t *tmpl, const unsigned char *data, unsigned int dataid, blknonce_t nonce) { json_t *blkmk_submit_jansson(blktemplate_t *tmpl, const unsigned char *data, unsigned int dataid, blknonce_t nonce) {
return _blkmk_submit_jansson(tmpl, data, NULL, 0, dataid, nonce, false); return _blkmk_submit_jansson(tmpl, data, dataid, nonce, false);
} }
json_t *blkmk_submit_foreign_jansson(blktemplate_t *tmpl, const unsigned char *data, unsigned int dataid, blknonce_t nonce) { json_t *blkmk_submit_foreign_jansson(blktemplate_t *tmpl, const unsigned char *data, unsigned int dataid, blknonce_t nonce) {
return _blkmk_submit_jansson(tmpl, data, NULL, 0, dataid, nonce, true); return _blkmk_submit_jansson(tmpl, data, dataid, nonce, true);
}
json_t *blkmk_submitm_jansson(blktemplate_t * const tmpl, const unsigned char *data, const void * const extranonce, const size_t extranoncesz, const blknonce_t nonce, const bool foreign) {
return _blkmk_submit_jansson(tmpl, data, extranonce, extranoncesz, 0, nonce, foreign);
} }

View File

@ -5,20 +5,9 @@
#include <blktemplate.h> #include <blktemplate.h>
#ifdef __cplusplus extern json_t *blktmpl_request_jansson(gbt_capabilities_t extracaps, const char *lpid);
extern "C" {
#endif
extern json_t *blktmpl_request_jansson(uint32_t extracaps, const char *lpid);
extern json_t *blktmpl_request_jansson2(uint32_t extracaps, const char *lpid, const char * const *rulelist);
extern const char *blktmpl_add_jansson(blktemplate_t *, const json_t *, time_t time_rcvd); extern const char *blktmpl_add_jansson(blktemplate_t *, const json_t *, time_t time_rcvd);
extern json_t *blktmpl_propose_jansson(blktemplate_t *, uint32_t caps, bool foreign);
extern json_t *blkmk_submit_jansson(blktemplate_t *, const unsigned char *data, unsigned int dataid, blknonce_t); extern json_t *blkmk_submit_jansson(blktemplate_t *, const unsigned char *data, unsigned int dataid, blknonce_t);
extern json_t *blkmk_submit_foreign_jansson(blktemplate_t *, const unsigned char *data, unsigned int dataid, blknonce_t); extern json_t *blkmk_submit_foreign_jansson(blktemplate_t *, const unsigned char *data, unsigned int dataid, blknonce_t);
extern json_t *blkmk_submitm_jansson(blktemplate_t *, const unsigned char *data, const void *extranonce, size_t extranoncesz, blknonce_t, bool foreign);
#ifdef __cplusplus
}
#endif
#endif #endif

View File

@ -1,16 +1,16 @@
/* /*
* Copyright 2012-2016 Luke Dashjr * Copyright 2012-2013 Luke Dashjr
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the standard MIT license. See COPYING for more details. * under the terms of the standard MIT license. See COPYING for more details.
*/ */
#define _BSD_SOURCE
#include <limits.h> #include <limits.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <strings.h>
#include <blktemplate.h> #include <blktemplate.h>
@ -27,7 +27,7 @@ static const char *capnames[] = {
"coinbase/append", "coinbase/append",
"coinbase", "coinbase",
"generation", "generate",
"time/increment", "time/increment",
"time/decrement", "time/decrement",
"transactions/add", "transactions/add",
@ -50,35 +50,13 @@ const char *blktmpl_capabilityname(gbt_capabilities_t caps) {
return NULL; 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) for (unsigned int i = 0; i < GBT_CAPABILITY_COUNT; ++i)
if (capnames[i] && !strcasecmp(n, capnames[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;
}
if (!strcasecmp(n, "transactions"))
return BMM_TXNADD; // Odd one as it's overloaded w/"transactions/add" per spec
return 0; 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 *blktmpl_create() {
blktemplate_t *tmpl; blktemplate_t *tmpl;
tmpl = calloc(1, sizeof(*tmpl)); tmpl = calloc(1, sizeof(*tmpl));
@ -87,17 +65,17 @@ blktemplate_t *blktmpl_create() {
tmpl->sigoplimit = USHRT_MAX; tmpl->sigoplimit = USHRT_MAX;
tmpl->sizelimit = ULONG_MAX; tmpl->sizelimit = ULONG_MAX;
tmpl->weightlimit = INT64_MAX;
tmpl->maxtime = 0xffffffff; tmpl->maxtime = 0xffffffff;
tmpl->maxtimeoff = 0x7fff; tmpl->maxtimeoff = 0x7fff;
tmpl->mintimeoff = -0x7fff; tmpl->mintimeoff = -0x7fff;
tmpl->maxnonce = 0xffffffff;
tmpl->expires = 0x7fff; tmpl->expires = 0x7fff;
return tmpl; return tmpl;
} }
uint32_t blktmpl_addcaps(const blktemplate_t *tmpl) { gbt_capabilities_t blktmpl_addcaps(const blktemplate_t *tmpl) {
// TODO: make this a lot more flexible for merging // TODO: make this a lot more flexible for merging
// For now, it's a simple "filled" vs "not filled" // For now, it's a simple "filled" vs "not filled"
if (tmpl->version) if (tmpl->version)
@ -115,52 +93,27 @@ bool blktmpl_get_submitold(blktemplate_t *tmpl) {
return tmpl->submitold; return tmpl->submitold;
} }
void blktxn_clean(struct blktxn_t * const bt) { static
void blktxn_free(struct blktxn_t *bt) {
free(bt->data); free(bt->data);
free(bt->hash); free(bt->hash);
free(bt->hash_);
free(bt->depends); free(bt->depends);
free(bt->txid);
}
static
void blkaux_clean(struct blkaux_t * const aux) {
free(aux->auxname);
free(aux->data);
} }
void blktmpl_free(blktemplate_t *tmpl) { void blktmpl_free(blktemplate_t *tmpl) {
for (unsigned long i = 0; i < tmpl->txncount; ++i) for (unsigned long i = 0; i < tmpl->txncount; ++i)
blktxn_clean(&tmpl->txns[i]); blktxn_free(&tmpl->txns[i]);
free(tmpl->txns); free(tmpl->txns);
if (tmpl->cbtxn) if (tmpl->cbtxn)
{ {
blktxn_clean(tmpl->cbtxn); blktxn_free(tmpl->cbtxn);
free(tmpl->cbtxn); free(tmpl->cbtxn);
} }
free(tmpl->_mrklbranch); // TODO: maybe free auxnames[0..n]? auxdata too
free(tmpl->_witnessmrklroot); free(tmpl->auxnames);
for (unsigned i = 0; i < tmpl->aux_count; ++i) free(tmpl->auxdata);
blkaux_clean(&tmpl->auxs[i]);
free(tmpl->auxs);
free(tmpl->workid); free(tmpl->workid);
free(tmpl->target);
free(tmpl->lp.id); free(tmpl->lp.id);
free(tmpl->lp.uri); free(tmpl->lp.uri);
if (tmpl->rules) {
for (char **currule = tmpl->rules; *currule; ++currule) {
free(*currule);
}
free(tmpl->rules);
}
if (tmpl->vbavailable) {
for (struct blktmpl_vbassoc **curvb = tmpl->vbavailable; *curvb; ++curvb) {
free((*curvb)->name);
free(*curvb);
}
free(tmpl->vbavailable);
}
free(tmpl); free(tmpl);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2016 Luke Dashjr * Copyright 2012 Luke Dashjr
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the standard MIT license. See COPYING for more details. * under the terms of the standard MIT license. See COPYING for more details.
@ -12,10 +12,6 @@
#include <stdint.h> #include <stdint.h>
#include <time.h> #include <time.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef uint32_t blkheight_t; typedef uint32_t blkheight_t;
typedef uint32_t libblkmaker_hash_t[8]; typedef uint32_t libblkmaker_hash_t[8];
typedef libblkmaker_hash_t blkhash_t; typedef libblkmaker_hash_t blkhash_t;
@ -24,32 +20,17 @@ typedef uint32_t blktime_t;
typedef int16_t blktime_diff_t; typedef int16_t blktime_diff_t;
typedef uint32_t blknonce_t; typedef uint32_t blknonce_t;
#define libblkmaker_blkheader_size (80)
#define libblkmaker_coinbase_size_minimum (4)
#define libblkmaker_coinbase_size_limit (100)
struct blktxn_t { struct blktxn_t {
unsigned char *data; unsigned char *data;
size_t datasz; size_t datasz;
// NOTE: The byte order of hash is backward; use hash_ instead
txnhash_t *hash; txnhash_t *hash;
signed long dependscount; signed long dependcount;
unsigned long *depends; unsigned long *depends;
int64_t fee_; uint64_t fee;
bool required; bool required;
int16_t sigops_; int16_t sigops;
int32_t weight;
txnhash_t *hash_;
txnhash_t *txid;
};
struct blkaux_t {
char *auxname;
unsigned char *data;
uint8_t datasz;
}; };
// BIP 23: Long Polling // BIP 23: Long Polling
@ -91,18 +72,11 @@ typedef enum {
extern const char *blktmpl_capabilityname(gbt_capabilities_t); extern const char *blktmpl_capabilityname(gbt_capabilities_t);
#define BLKTMPL_LONGEST_CAPABILITY_NAME (16) #define BLKTMPL_LONGEST_CAPABILITY_NAME (16)
// NOTE: blktmpl_getcapability("time") yields a combination of gbt_capabilities_t extern gbt_capabilities_t blktmpl_getcapability(const char *);
extern uint32_t blktmpl_getcapability(const char *);
typedef gbt_capabilities_t blkmutations_t; typedef gbt_capabilities_t blkmutations_t;
struct blktmpl_vbassoc {
char *name;
uint8_t bitnum;
};
// WARNING: Do not allocate this (ABI is not guaranteed to remain fixed-size)
typedef struct { typedef struct {
uint32_t version; uint32_t version;
unsigned char diffbits[4]; unsigned char diffbits[4];
@ -119,6 +93,9 @@ typedef struct {
time_t _time_rcvd; time_t _time_rcvd;
blktime_t curtime; blktime_t curtime;
char auxcount;
char **auxnames;
unsigned char **auxdata;
char *workid; char *workid;
@ -128,51 +105,26 @@ typedef struct {
// BIP 23: Basic Pool Extensions // BIP 23: Basic Pool Extensions
int16_t expires; int16_t expires;
blkhash_t *target; blkhash_t target;
// BIP 23: Mutations // BIP 23: Mutations
uint32_t mutations; blkmutations_t mutations;
blktime_t maxtime; blktime_t maxtime;
blktime_diff_t maxtimeoff; blktime_diff_t maxtimeoff;
blktime_t mintime; blktime_t mintime;
blktime_diff_t mintimeoff; blktime_diff_t mintimeoff;
blknonce_t minnonce;
blknonce_t maxnonce;
// TEMPORARY HACK // TEMPORARY HACK
libblkmaker_hash_t *_mrklbranch; libblkmaker_hash_t _mrklroot;
int _mrklbranchcount;
unsigned int next_dataid; unsigned int next_dataid;
unsigned aux_count;
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; } blktemplate_t;
extern void blktxn_init(struct blktxn_t *);
extern void blktxn_clean(struct blktxn_t *);
extern blktemplate_t *blktmpl_create(); extern blktemplate_t *blktmpl_create();
extern uint32_t blktmpl_addcaps(const blktemplate_t *); extern gbt_capabilities_t blktmpl_addcaps(const blktemplate_t *);
extern const struct blktmpl_longpoll_req *blktmpl_get_longpoll(blktemplate_t *); extern const struct blktmpl_longpoll_req *blktmpl_get_longpoll(blktemplate_t *);
extern bool blktmpl_get_submitold(blktemplate_t *tmpl); extern bool blktmpl_get_submitold(blktemplate_t *tmpl);
extern void blktmpl_free(blktemplate_t *); extern void blktmpl_free(blktemplate_t *);
#ifdef __cplusplus
}
#endif
#endif #endif

View File

@ -1,25 +1,24 @@
dnl * Copyright 2012-2014 Luke Dashjr dnl * Copyright 2012-2013 Luke Dashjr
dnl * dnl *
dnl * This program is free software; you can redistribute it and/or modify it dnl * This program is free software; you can redistribute it and/or modify it
dnl * under the terms of the standard MIT license. See COPYING for more details. dnl * under the terms of the standard MIT license. See COPYING for more details.
AC_INIT( AC_INIT(
[libblkmaker], [libblkmaker],
[0.6.0], [0.1],
[luke_libblkmaker@dashjr.org], [luke_libblkmaker@dashjr.org],
[libblkmaker], [libblkmaker],
[http://gitorious.org/bitcoin/libblkmaker]) [http://gitorious.org/bitcoin/libblkmaker])
AC_CONFIG_AUX_DIR([.]) AC_CONFIG_AUX_DIR([.])
AC_PREREQ([2.59]) AC_PREREQ([2.59])
AM_INIT_AUTOMAKE([1.11 -Wall dist-xz foreign]) AM_INIT_AUTOMAKE([1.10 -Wall dist-bzip2 foreign])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_PROG_CC_C99 AC_PROG_CC_C99
m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
LT_INIT([disable-static]) LT_INIT([disable-static])
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html # 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], [4:2:4])
AC_SUBST([LIBBLKMAKER_API_VERSION], [0.1]) AC_SUBST([LIBBLKMAKER_API_VERSION], [0.1])
AC_CONFIG_FILES([Makefile AC_CONFIG_FILES([Makefile
@ -47,22 +46,6 @@ PKG_CHECK_MODULES([JANSSON],[jansson],[
AC_SUBST(JANSSON_CFLAGS) AC_SUBST(JANSSON_CFLAGS)
AC_SUBST(JANSSON_LIBS) AC_SUBST(JANSSON_LIBS)
PKG_CHECK_MODULES([libbase58],[libbase58])
AC_CHECK_LIB([ws2_32], [strchr]) 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 AC_OUTPUT

View File

@ -9,14 +9,9 @@
#include <inttypes.h> #include <inttypes.h>
#include <stdint.h> #include <stdint.h>
#ifndef WIN32
#include <arpa/inet.h> #include <arpa/inet.h>
#else
#include <winsock2.h>
#endif
#include <gcrypt.h> #include <gcrypt.h>
#include <libbase58.h>
#include <blkmaker.h> #include <blkmaker.h>
#include <blkmaker_jansson.h> #include <blkmaker_jansson.h>
@ -28,23 +23,20 @@ void testb58() {
int rv; int rv;
const char *iaddr = "11Baf75Ferj6A7AoN565gCQj9kGWbDMHfN9"; const char *iaddr = "11Baf75Ferj6A7AoN565gCQj9kGWbDMHfN9";
const char *addr = &iaddr[1]; const char *addr = &iaddr[1];
const size_t addrlen = strlen(addr);
size_t actuallen;
char bufx[26] = {'\xff'}; char bufx[26] = {'\xff'};
char *buf = &bufx[1]; char *buf = &bufx[1];
actuallen = 25; if (!_blkmk_b58tobin(buf, 25, addr, 0))
if (!b58tobin(buf, &actuallen, addr, addrlen))
exit(1); exit(1);
if (bufx[0] != '\xff') if (bufx[0] != '\xff')
exit(2); exit(2);
char cbuf[51]; char cbuf[51];
_blkmk_bin2hex(cbuf, buf, 25); _blkmk_bin2hex(cbuf, buf, 25);
printf("Base58 raw data: %s\n", cbuf); printf("Base58 raw data: %s\n", cbuf);
assert((rv = b58check(buf, 25, addr, addrlen)) == 0); assert((rv = _blkmk_b58check(buf, 25, addr)) == 0);
printf("Base58 check: %d\n", rv); printf("Base58 check: %d\n", rv);
assert((rv = b58check(buf, 25, &addr[1], addrlen)) < 0); assert((rv = _blkmk_b58check(buf, 25, &addr[1])) < 0);
printf("Base58 check (invalid/ unpadded): %d\n", rv); printf("Base58 check (invalid/ unpadded): %d\n", rv);
assert((rv = b58check(buf, 25, iaddr, addrlen + 1)) < 0); assert((rv = _blkmk_b58check(buf, 25, iaddr)) < 0);
printf("Base58 check (invalid/extra padded): %d\n", rv); printf("Base58 check (invalid/extra padded): %d\n", rv);
} }
@ -67,7 +59,6 @@ int main(int argc, char**argv) {
json_error_t jsone; json_error_t jsone;
const char *err; const char *err;
b58_sha256_impl = my_sha256;
blkmk_sha256_impl = my_sha256; blkmk_sha256_impl = my_sha256;
testb58(); testb58();
@ -131,5 +122,4 @@ int main(int argc, char**argv) {
send_json(req); send_json(req);
} }
blktmpl_free(tmpl); blktmpl_free(tmpl);
return 0;
} }

View File

@ -7,7 +7,5 @@ Name: @PACKAGE_NAME@_jansson
Description: Bitcoin block maker library. Description: Bitcoin block maker library.
Version: @PACKAGE_VERSION@ Version: @PACKAGE_VERSION@
URL: @PACKAGE_URL@ 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@ Cflags: -I${includedir}/libblkmaker-@LIBBLKMAKER_API_VERSION@
Requires: jansson
Requires.private: libbase58

View File

@ -4,59 +4,15 @@
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include <blktemplate.h>
// blkmaker.c // blkmaker.c
extern bool _blkmk_dblsha256(void *hash, const void *data, size_t datasz); 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);
// hex.c // hex.c
extern void _blkmk_bin2hex(char *out, const void *data, size_t datasz); extern void _blkmk_bin2hex(char *out, const void *data, size_t datasz);
extern bool _blkmk_hex2bin(void *o, const char *x, size_t len); extern bool _blkmk_hex2bin(void *o, const char *x, size_t len);
// inline // base58.c
extern bool _blkmk_b58tobin(void *bin, size_t binsz, const char *b58, size_t b58sz);
// NOTE: This must return 0 for 0 extern int _blkmk_b58check(void *bin, size_t binsz, const char *b58);
static inline
int blkmk_flsl(unsigned long n)
{
int i;
for (i = 0; n; ++i)
n >>= 1;
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 #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