pax_global_header00006660000000000000000000000064126200325570014514gustar00rootroot0000000000000052 comment=cc0f35fb8a960056e4760f775aca4793ab82b7b3 libblkmaker-0.5.2/000077500000000000000000000000001262003255700137775ustar00rootroot00000000000000libblkmaker-0.5.2/.gitignore000066400000000000000000000002761262003255700157740ustar00rootroot00000000000000*~ *.so *.o a.* todo* example .*.kate-swp configure Makefile Makefile.in *.la *.pc ltmain.sh libtool install-sh missing depcomp .libs .deps aclocal.m4 autom4te.cache *.lo config.* ii ar-lib libblkmaker-0.5.2/AUTHORS000066400000000000000000000001161262003255700150450ustar00rootroot00000000000000Luke Dashjr Andy Alness libblkmaker-0.5.2/COPYING000066400000000000000000000020401262003255700150260ustar00rootroot00000000000000Copyright 2012-2014 Luke Dashjr Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. libblkmaker-0.5.2/Makefile.am000066400000000000000000000030521262003255700160330ustar00rootroot00000000000000# Copyright 2012-2013 Luke Dashjr # # 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. lib_LTLIBRARIES = \ libblkmaker_jansson-@LIBBLKMAKER_API_VERSION@.la \ libblkmaker-@LIBBLKMAKER_API_VERSION@.la libblkmaker_@LIBBLKMAKER_API_VERSION@_la_SOURCES = \ base58.c \ blkmaker.c \ blktemplate.c \ hex.c \ private.h libblkmaker_@LIBBLKMAKER_API_VERSION@_la_CFLAGS = \ $(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_include_HEADERS = \ blkmaker.h \ blktemplate.h libblkmaker_jansson_@LIBBLKMAKER_API_VERSION@_la_SOURCES = blkmaker_jansson.c libblkmaker_jansson_@LIBBLKMAKER_API_VERSION@_la_DEPENDENCIES = libblkmaker-$(LIBBLKMAKER_API_VERSION).la libblkmaker_jansson_@LIBBLKMAKER_API_VERSION@_la_CFLAGS = $(JANSSON_CFLAGS) libblkmaker_jansson_@LIBBLKMAKER_API_VERSION@_la_LDFLAGS = \ -L.libs \ -lblkmaker-$(LIBBLKMAKER_API_VERSION) \ $(JANSSON_LIBS) \ -no-undefined \ -version-info $(LIBBLKMAKER_SO_VERSION) libblkmaker_jansson_includedir = $(includedir)/libblkmaker-$(LIBBLKMAKER_API_VERSION) libblkmaker_jansson_include_HEADERS = \ blkmaker_jansson.h pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = \ libblkmaker_jansson-$(LIBBLKMAKER_API_VERSION).pc dist_noinst_SCRIPTS = autogen.sh dist_noinst_DATA = \ AUTHORS COPYING README \ example.c \ testinput.c libblkmaker-0.5.2/README000066400000000000000000000021061262003255700146560ustar00rootroot00000000000000Dependencies: Jansson 2.0 with 'long long' support Example dependencies: Jansson 2.1 (to read JSON from stdin) libgcrypt (for SHA256) For usage, check out example.c Note that you must assign blkmk_sha256_impl to a function pointer: bool mysha256(void *hash_out, const void *data, size_t datasz) hash_out must be able to overlap with data! Also note that you should NOT roll ntime for data retrieved without explicitly checking that it falls within the template's limitations (mintime, maxtime, mintimeoff, and maxtimeoff); read the BIP 23 specification in detail to understand how they work. It is usually best to simply get more data as often 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. libblkmaker-0.5.2/autogen.sh000077500000000000000000000004701262003255700160010ustar00rootroot00000000000000#!/bin/sh -e # Written by Luke Dashjr in 2012 # This program is released under the terms of the Creative Commons "CC0 1.0 Universal" license and/or copyright waiver. if test -z "$srcdir"; then srcdir=`dirname "$0"` if test -z "$srcdir"; then srcdir=. fi fi autoreconf --force --install --verbose "$srcdir" libblkmaker-0.5.2/base58.c000066400000000000000000000033441262003255700152360ustar00rootroot00000000000000/* * Copyright 2012 Luke Dashjr * * 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. */ #ifndef WIN32 #include #else #include #endif #include #include #include #include #include #include "private.h" bool _blkmk_b58tobin(void *bin, size_t binsz, const char *b58, size_t b58sz) { return b58tobin(bin, &binsz, b58, b58sz); } int _blkmk_b58check(void *bin, size_t binsz, const char *base58str) { if (!b58_sha256_impl) b58_sha256_impl = blkmk_sha256_impl; return b58check(bin, binsz, base58str, 34); } size_t blkmk_address_to_script(void *out, size_t outsz, const char *addr) { unsigned char addrbin[25]; unsigned char *cout = out; const size_t b58sz = strlen(addr); int addrver; size_t rv; rv = sizeof(addrbin); if (!b58_sha256_impl) b58_sha256_impl = blkmk_sha256_impl; if (!b58tobin(addrbin, &rv, addr, b58sz)) return 0; addrver = b58check(addrbin, sizeof(addrbin), addr, b58sz); switch (addrver) { case 0: // Bitcoin pubkey hash case 111: // Testnet pubkey hash if (outsz < (rv = 25)) return rv; cout[ 0] = 0x76; // OP_DUP cout[ 1] = 0xa9; // OP_HASH160 cout[ 2] = 0x14; // push 20 bytes memcpy(&cout[3], &addrbin[1], 20); cout[23] = 0x88; // OP_EQUALVERIFY cout[24] = 0xac; // OP_CHECKSIG return rv; case 5: // Bitcoin script hash case 196: // Testnet script hash if (outsz < (rv = 23)) return rv; cout[ 0] = 0xa9; // OP_HASH160 cout[ 1] = 0x14; // push 20 bytes memcpy(&cout[2], &addrbin[1], 20); cout[22] = 0x87; // OP_EQUAL return rv; default: return 0; } } libblkmaker-0.5.2/blkmaker.c000066400000000000000000000305161262003255700157400ustar00rootroot00000000000000/* * Copyright 2012-2014 Luke Dashjr * * 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. */ #include #include #include #include #include #include #include #ifndef WIN32 #include #else #include #endif #include #include #include "private.h" static inline void my_htole32(unsigned char *buf, uint32_t n) { buf[0] = (n >> 0) % 256; buf[1] = (n >> 8) % 256; buf[2] = (n >> 16) % 256; buf[3] = (n >> 24) % 256; } static inline void my_htole64(unsigned char *buf, uint64_t n) { for (int i = 0; i < 8; ++i) buf[i] = (n >> (8*i)) & 0xff; } bool (*blkmk_sha256_impl)(void *, const void *, size_t) = NULL; bool _blkmk_dblsha256(void *hash, const void *data, size_t datasz) { return blkmk_sha256_impl(hash, data, datasz) && blkmk_sha256_impl(hash, hash, 32); } #define dblsha256 _blkmk_dblsha256 uint64_t blkmk_init_generation3(blktemplate_t * const tmpl, const void * const script, const size_t scriptsz, bool * const inout_newcb) { if (tmpl->cbtxn && !(*inout_newcb && (tmpl->mutations & BMM_GENERATE))) { *inout_newcb = false; return 0; } *inout_newcb = true; if (scriptsz >= 0xfd) return 0; unsigned char *data = malloc(168 + scriptsz); size_t off = 0; if (!data) return 0; memcpy(&data[0], "\x01\0\0\0" // txn ver "\x01" // input count "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" // prevout "\xff\xff\xff\xff" // index (-1) "\x02" // scriptSig length // height serialization length (set later) , 42); off += 43; blkheight_t h = tmpl->height; while (h > 127) { ++data[41]; data[off++] = h & 0xff; h >>= 8; } data[off++] = h; 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 > 100) { 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], "\xff\xff\xff\xff" // sequence "\x01" // output count , 5); off += 5; my_htole64(&data[off], tmpl->cbvalue); off += 8; data[off++] = scriptsz; memcpy(&data[off], script, scriptsz); off += scriptsz; memset(&data[off], 0, 4); // lock time off += 4; struct blktxn_t *txn = calloc(1, sizeof(*tmpl->cbtxn)); if (!txn) { free(data); return 0; } txn->data = data; txn->datasz = off; if (tmpl->cbtxn) { _blktxn_free(tmpl->cbtxn); free(tmpl->cbtxn); } tmpl->cbtxn = txn; tmpl->mutations |= BMM_CBAPPEND | BMM_CBSET | BMM_GENERATE; 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) { 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)); size_t hashcount = tmpl->txncount + 1; unsigned char hashes[(hashcount + 1) * 32]; for (i = 0; i < tmpl->txncount; ++i) memcpy(&hashes[0x20 * (i + 1)], tmpl->txns[i].hash_, 0x20); for (i = 0; i < branchcount; ++i) { memcpy(&branches[i], &hashes[0x20], 0x20); if (hashcount % 2) { memcpy(&hashes[32 * hashcount], &hashes[32 * (hashcount - 1)], 32); ++hashcount; } for (size_t i = 2; i < hashcount; i += 2) // This is where we overlap input and output, on the first pair if (!dblsha256(&hashes[i / 2 * 32], &hashes[32 * i], 64)) { free(branches); return false; } hashcount /= 2; } tmpl->_mrklbranch = branches; tmpl->_mrklbranchcount = branchcount; return true; } static bool build_merkle_root(unsigned char *mrklroot_out, blktemplate_t *tmpl, unsigned char *cbtxndata, size_t cbtxndatasz) { int i; libblkmaker_hash_t hashes[0x40]; if (!blkmk_build_merkle_branches(tmpl)) return false; if (!dblsha256(&hashes[0], cbtxndata, cbtxndatasz)) return false; for (i = 0; i < tmpl->_mrklbranchcount; ++i) { memcpy(&hashes[1], tmpl->_mrklbranch[i], 0x20); // This is where we overlap input and output, on the first pair if (!dblsha256(&hashes[0], &hashes[0], 0x40)) return false; } memcpy(mrklroot_out, &hashes[0], 32); return true; } 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) { unsigned char *out = vout; unsigned char *in = tmpl->cbtxn->data; size_t insz = tmpl->cbtxn->datasz; if (in[cbScriptSigLen] > 100 - appendsz) return false; int cbPostScriptSig = cbScriptSigLen + 1 + in[cbScriptSigLen]; if (appended_at_offset) *appended_at_offset = cbPostScriptSig; unsigned char *outPostScriptSig = &out[cbPostScriptSig]; void *outExtranonce = (void*)outPostScriptSig; outPostScriptSig += appendsz; if (out != in) { memcpy(out, in, cbPostScriptSig+1); memcpy(outPostScriptSig, &in[cbPostScriptSig], insz - cbPostScriptSig); } else memmove(outPostScriptSig, &in[cbPostScriptSig], insz - cbPostScriptSig); out[cbScriptSigLen] += appendsz; memcpy(outExtranonce, append, appendsz); 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) { if (!(tmpl->mutations & (BMM_CBAPPEND | BMM_CBSET))) return -1; size_t datasz = tmpl->cbtxn->datasz; if (!merkle_only) { if (extranoncesz < sizeof(unsigned int)) extranoncesz = sizeof(unsigned int); else if (extranoncesz == sizeof(unsigned int)) ++extranoncesz; } size_t availsz = 100 - extranoncesz - tmpl->cbtxn->data[cbScriptSigLen]; if (appendsz > availsz) return availsz; void *newp = realloc(tmpl->cbtxn->data, datasz + appendsz); if (!newp) return -2; tmpl->cbtxn->data = newp; if (!_blkmk_append_cb(tmpl, newp, append, appendsz, NULL)) return -3; tmpl->cbtxn->datasz += appendsz; 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) { unsigned char *in = tmpl->cbtxn->data; size_t insz = tmpl->cbtxn->datasz; if (!workid) { memcpy(vout, in, insz); *offs += insz; return true; } if (!_blkmk_append_cb(tmpl, vout, &workid, sizeof(workid), NULL)) return false; *offs += insz + sizeof(workid); 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)]; size_t cbtxndatasz = 0; if (!_blkmk_extranonce(tmpl, cbtxndata, dataid, &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) { if (!(blkmk_time_left(tmpl, usetime) && blkmk_work_left(tmpl) && tmpl->cbtxn)) return 0; if (bufsz < 76) return 76; 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 )) return false; if (extranoncesz == sizeof(unsigned int)) // Avoid overlapping with blkmk_get_data use ++extranoncesz; void ** const out_branches = _out_branches; void ** const out_cbtxn = _out_cbtxn; unsigned char *cbuf = buf; my_htole32(&cbuf[0], tmpl->version); memcpy(&cbuf[4], &tmpl->prevblk, 32); *out_cbtxnsz = tmpl->cbtxn->datasz + extranoncesz; *out_cbtxn = malloc(*out_cbtxnsz); if (!*out_cbtxn) return false; unsigned char dummy[extranoncesz]; memset(dummy, 0, extranoncesz); if (!_blkmk_append_cb(tmpl, *out_cbtxn, dummy, extranoncesz, cbextranonceoffset)) { free(*out_cbtxn); return false; } blkmk_set_times(tmpl, &cbuf[68], usetime, out_expire, can_roll_ntime); memcpy(&cbuf[72], &tmpl->diffbits, 4); *out_branchcount = tmpl->_mrklbranchcount; const size_t branches_bytesz = (sizeof(libblkmaker_hash_t) * tmpl->_mrklbranchcount); *out_branches = malloc(branches_bytesz); if (!*out_branches) { free(*out_cbtxn); return false; } memcpy(*out_branches, tmpl->_mrklbranch, branches_bytesz); return true; } blktime_diff_t blkmk_time_left(const blktemplate_t *tmpl, time_t nowtime) { double age = difftime(nowtime, tmpl->_time_rcvd); if (age >= tmpl->expires) return 0; return tmpl->expires - age; } unsigned long blkmk_work_left(const blktemplate_t *tmpl) { if (!tmpl->version) return 0; if (!(tmpl->mutations & (BMM_CBAPPEND | BMM_CBSET))) return 1; return UINT_MAX - tmpl->next_dataid; return BLKMK_UNLIMITED_WORK_COUNT; } 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; } char *blkmk_assemble_submission_(blktemplate_t * const tmpl, const unsigned char * const data, const unsigned int dataid, blknonce_t nonce, const bool foreign) { unsigned char blk[80 + 8 + 1000000]; memcpy(blk, data, 76); 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 = malloc((offs * 2) + 1); _blkmk_bin2hex(blkhex, blk, offs); return blkhex; } libblkmaker-0.5.2/blkmaker.h000066400000000000000000000031661262003255700157460ustar00rootroot00000000000000#ifndef BLKMAKER_H #define BLKMAKER_H #include #include #include #include #ifdef __cplusplus extern "C" { #endif #define BLKMAKER_VERSION (6L) #define BLKMAKER_MAX_BLOCK_VERSION (4) 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_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_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 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 unsigned long blkmk_work_left(const blktemplate_t *); #define BLKMK_UNLIMITED_WORK_COUNT ULONG_MAX extern size_t blkmk_address_to_script(void *out, size_t outsz, const char *addr); #ifdef __cplusplus } #endif #endif libblkmaker-0.5.2/blkmaker_jansson.c000066400000000000000000000226441262003255700174760ustar00rootroot00000000000000/* * Copyright 2012-2014 Luke Dashjr * * 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. */ #define _BSD_SOURCE #include #include #include #include #include #include "private.h" #ifndef JSON_INTEGER_IS_LONG_LONG # error "Jansson 2.0 with long long support required!" #endif json_t *blktmpl_request_jansson(const uint32_t caps, const char * const lpid) { json_t *req, *jcaps, *jstr, *reqf, *reqa; if (!(req = json_object())) return NULL; jstr = reqa = jcaps = NULL; if (!(reqf = json_object())) goto err; if (!(reqa = json_array())) goto err; if (!(jcaps = json_array())) goto err; for (int i = 0; i < GBT_CAPABILITY_COUNT; ++i) if (caps & (1 << i)) { jstr = json_string(blktmpl_capabilityname(1 << i)); if (!jstr) goto err; if (json_array_append_new(jcaps, jstr)) goto err; } jstr = NULL; if (json_object_set_new(req, "capabilities", jcaps)) goto err; jcaps = NULL; if (!(jstr = json_integer(0))) goto err; if (json_object_set_new(reqf, "id", jstr)) goto err; if (!(jstr = json_integer(BLKMAKER_MAX_BLOCK_VERSION))) goto err; if (json_object_set_new(req, "maxversion", jstr)) goto err; if (lpid) { if (!(jstr = json_string(lpid))) goto err; if (json_object_set_new(req, "longpollid", jstr)) goto err; } if (!(jstr = json_string("getblocktemplate"))) goto err; if (json_object_set_new(reqf, "method", jstr)) goto err; jstr = NULL; if (json_array_append_new(reqa, req)) goto err; req = NULL; if (json_object_set_new(reqf, "params", reqa)) goto err; return reqf; err: if (req ) json_decref(req ); if (reqa ) json_decref(reqa ); if (reqf ) json_decref(reqf ); if (jcaps) json_decref(jcaps); if (jstr ) json_decref(jstr ); return NULL; } #define my_hex2bin _blkmk_hex2bin #define GET(key, type) do { \ if (!(v = json_object_get(json, #key))) \ return "Missing '" #key "'"; \ if (!json_is_ ## type(v)) \ return "Wrong type for '" #key "'"; \ } while(0) #define GETHEX(key, skey) do { \ GET(key, string); \ if (!my_hex2bin(tmpl->skey, json_string_value(v), sizeof(tmpl->skey))) \ return "Error decoding '" #key "'"; \ } while(0) #define GETNUM(key) do { \ GET(key, number); \ tmpl->key = json_integer_value(v); \ } while(0) #define GETNUM_O2(key, skey) do { \ if ((v = json_object_get(json, #skey)) && json_is_number(v)) \ tmpl->key = json_integer_value(v); \ } while(0) #define GETNUM_O(key) GETNUM_O2(key, key) #define GETSTR(key, skey) do { \ if ((v = json_object_get(json, #key)) && json_is_string(v)) \ if (!(tmpl->skey = strdup(json_string_value(v)))) \ return "Error copying '" #key "'"; \ } while(0) #define GETBOOL(key, skey, def) do { \ if ((v = json_object_get(json, #key)) && json_is_boolean(v)) \ tmpl->skey = json_is_true(v); \ else \ if (def) \ tmpl->skey = true; \ } while(0) static void my_flip(void *, size_t); static const char *parse_txn(struct blktxn_t *txn, json_t *txnj) { json_t *vv; 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); size_t datasz = strlen(hexdata) / 2; txn->data = malloc(datasz); txn->datasz = datasz; if (!my_hex2bin(txn->data, hexdata, datasz)) return "Error decoding transaction data"; if ((vv = json_object_get(txnj, "hash")) && json_is_string(vv)) { hexdata = json_string_value(vv); txn->hash_ = malloc(sizeof(*txn->hash_)); if (!my_hex2bin(*txn->hash_, hexdata, sizeof(*txn->hash_))) { free(txn->hash_); txn->hash_ = NULL; } else my_flip(*txn->hash_, sizeof(*txn->hash_)); } // TODO: dependcount/depends, fee, required, sigops return NULL; } static void my_flip(void *data, size_t datasz) { char *cdata = (char*)data; --datasz; size_t hds = datasz / 2; for (size_t i = 0; i <= hds; ++i) { int altp = datasz - i; char c = cdata[i]; cdata[i] = cdata[altp]; cdata[altp] = c; } } const char *blktmpl_add_jansson(blktemplate_t *tmpl, const json_t *json, time_t time_rcvd) { if (tmpl->version) return "Template already populated (combining not supported)"; json_t *v, *v2; const char *s; if ((v = json_object_get(json, "result"))) { json_t *je; if ((je = json_object_get(json, "error")) && !json_is_null(je)) return "JSON result is error"; json = v; } GETHEX(bits, diffbits); my_flip(tmpl->diffbits, 4); GETNUM(curtime); GETNUM(height); GETHEX(previousblockhash, prevblk); my_flip(tmpl->prevblk, 32); GETNUM_O(sigoplimit); GETNUM_O(sizelimit); GETNUM(version); GETNUM_O2(cbvalue, coinbasevalue); GETSTR(workid, workid); GETNUM_O(expires); GETNUM_O(maxtime); GETNUM_O(maxtimeoff); GETNUM_O(mintime); GETNUM_O(mintimeoff); 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; } if ((v = json_object_get(json, "coinbaseaux")) && json_is_object(v)) { tmpl->aux_count = json_object_size(v); tmpl->auxs = malloc(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, }; my_hex2bin(tmpl->auxs[i].data, s, sz); } } 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--; ) { v2 = json_array_get(v, i); if (!json_is_string(v2)) continue; tmpl->mutations |= blktmpl_getcapability(json_string_value(v2)); } } if (tmpl->version > BLKMAKER_MAX_BLOCK_VERSION || (tmpl->version >= 2 && !tmpl->height)) { if (tmpl->mutations & BMM_VERDROP) tmpl->version = tmpl->height ? BLKMAKER_MAX_BLOCK_VERSION : 1; else if (!(tmpl->mutations & BMM_VERFORCE)) return "Unrecognized block version, and not allowed to reduce or force it"; } tmpl->_time_rcvd = time_rcvd; return NULL; } json_t *blktmpl_propose_jansson(blktemplate_t * const tmpl, const uint32_t caps, const bool foreign) { json_t *jreq = blktmpl_request_jansson(caps, NULL), *ja = NULL, *jparams; if (!(jreq && json_is_object(jreq))) 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))) goto err; if (json_object_set_new(jparams, "workid", ja)) goto err; } ja = NULL; unsigned int dataid = (tmpl->mutations & (BMM_CBAPPEND | BMM_CBSET) ? 1 : 0); uint8_t sdata[0x4c]; if (!blkmk_sample_data_(tmpl, sdata, dataid)) goto err; char *blkhex = blkmk_assemble_submission_(tmpl, sdata, dataid, 0, foreign); if (!blkhex) goto err; if (!(ja = json_string(blkhex))) goto err; if (json_object_set_new(jparams, "data", ja)) goto err; return jreq; err: if (jreq) json_decref(jreq); if (ja) json_decref(ja); return NULL; } static json_t *_blkmk_submit_jansson(blktemplate_t *tmpl, const unsigned char *data, unsigned int dataid, blknonce_t nonce, bool foreign) { char *blkhex = blkmk_assemble_submission_(tmpl, data, dataid, nonce, foreign); if (!blkhex) return NULL; json_t *rv = json_array(), *ja, *jb; jb = NULL; ja = json_string(blkhex); free(blkhex); if (!ja) goto err; if (json_array_append_new(rv, ja)) goto err; if (!(ja = json_object())) goto err; if (tmpl->workid && !foreign) { if (!(jb = json_string(tmpl->workid))) goto err; if (json_object_set_new(ja, "workid", jb)) goto err; jb = NULL; } if (json_array_append_new(rv, ja)) goto err; if (!(ja = json_object())) goto err; if (!(jb = json_integer(0))) goto err; if (json_object_set_new(ja, "id", jb)) goto err; if (!(jb = json_string("submitblock"))) goto err; if (json_object_set_new(ja, "method", jb)) goto err; jb = NULL; if (json_object_set_new(ja, "params", rv)) goto err; return ja; err: json_decref(rv); if (ja) json_decref(ja); if (jb) json_decref(jb); return NULL; } json_t *blkmk_submit_jansson(blktemplate_t *tmpl, const unsigned char *data, unsigned int dataid, blknonce_t nonce) { 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) { return _blkmk_submit_jansson(tmpl, data, dataid, nonce, true); } libblkmaker-0.5.2/blkmaker_jansson.h000066400000000000000000000012371262003255700174760ustar00rootroot00000000000000#ifndef BLKMAKER_JANSSON_H #define BLKMAKER_JANSSON_H #include #include #ifdef __cplusplus extern "C" { #endif extern json_t *blktmpl_request_jansson(uint32_t extracaps, const char *lpid); 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_foreign_jansson(blktemplate_t *, const unsigned char *data, unsigned int dataid, blknonce_t); #ifdef __cplusplus } #endif #endif libblkmaker-0.5.2/blktemplate.c000066400000000000000000000055011262003255700164500ustar00rootroot00000000000000/* * Copyright 2012-2013 Luke Dashjr * * 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. */ #define _BSD_SOURCE #include #include #include #include #include static const char *capnames[] = { "coinbasetxn", "coinbasevalue", "workid", "longpoll", "proposal", "serverlist", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "coinbase/append", "coinbase", "generate", "time/increment", "time/decrement", "transactions/add", "prevblock", "version/force", "version/reduce", "submit/hash", "submit/coinbase", "submit/truncate", "share/coinbase", "share/merkle", "share/truncate", }; const char *blktmpl_capabilityname(gbt_capabilities_t caps) { for (unsigned int i = 0; i < GBT_CAPABILITY_COUNT; ++i) if (caps & (1 << i)) return capnames[i]; return NULL; } gbt_capabilities_t blktmpl_getcapability(const char *n) { for (unsigned int i = 0; i < GBT_CAPABILITY_COUNT; ++i) if (capnames[i] && !strcasecmp(n, capnames[i])) return 1 << i; if (!strcasecmp(n, "transactions")) return BMM_TXNADD; // Odd one as it's overloaded w/"transactions/add" per spec return 0; } blktemplate_t *blktmpl_create() { blktemplate_t *tmpl; tmpl = calloc(1, sizeof(*tmpl)); if (!tmpl) return NULL; tmpl->sigoplimit = USHRT_MAX; tmpl->sizelimit = ULONG_MAX; tmpl->maxtime = 0xffffffff; tmpl->maxtimeoff = 0x7fff; tmpl->mintimeoff = -0x7fff; tmpl->maxnonce = 0xffffffff; tmpl->expires = 0x7fff; return tmpl; } uint32_t blktmpl_addcaps(const blktemplate_t *tmpl) { // TODO: make this a lot more flexible for merging // For now, it's a simple "filled" vs "not filled" if (tmpl->version) return 0; return GBT_CBTXN | GBT_WORKID | BMM_TIMEINC | BMM_CBAPPEND | BMM_VERFORCE | BMM_VERDROP | BMAb_COINBASE | BMAb_TRUNCATE; } const struct blktmpl_longpoll_req *blktmpl_get_longpoll(blktemplate_t *tmpl) { if (!tmpl->lp.id) return NULL; return &tmpl->lp; } bool blktmpl_get_submitold(blktemplate_t *tmpl) { return tmpl->submitold; } void _blktxn_free(struct blktxn_t *bt) { free(bt->data); free(bt->hash); free(bt->hash_); free(bt->depends); } #define blktxn_free _blktxn_free static void blkaux_clean(struct blkaux_t * const aux) { free(aux->auxname); free(aux->data); } void blktmpl_free(blktemplate_t *tmpl) { for (unsigned long i = 0; i < tmpl->txncount; ++i) blktxn_free(&tmpl->txns[i]); free(tmpl->txns); if (tmpl->cbtxn) { blktxn_free(tmpl->cbtxn); free(tmpl->cbtxn); } free(tmpl->_mrklbranch); for (unsigned i = 0; i < tmpl->aux_count; ++i) blkaux_clean(&tmpl->auxs[i]); free(tmpl->auxs); free(tmpl->workid); free(tmpl->target); free(tmpl->lp.id); free(tmpl->lp.uri); free(tmpl); } libblkmaker-0.5.2/blktemplate.h000066400000000000000000000062061262003255700164600ustar00rootroot00000000000000/* * Copyright 2012 Luke Dashjr * * 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. */ #ifndef BLKTEMPLATE_H #define BLKTEMPLATE_H #include #include #include #ifdef __cplusplus extern "C" { #endif typedef uint32_t blkheight_t; typedef uint32_t libblkmaker_hash_t[8]; typedef libblkmaker_hash_t blkhash_t; typedef libblkmaker_hash_t txnhash_t; typedef uint32_t blktime_t; typedef int16_t blktime_diff_t; typedef uint32_t blknonce_t; struct blktxn_t { unsigned char *data; size_t datasz; // NOTE: The byte order of hash is backward; use hash_ instead txnhash_t *hash; signed long dependcount; unsigned long *depends; uint64_t fee; bool required; int16_t sigops; txnhash_t *hash_; }; struct blkaux_t { char *auxname; unsigned char *data; uint8_t datasz; }; // BIP 23: Long Polling struct blktmpl_longpoll_req { char *id; char *uri; }; typedef enum { GBT_CBTXN = 1 << 0, GBT_CBVALUE = 1 << 1, GBT_WORKID = 1 << 2, GBT_LONGPOLL = 1 << 3, // BIP 22: Long Polling GBT_PROPOSAL = 1 << 4, // BIP 23: Block Proposal GBT_SERVICE = 1 << 5, // BIP 23: Logical Services // BIP 23: Mutations BMM_CBAPPEND = 1 << 0x10, BMM_CBSET = 1 << 0x11, BMM_GENERATE = 1 << 0x12, BMM_TIMEINC = 1 << 0x13, BMM_TIMEDEC = 1 << 0x14, BMM_TXNADD = 1 << 0x15, BMM_PREVBLK = 1 << 0x16, BMM_VERFORCE = 1 << 0x17, BMM_VERDROP = 1 << 0x18, // BIP 23: Submission Abbreviation BMA_TXNHASH = 1 << 0x19, BMAb_COINBASE = 1 << 0x1a, BMAb_TRUNCATE = 1 << 0x1b, BMAs_COINBASE = 1 << 0x1c, BMAs_MERKLE = 1 << 0x1d, BMAs_TRUNCATE = 1 << 0x1e, } gbt_capabilities_t; #define GBT_CAPABILITY_COUNT (0x1f) extern const char *blktmpl_capabilityname(gbt_capabilities_t); #define BLKTMPL_LONGEST_CAPABILITY_NAME (16) extern gbt_capabilities_t blktmpl_getcapability(const char *); typedef gbt_capabilities_t blkmutations_t; // WARNING: Do not allocate this (ABI is not guaranteed to remain fixed-size) typedef struct { uint32_t version; unsigned char diffbits[4]; blkheight_t height; blkhash_t prevblk; unsigned short sigoplimit; unsigned long sizelimit; unsigned long txncount; struct blktxn_t *txns; struct blktxn_t *cbtxn; uint64_t cbvalue; time_t _time_rcvd; blktime_t curtime; char *workid; // BIP 22: Long Polling struct blktmpl_longpoll_req lp; bool submitold; // BIP 23: Basic Pool Extensions int16_t expires; blkhash_t *target; // BIP 23: Mutations uint32_t mutations; blktime_t maxtime; blktime_diff_t maxtimeoff; blktime_t mintime; blktime_diff_t mintimeoff; blknonce_t minnonce; blknonce_t maxnonce; // TEMPORARY HACK libblkmaker_hash_t *_mrklbranch; int _mrklbranchcount; unsigned int next_dataid; unsigned aux_count; struct blkaux_t *auxs; } blktemplate_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 *); extern bool blktmpl_get_submitold(blktemplate_t *tmpl); extern void blktmpl_free(blktemplate_t *); #ifdef __cplusplus } #endif #endif libblkmaker-0.5.2/configure.ac000066400000000000000000000024611262003255700162700ustar00rootroot00000000000000dnl * Copyright 2012-2014 Luke Dashjr dnl * 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. AC_INIT( [libblkmaker], [0.5.2], [luke_libblkmaker@dashjr.org], [libblkmaker], [http://gitorious.org/bitcoin/libblkmaker]) AC_CONFIG_AUX_DIR([.]) AC_PREREQ([2.59]) AM_INIT_AUTOMAKE([1.11 -Wall dist-xz foreign]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AC_PROG_CC_C99 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], [6:2:0]) AC_SUBST([LIBBLKMAKER_API_VERSION], [0.1]) AC_CONFIG_FILES([Makefile libblkmaker_jansson-${LIBBLKMAKER_API_VERSION}.pc:libblkmaker_jansson.pc.in ]) PKG_CHECK_MODULES([JANSSON],[jansson],[ true ],[ AC_MSG_CHECKING([for jansson in system-default locations]) LIBS="$LIBS -ljansson" AC_TRY_LINK([ #include ],[ json_object(); ],[ AC_MSG_RESULT([found]) JANSSON_LIBS=-ljansson ],[ AC_MSG_RESULT([not found]) AC_MSG_ERROR([Could not find jansson library]) ]) LIBS="${save_LIBS}" ]) AC_SUBST(JANSSON_CFLAGS) AC_SUBST(JANSSON_LIBS) PKG_CHECK_MODULES([libbase58],[libbase58]) AC_CHECK_LIB([ws2_32], [strchr]) AC_OUTPUT libblkmaker-0.5.2/example.c000066400000000000000000000063131262003255700156010ustar00rootroot00000000000000/* * Copyright 2012 Luke Dashjr * * 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. */ #include #include #include #include #include #include #include #include #include "private.h" #include "testinput.c" void testb58() { int rv; const char *iaddr = "11Baf75Ferj6A7AoN565gCQj9kGWbDMHfN9"; const char *addr = &iaddr[1]; const size_t addrlen = strlen(addr); size_t actuallen; char bufx[26] = {'\xff'}; char *buf = &bufx[1]; actuallen = 25; if (!b58tobin(buf, &actuallen, addr, addrlen)) exit(1); if (bufx[0] != '\xff') exit(2); char cbuf[51]; _blkmk_bin2hex(cbuf, buf, 25); printf("Base58 raw data: %s\n", cbuf); assert((rv = b58check(buf, 25, addr, addrlen)) == 0); printf("Base58 check: %d\n", rv); assert((rv = b58check(buf, 25, &addr[1], addrlen)) < 0); printf("Base58 check (invalid/ unpadded): %d\n", rv); assert((rv = b58check(buf, 25, iaddr, addrlen + 1)) < 0); printf("Base58 check (invalid/extra padded): %d\n", rv); } static void send_json(json_t *req) { char *s = json_dumps(req, JSON_INDENT(2)); puts(s); free(s); } static bool my_sha256(void *digest, const void *buffer, size_t length) { gcry_md_hash_buffer(GCRY_MD_SHA256, digest, buffer, length); return true; } int main(int argc, char**argv) { blktemplate_t *tmpl; json_t *req; json_error_t jsone; const char *err; b58_sha256_impl = my_sha256; blkmk_sha256_impl = my_sha256; testb58(); tmpl = blktmpl_create(); assert(tmpl); req = blktmpl_request_jansson(blktmpl_addcaps(tmpl), NULL); assert(req); // send req to server and parse response into req send_json(req); json_decref(req); if (argc == 2) req = json_loadf(stdin, JSON_DISABLE_EOF_CHECK, &jsone); else { req = json_loads(blkmaker_test_input, 0, &jsone); send_json(req); } assert(req); err = blktmpl_add_jansson(tmpl, req, time(NULL)); json_decref(req); if (err) { fprintf(stderr, "Error adding block template: %s", err); assert(0 && "Error adding block template"); } while (blkmk_time_left(tmpl, time(NULL)) && blkmk_work_left(tmpl)) { unsigned char data[80], hash[32]; size_t datasz; unsigned int dataid; uint32_t nonce; datasz = blkmk_get_data(tmpl, data, sizeof(data), time(NULL), NULL, &dataid); assert(datasz >= 76 && datasz <= sizeof(data)); // mine the right nonce // this is iterating in native order, even though SHA256 is big endian, because we don't implement noncerange // however, the nonce is always interpreted as big endian, so we need to convert it as if it were big endian for (nonce = 0; nonce < 0xffffffff; ++nonce) { *(uint32_t*)(&data[76]) = nonce; assert(my_sha256(hash, data, 80)); assert(my_sha256(hash, hash, 32)); if (!*(uint32_t*)(&hash[28])) break; if (!(nonce % 0x1000)) { printf("0x%8" PRIx32 " hashes done...\r", nonce); fflush(stdout); } } printf("Found nonce: 0x%8" PRIx32 " \n", nonce); nonce = ntohl(nonce); req = blkmk_submit_jansson(tmpl, data, dataid, nonce); assert(req); // send req to server send_json(req); } blktmpl_free(tmpl); } libblkmaker-0.5.2/hex.c000066400000000000000000000022121262003255700147240ustar00rootroot00000000000000/* * Copyright 2012 Luke Dashjr * * 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. */ #include #include bool _blkmk_hex2bin(void *o, const char *x, size_t len) { unsigned char *oc = o; unsigned char c, hc = 0x10; len *= 2; while (len) { switch (x[0]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': c = x[0] - '0'; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': c = x[0] - 'A' + 10; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': c = x[0] - 'a' + 10; break; default: return false; } ++x; if (hc < 0x10) { (oc++)[0] = (hc << 4) | c; hc = 0x10; } else hc = c; --len; } return !x[0]; } void _blkmk_bin2hex(char *out, const void *data, size_t datasz) { const unsigned char *datac = data; static char hex[] = "0123456789abcdef"; out[datasz * 2] = '\0'; for (size_t i = 0; i < datasz; ++i) { out[ i*2 ] = hex[datac[i] >> 4]; out[(i*2)+1] = hex[datac[i] & 15]; } } libblkmaker-0.5.2/libblkmaker_jansson.pc.in000066400000000000000000000006061262003255700207440ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ 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@ Cflags: -I${includedir}/libblkmaker-@LIBBLKMAKER_API_VERSION@ Requires.private: libbase58 libblkmaker-0.5.2/private.h000066400000000000000000000014251262003255700156240ustar00rootroot00000000000000#ifndef BLKMK_PRIVATE_H #define BLKMK_PRIVATE_H #include #include #include // blkmaker.c 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_submission_(blktemplate_t *, const unsigned char *data, 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); // inline // NOTE: This must return 0 for 0 static inline int blkmk_flsl(unsigned long n) { int i; for (i = 0; n; ++i) n >>= 1; return i; } #endif libblkmaker-0.5.2/testinput.c000066400000000000000000000027461262003255700162130ustar00rootroot00000000000000/* * Written by Luke Dashjr in 2012 * * This data is released under the terms of the Creative Commons "CC0 1.0 Universal" license and/or copyright waiver. */ const char *blkmaker_test_input = "{" "\"result\": {" "\"previousblockhash\": \"000000004d424dec1c660a68456b8271d09628a80cc62583e5904f5894a2483c\"," "\"target\": \"00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"," "\"noncerange\": \"00000000ffffffff\"," "\"transactions\": []," "\"sigoplimit\": 20000," "\"expires\": 120," "\"longpoll\": \"/LP\"," "\"height\": 23957," "\"coinbasetxn\": {" "\"data\": \"" "01000000" // txn version "01" // txn in count "0000000000000000000000000000000000000000000000000000000000000000" // input coin "ffffffff" "13" "02955d0f00456c6967697573005047dc66085f" // scriptSig "ffffffff" // sequence "02" // tx out count "fff1052a01000000" // tx out #1 amount "19" "76a9144ebeb1cd26d6227635828d60d3e0ed7d0da248fb88ac" // tx out #1 scriptPubKey "0100000000000000" // tx out #2 amount "19" "76a9147c866aee1fa2f3b3d5effad576df3dbf1f07475588ac" // tx out #2 scriptPubKey "00000000" // lock time "\"" "}," "\"version\": 2," "\"curtime\": 1346886758," "\"mutable\": [\"coinbase/append\"]," "\"sizelimit\": 1000000," "\"bits\": \"ffff001d\"" "}," "\"id\": 0," "\"error\": null" "}" ;