├── test.sh ├── AUTHORS ├── autogen.sh ├── .gitignore ├── libblkmaker_jansson.pc.in ├── blkmaker_jansson.h ├── COPYING ├── README ├── hex.c ├── testinput.c ├── blkmaker.h ├── configure.ac ├── private.h ├── base58.c ├── Makefile.am ├── example.c ├── .travis.yml ├── blktemplate.c ├── blktemplate.h ├── blkmaker_jansson.c ├── blkmaker.c └── test.c /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # To avoid exit codes other than 0 or 1 3 | ./test || exit 1 4 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Luke Dashjr 2 | Andy Alness 3 | Huang Le <4tarhl@gmail.com> 4 | Cory Fields 5 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | # Written by Luke Dashjr in 2012 3 | # This program is released under the terms of the Creative Commons "CC0 1.0 Universal" license and/or copyright waiver. 4 | 5 | if test -z "$srcdir"; then 6 | srcdir=`dirname "$0"` 7 | if test -z "$srcdir"; then 8 | srcdir=. 9 | fi 10 | fi 11 | autoreconf --force --install --verbose "$srcdir" 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gcov 2 | *.gcda 3 | *.gcno 4 | vgcore* 5 | core* 6 | *.orig 7 | *.rej 8 | *~ 9 | *.so 10 | *.o 11 | a.* 12 | todo* 13 | example 14 | .*.kate-swp 15 | configure 16 | Makefile 17 | Makefile.in 18 | *.la 19 | *.pc 20 | ltmain.sh 21 | libtool 22 | install-sh 23 | missing 24 | depcomp 25 | .libs 26 | .deps 27 | aclocal.m4 28 | autom4te.cache 29 | *.lo 30 | config.* 31 | ii 32 | ar-lib 33 | compile 34 | test-driver 35 | test 36 | test-suite.log 37 | test.log 38 | test.trs 39 | -------------------------------------------------------------------------------- /libblkmaker_jansson.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: @PACKAGE_NAME@_jansson 7 | Description: Bitcoin block maker library. 8 | Version: @PACKAGE_VERSION@ 9 | URL: @PACKAGE_URL@ 10 | Libs: -L${libdir} -lblkmaker_jansson-@LIBBLKMAKER_API_VERSION@ -lblkmaker-@LIBBLKMAKER_API_VERSION@ 11 | Cflags: -I${includedir}/libblkmaker-@LIBBLKMAKER_API_VERSION@ 12 | Requires: jansson 13 | Requires.private: libbase58 14 | -------------------------------------------------------------------------------- /blkmaker_jansson.h: -------------------------------------------------------------------------------- 1 | #ifndef BLKMAKER_JANSSON_H 2 | #define BLKMAKER_JANSSON_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | extern json_t *blktmpl_request_jansson(uint32_t extracaps, const char *lpid); 13 | extern json_t *blktmpl_request_jansson2(uint32_t extracaps, const char *lpid, const char * const *rulelist); 14 | extern const char *blktmpl_add_jansson(blktemplate_t *, const json_t *, time_t time_rcvd); 15 | extern json_t *blktmpl_propose_jansson(blktemplate_t *, uint32_t caps, bool foreign); 16 | extern json_t *blkmk_submit_jansson(blktemplate_t *, const unsigned char *data, unsigned int dataid, blknonce_t); 17 | extern json_t *blkmk_submit_foreign_jansson(blktemplate_t *, const unsigned char *data, unsigned int dataid, blknonce_t); 18 | extern json_t *blkmk_submitm_jansson(blktemplate_t *, const unsigned char *data, const void *extranonce, size_t extranoncesz, blknonce_t, bool foreign); 19 | 20 | #ifdef __cplusplus 21 | } 22 | #endif 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright 2012-2014 Luke Dashjr 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Dependencies: 2 | Jansson 2.0 with 'long long' support 3 | 4 | Example dependencies: 5 | Jansson 2.1 (to read JSON from stdin) 6 | libgcrypt (for SHA256) 7 | 8 | For usage, check out example.c. Run "make example" to build it. 9 | 10 | Note that you must assign blkmk_sha256_impl to a function pointer: 11 | bool mysha256(void *hash_out, const void *data, size_t datasz) 12 | hash_out must be able to overlap with data! 13 | 14 | Also note that you should NOT roll ntime for data retrieved without explicitly 15 | checking that it falls within the template's limitations (mintime, maxtime, 16 | mintimeoff, and maxtimeoff); read the BIP 23 specification in detail to 17 | understand how they work. It is usually best to simply get more data as often 18 | as it is needed. For blkmk_get_mdata, you may specify that you intend to roll 19 | the ntime header exactly once per second past usetime - it will then set 20 | *out_expires such that the expiration occurs before you roll beyond any ntime 21 | limits. If you are rolling ntime at any rate other than once per second, you 22 | should NOT specify can_roll_ntime to blkmk_get_mdata, and must check that your 23 | usage falls within the explicit template limits yourself. 24 | -------------------------------------------------------------------------------- /hex.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Luke Dashjr 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the standard MIT license. See COPYING for more details. 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | 12 | bool _blkmk_hex2bin(void *o, const char *x, size_t len) { 13 | unsigned char *oc = o; 14 | unsigned char c, hc = 0x10; 15 | len *= 2; 16 | while (len) 17 | { 18 | switch (x[0]) { 19 | case '0': case '1': case '2': case '3': case '4': 20 | case '5': case '6': case '7': case '8': case '9': 21 | c = x[0] - '0'; 22 | break; 23 | case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': 24 | c = x[0] - 'A' + 10; 25 | break; 26 | case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 27 | c = x[0] - 'a' + 10; 28 | break; 29 | default: 30 | return false; 31 | } 32 | ++x; 33 | if (hc < 0x10) 34 | { 35 | (oc++)[0] = (hc << 4) | c; 36 | hc = 0x10; 37 | } 38 | else 39 | hc = c; 40 | --len; 41 | } 42 | return !x[0]; 43 | } 44 | 45 | void _blkmk_bin2hex(char *out, const void *data, size_t datasz) { 46 | const unsigned char *datac = data; 47 | static char hex[] = "0123456789abcdef"; 48 | out[datasz * 2] = '\0'; 49 | for (size_t i = 0; i < datasz; ++i) 50 | { 51 | out[ i*2 ] = hex[datac[i] >> 4]; 52 | out[(i*2)+1] = hex[datac[i] & 15]; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /testinput.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Written by Luke Dashjr in 2012 3 | * 4 | * This data is released under the terms of the Creative Commons "CC0 1.0 Universal" license and/or copyright waiver. 5 | */ 6 | 7 | const char *blkmaker_test_input = 8 | "{" 9 | "\"result\": {" 10 | "\"previousblockhash\": \"000000004d424dec1c660a68456b8271d09628a80cc62583e5904f5894a2483c\"," 11 | "\"target\": \"00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"," 12 | "\"noncerange\": \"00000000ffffffff\"," 13 | "\"transactions\": []," 14 | "\"sigoplimit\": 20000," 15 | "\"expires\": 120," 16 | "\"longpoll\": \"/LP\"," 17 | "\"height\": 23957," 18 | "\"coinbasetxn\": {" 19 | "\"data\": \"" 20 | "01000000" // txn version 21 | "01" // txn in count 22 | "0000000000000000000000000000000000000000000000000000000000000000" // input coin 23 | "ffffffff" 24 | "13" "02955d0f00456c6967697573005047dc66085f" // scriptSig 25 | "ffffffff" // sequence 26 | "02" // tx out count 27 | "fff1052a01000000" // tx out #1 amount 28 | "19" "76a9144ebeb1cd26d6227635828d60d3e0ed7d0da248fb88ac" // tx out #1 scriptPubKey 29 | "0100000000000000" // tx out #2 amount 30 | "19" "76a9147c866aee1fa2f3b3d5effad576df3dbf1f07475588ac" // tx out #2 scriptPubKey 31 | "00000000" // lock time 32 | "\"" 33 | "}," 34 | "\"version\": 2," 35 | "\"curtime\": 1346886758," 36 | "\"mutable\": [\"coinbase/append\"]," 37 | "\"sizelimit\": 1000000," 38 | "\"bits\": \"ffff001d\"" 39 | "}," 40 | "\"id\": 0," 41 | "\"error\": null" 42 | "}" 43 | ; -------------------------------------------------------------------------------- /blkmaker.h: -------------------------------------------------------------------------------- 1 | #ifndef BLKMAKER_H 2 | #define BLKMAKER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | #define BLKMAKER_VERSION (8L) 15 | #define BLKMAKER_MAX_BLOCK_VERSION (0x3fffffff) 16 | #define BLKMAKER_MAX_PRERULES_BLOCK_VERSION (4) 17 | 18 | extern const char *blkmk_supported_rules[]; 19 | extern bool blkmk_supports_rule(const char *rulename); 20 | 21 | extern bool (*blkmk_sha256_impl)(void *hash_out, const void *data, size_t datasz); 22 | 23 | extern uint64_t blkmk_init_generation(blktemplate_t *, void *script, size_t scriptsz); 24 | extern uint64_t blkmk_init_generation2(blktemplate_t *, void *script, size_t scriptsz, bool *out_newcb); 25 | extern uint64_t blkmk_init_generation3(blktemplate_t *, const void *script, size_t scriptsz, bool *inout_newcb); 26 | extern ssize_t blkmk_append_coinbase_safe(blktemplate_t *, const void *append, size_t appendsz); 27 | extern ssize_t blkmk_append_coinbase_safe2(blktemplate_t *, const void *append, size_t appendsz, int extranoncesz, bool merkle_only); 28 | extern bool _blkmk_extranonce(blktemplate_t *tmpl, void *vout, unsigned int workid, size_t *offs); 29 | extern size_t blkmk_get_data(blktemplate_t *, void *buf, size_t bufsz, time_t usetime, int16_t *out_expire, unsigned int *out_dataid); 30 | 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); 31 | extern blktime_diff_t blkmk_time_left(const blktemplate_t *, time_t nowtime); 32 | extern unsigned long blkmk_work_left(const blktemplate_t *); 33 | #define BLKMK_UNLIMITED_WORK_COUNT ULONG_MAX 34 | 35 | extern size_t blkmk_address_to_script(void *out, size_t outsz, const char *addr); 36 | 37 | #ifdef __cplusplus 38 | } 39 | #endif 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | dnl * Copyright 2012-2014 Luke Dashjr 2 | dnl * 3 | dnl * This program is free software; you can redistribute it and/or modify it 4 | dnl * under the terms of the standard MIT license. See COPYING for more details. 5 | 6 | AC_INIT( 7 | [libblkmaker], 8 | [0.6.0], 9 | [luke_libblkmaker@dashjr.org], 10 | [libblkmaker], 11 | [http://gitorious.org/bitcoin/libblkmaker]) 12 | AC_CONFIG_AUX_DIR([.]) 13 | AC_PREREQ([2.59]) 14 | AM_INIT_AUTOMAKE([1.11 -Wall dist-xz foreign]) 15 | m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) 16 | 17 | AC_PROG_CC_C99 18 | m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) 19 | LT_INIT([disable-static]) 20 | 21 | # http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html 22 | AC_SUBST([LIBBLKMAKER_SO_VERSION], [8:0:0]) 23 | AC_SUBST([LIBBLKMAKER_API_VERSION], [0.1]) 24 | 25 | AC_CONFIG_FILES([Makefile 26 | libblkmaker_jansson-${LIBBLKMAKER_API_VERSION}.pc:libblkmaker_jansson.pc.in 27 | ]) 28 | 29 | PKG_CHECK_MODULES([JANSSON],[jansson],[ 30 | true 31 | ],[ 32 | AC_MSG_CHECKING([for jansson in system-default locations]) 33 | LIBS="$LIBS -ljansson" 34 | AC_TRY_LINK([ 35 | #include 36 | ],[ 37 | json_object(); 38 | ],[ 39 | AC_MSG_RESULT([found]) 40 | JANSSON_LIBS=-ljansson 41 | ],[ 42 | AC_MSG_RESULT([not found]) 43 | AC_MSG_ERROR([Could not find jansson library]) 44 | ]) 45 | LIBS="${save_LIBS}" 46 | ]) 47 | AC_SUBST(JANSSON_CFLAGS) 48 | AC_SUBST(JANSSON_LIBS) 49 | 50 | PKG_CHECK_MODULES([libbase58],[libbase58]) 51 | 52 | AC_CHECK_LIB([ws2_32], [strchr]) 53 | 54 | dnl libgcrypt necessary to build tests and example 55 | dnl check for libgcrypt: 56 | m4_ifdef([AM_PATH_LIBGCRYPT], [ 57 | AM_PATH_LIBGCRYPT([], 58 | [ 59 | have_libgcrypt=yes 60 | ],[ 61 | have_libgcrypt=no 62 | ]) 63 | ],[ 64 | m4_warn([syntax], [AM_PATH_LIBGCRYPT missing; example and tests will not be available]) 65 | ]) 66 | AM_CONDITIONAL([HAVE_LIBGCRYPT], [test x$have_libgcrypt = xyes]) 67 | 68 | AC_OUTPUT 69 | -------------------------------------------------------------------------------- /private.h: -------------------------------------------------------------------------------- 1 | #ifndef BLKMK_PRIVATE_H 2 | #define BLKMK_PRIVATE_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | // blkmaker.c 10 | extern bool _blkmk_dblsha256(void *hash, const void *data, size_t datasz); 11 | extern bool blkmk_sample_data_(blktemplate_t *, uint8_t *, unsigned int dataid); 12 | 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); 13 | 14 | // hex.c 15 | extern void _blkmk_bin2hex(char *out, const void *data, size_t datasz); 16 | extern bool _blkmk_hex2bin(void *o, const char *x, size_t len); 17 | 18 | // inline 19 | 20 | // NOTE: This must return 0 for 0 21 | static inline 22 | int blkmk_flsl(unsigned long n) 23 | { 24 | int i; 25 | for (i = 0; n; ++i) 26 | n >>= 1; 27 | return i; 28 | } 29 | 30 | static inline 31 | uint16_t upk_u16le(const void * const bufp, const int offset) 32 | { 33 | const uint8_t * const buf = bufp; 34 | return (((uint16_t)buf[offset+0]) << 0) 35 | | (((uint16_t)buf[offset+1]) << 8); 36 | } 37 | 38 | static inline 39 | uint32_t upk_u32le(const void * const bufp, const int offset) 40 | { 41 | const uint8_t * const buf = bufp; 42 | return (((uint32_t)buf[offset+0]) << 0) 43 | | (((uint32_t)buf[offset+1]) << 8) 44 | | (((uint32_t)buf[offset+2]) << 0x10) 45 | | (((uint32_t)buf[offset+3]) << 0x18); 46 | } 47 | 48 | static inline 49 | uint64_t upk_u64le(const void * const bufp, const int offset) 50 | { 51 | const uint8_t * const buf = bufp; 52 | return (((uint64_t)buf[offset+0]) << 0) 53 | | (((uint64_t)buf[offset+1]) << 8) 54 | | (((uint64_t)buf[offset+2]) << 0x10) 55 | | (((uint64_t)buf[offset+3]) << 0x18) 56 | | (((uint64_t)buf[offset+4]) << 0x20) 57 | | (((uint64_t)buf[offset+5]) << 0x28) 58 | | (((uint64_t)buf[offset+6]) << 0x30) 59 | | (((uint64_t)buf[offset+7]) << 0x38); 60 | } 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /base58.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Luke Dashjr 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the standard MIT license. See COPYING for more details. 6 | */ 7 | 8 | #ifndef WIN32 9 | #include 10 | #else 11 | #include 12 | #endif 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | #include 21 | 22 | #include "private.h" 23 | 24 | bool _blkmk_b58tobin(void *bin, size_t binsz, const char *b58, size_t b58sz) { 25 | return b58tobin(bin, &binsz, b58, b58sz); 26 | } 27 | 28 | int _blkmk_b58check(void *bin, size_t binsz, const char *base58str) { 29 | if (!b58_sha256_impl) 30 | b58_sha256_impl = blkmk_sha256_impl; 31 | return b58check(bin, binsz, base58str, 34); 32 | } 33 | 34 | size_t blkmk_address_to_script(void *out, size_t outsz, const char *addr) { 35 | unsigned char addrbin[25]; 36 | unsigned char *cout = out; 37 | const size_t b58sz = strlen(addr); 38 | int addrver; 39 | size_t rv; 40 | 41 | rv = sizeof(addrbin); 42 | if (!b58_sha256_impl) 43 | b58_sha256_impl = blkmk_sha256_impl; 44 | if (!b58tobin(addrbin, &rv, addr, b58sz)) 45 | return 0; 46 | addrver = b58check(addrbin, sizeof(addrbin), addr, b58sz); 47 | switch (addrver) { 48 | case 0: // Bitcoin pubkey hash 49 | case 111: // Testnet pubkey hash 50 | if (outsz < (rv = 25)) 51 | return rv; 52 | cout[ 0] = 0x76; // OP_DUP 53 | cout[ 1] = 0xa9; // OP_HASH160 54 | cout[ 2] = 0x14; // push 20 bytes 55 | memcpy(&cout[3], &addrbin[1], 20); 56 | cout[23] = 0x88; // OP_EQUALVERIFY 57 | cout[24] = 0xac; // OP_CHECKSIG 58 | return rv; 59 | case 5: // Bitcoin script hash 60 | case 196: // Testnet script hash 61 | if (outsz < (rv = 23)) 62 | return rv; 63 | cout[ 0] = 0xa9; // OP_HASH160 64 | cout[ 1] = 0x14; // push 20 bytes 65 | memcpy(&cout[2], &addrbin[1], 20); 66 | cout[22] = 0x87; // OP_EQUAL 67 | return rv; 68 | default: 69 | return 0; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # Copyright 2012-2013 Luke Dashjr 2 | # 3 | # This program is free software; you can redistribute it and/or modify it 4 | # under the terms of the standard MIT license. See COPYING for more details. 5 | 6 | lib_LTLIBRARIES = \ 7 | libblkmaker_jansson-@LIBBLKMAKER_API_VERSION@.la \ 8 | libblkmaker-@LIBBLKMAKER_API_VERSION@.la 9 | 10 | 11 | libblkmaker_@LIBBLKMAKER_API_VERSION@_la_SOURCES = \ 12 | base58.c \ 13 | blkmaker.c \ 14 | blktemplate.c \ 15 | hex.c \ 16 | private.h 17 | 18 | libblkmaker_@LIBBLKMAKER_API_VERSION@_la_CFLAGS = \ 19 | $(libbase58_CFLAGS) 20 | libblkmaker_@LIBBLKMAKER_API_VERSION@_la_LDFLAGS = \ 21 | $(libbase58_LIBS) \ 22 | -no-undefined \ 23 | -version-info $(LIBBLKMAKER_SO_VERSION) 24 | 25 | libblkmaker_includedir = $(includedir)/libblkmaker-$(LIBBLKMAKER_API_VERSION) 26 | libblkmaker_include_HEADERS = \ 27 | blkmaker.h \ 28 | blktemplate.h 29 | 30 | libblkmaker_jansson_@LIBBLKMAKER_API_VERSION@_la_SOURCES = blkmaker_jansson.c 31 | libblkmaker_jansson_@LIBBLKMAKER_API_VERSION@_la_DEPENDENCIES = libblkmaker-$(LIBBLKMAKER_API_VERSION).la 32 | libblkmaker_jansson_@LIBBLKMAKER_API_VERSION@_la_CFLAGS = $(JANSSON_CFLAGS) 33 | libblkmaker_jansson_@LIBBLKMAKER_API_VERSION@_la_LDFLAGS = \ 34 | -L.libs \ 35 | -lblkmaker-$(LIBBLKMAKER_API_VERSION) \ 36 | $(JANSSON_LIBS) \ 37 | -no-undefined \ 38 | -version-info $(LIBBLKMAKER_SO_VERSION) 39 | 40 | libblkmaker_jansson_includedir = $(includedir)/libblkmaker-$(LIBBLKMAKER_API_VERSION) 41 | libblkmaker_jansson_include_HEADERS = \ 42 | blkmaker_jansson.h 43 | 44 | pkgconfigdir = $(libdir)/pkgconfig 45 | pkgconfig_DATA = \ 46 | libblkmaker_jansson-$(LIBBLKMAKER_API_VERSION).pc 47 | 48 | dist_noinst_SCRIPTS = autogen.sh test.sh 49 | dist_noinst_DATA = \ 50 | AUTHORS COPYING README \ 51 | example.c \ 52 | testinput.c 53 | 54 | if HAVE_LIBGCRYPT 55 | check_PROGRAMS = test 56 | test_SOURCES = test.c 57 | test_CFLAGS = $(libbase58_CFLAGS) $(JANSSON_CFLAGS) $(LIBGCRYPT_CFLAGS) 58 | test_LDADD = $(libbase58_LIBS) libblkmaker-@LIBBLKMAKER_API_VERSION@.la libblkmaker_jansson-@LIBBLKMAKER_API_VERSION@.la $(JANSSON_LIBS) $(LIBGCRYPT_LIBS) 59 | TESTS = test.sh 60 | 61 | EXTRA_PROGRAMS = example 62 | example_SOURCES = example.c 63 | example_CFLAGS = $(libbase58_CFLAGS) $(JANSSON_CFLAGS) $(LIBGCRYPT_CFLAGS) 64 | example_LDADD = $(libbase58_LIBS) libblkmaker-@LIBBLKMAKER_API_VERSION@.la libblkmaker_jansson-@LIBBLKMAKER_API_VERSION@.la $(JANSSON_LIBS) $(LIBGCRYPT_LIBS) 65 | else 66 | example: 67 | @echo "libgcrypt is required to build the example, but was not found" 68 | .PHONY: example 69 | endif 70 | -------------------------------------------------------------------------------- /example.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Luke Dashjr 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the standard MIT license. See COPYING for more details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #ifndef WIN32 13 | #include 14 | #else 15 | #include 16 | #endif 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | #include "private.h" 25 | #include "testinput.c" 26 | 27 | void testb58() { 28 | int rv; 29 | const char *iaddr = "11Baf75Ferj6A7AoN565gCQj9kGWbDMHfN9"; 30 | const char *addr = &iaddr[1]; 31 | const size_t addrlen = strlen(addr); 32 | size_t actuallen; 33 | char bufx[26] = {'\xff'}; 34 | char *buf = &bufx[1]; 35 | actuallen = 25; 36 | if (!b58tobin(buf, &actuallen, addr, addrlen)) 37 | exit(1); 38 | if (bufx[0] != '\xff') 39 | exit(2); 40 | char cbuf[51]; 41 | _blkmk_bin2hex(cbuf, buf, 25); 42 | printf("Base58 raw data: %s\n", cbuf); 43 | assert((rv = b58check(buf, 25, addr, addrlen)) == 0); 44 | printf("Base58 check: %d\n", rv); 45 | assert((rv = b58check(buf, 25, &addr[1], addrlen)) < 0); 46 | printf("Base58 check (invalid/ unpadded): %d\n", rv); 47 | assert((rv = b58check(buf, 25, iaddr, addrlen + 1)) < 0); 48 | printf("Base58 check (invalid/extra padded): %d\n", rv); 49 | } 50 | 51 | static 52 | void send_json(json_t *req) { 53 | char *s = json_dumps(req, JSON_INDENT(2)); 54 | puts(s); 55 | free(s); 56 | } 57 | 58 | static 59 | bool my_sha256(void *digest, const void *buffer, size_t length) { 60 | gcry_md_hash_buffer(GCRY_MD_SHA256, digest, buffer, length); 61 | return true; 62 | } 63 | 64 | int main(int argc, char**argv) { 65 | blktemplate_t *tmpl; 66 | json_t *req; 67 | json_error_t jsone; 68 | const char *err; 69 | 70 | b58_sha256_impl = my_sha256; 71 | blkmk_sha256_impl = my_sha256; 72 | 73 | testb58(); 74 | 75 | tmpl = blktmpl_create(); 76 | assert(tmpl); 77 | req = blktmpl_request_jansson(blktmpl_addcaps(tmpl), NULL); 78 | assert(req); 79 | 80 | // send req to server and parse response into req 81 | send_json(req); 82 | json_decref(req); 83 | if (argc == 2) 84 | req = json_loadf(stdin, JSON_DISABLE_EOF_CHECK, &jsone); 85 | else 86 | { 87 | req = json_loads(blkmaker_test_input, 0, &jsone); 88 | send_json(req); 89 | } 90 | assert(req); 91 | 92 | err = blktmpl_add_jansson(tmpl, req, time(NULL)); 93 | json_decref(req); 94 | if (err) 95 | { 96 | fprintf(stderr, "Error adding block template: %s", err); 97 | assert(0 && "Error adding block template"); 98 | } 99 | while (blkmk_time_left(tmpl, time(NULL)) && blkmk_work_left(tmpl)) 100 | { 101 | unsigned char data[80], hash[32]; 102 | size_t datasz; 103 | unsigned int dataid; 104 | uint32_t nonce; 105 | 106 | datasz = blkmk_get_data(tmpl, data, sizeof(data), time(NULL), NULL, &dataid); 107 | assert(datasz >= 76 && datasz <= sizeof(data)); 108 | 109 | // mine the right nonce 110 | // this is iterating in native order, even though SHA256 is big endian, because we don't implement noncerange 111 | // however, the nonce is always interpreted as big endian, so we need to convert it as if it were big endian 112 | for (nonce = 0; nonce < 0xffffffff; ++nonce) 113 | { 114 | *(uint32_t*)(&data[76]) = nonce; 115 | assert(my_sha256(hash, data, 80)); 116 | assert(my_sha256(hash, hash, 32)); 117 | if (!*(uint32_t*)(&hash[28])) 118 | break; 119 | if (!(nonce % 0x1000)) 120 | { 121 | printf("0x%8" PRIx32 " hashes done...\r", nonce); 122 | fflush(stdout); 123 | } 124 | } 125 | printf("Found nonce: 0x%8" PRIx32 " \n", nonce); 126 | nonce = ntohl(nonce); 127 | 128 | req = blkmk_submit_jansson(tmpl, data, dataid, nonce); 129 | assert(req); 130 | // send req to server 131 | send_json(req); 132 | } 133 | blktmpl_free(tmpl); 134 | return 0; 135 | } 136 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: linux 2 | language: c 3 | compiler: gcc 4 | sudo: false 5 | env: 6 | global: 7 | - PKG_CONFIG_LIBDIR="$HOME/lib/pkgconfig" 8 | - OPTS="--prefix=$HOME" 9 | matrix: 10 | include: 11 | # Normal build 12 | - addons: 13 | apt: 14 | packages: 15 | - build-essential 16 | - libjansson-dev 17 | - libgcrypt11-dev 18 | env: CFLAGS="-Wall" AM_CFLAGS='-Werror' 19 | # clang 20 | - compiler: clang 21 | addons: 22 | apt: 23 | packages: 24 | - build-essential 25 | - libjansson-dev 26 | - libgcrypt11-dev 27 | env: CFLAGS="-Wall -fsanitize=undefined -fno-sanitize-recover -fsanitize=address" 28 | # w/o libgcrypt 29 | - addons: 30 | apt: 31 | packages: 32 | - build-essential 33 | - libjansson-dev 34 | # Win32 35 | - addons: 36 | apt: 37 | packages: 38 | - gcc-mingw-w64-i686 39 | - binutils-mingw-w64-i686 40 | - mingw-w64-dev 41 | - wine 42 | env: 43 | - CROSS_TARGET=i686-w64-mingw32 44 | EXEEXT=.exe 45 | BUILD_LIBS=1 46 | WINE_TESTS=1 47 | OPTS="$OPTS --disable-static" 48 | JANSSON_VERSION=v2.4 49 | # Win64 50 | - addons: 51 | apt: 52 | packages: 53 | - gcc-mingw-w64-x86-64 54 | - binutils-mingw-w64-x86-64 55 | - mingw-w64-dev 56 | - wine 57 | env: 58 | - CROSS_TARGET=x86_64-w64-mingw32 59 | EXEEXT=.exe 60 | BUILD_LIBS=1 61 | WINE_TESTS=1 62 | OPTS="$OPTS --disable-static" 63 | JANSSON_VERSION=v2.4 64 | exclude: 65 | - compiler: gcc 66 | # TODO: Linux32 (or 64) & OS X 67 | script: 68 | - if [ -n "$CROSS_TARGET" ]; then 69 | unset CC; 70 | TARGET_OPTS="$TARGET_OPTS --host=$CROSS_TARGET"; 71 | fi 72 | - if [ -n "$BUILD_LIBS" ]; then 73 | OPTS="$OPTS --with-gpg-error-prefix=$HOME"; 74 | git clone git://git.gnupg.org/libgpg-error.git -b libgpg-error-1.13 --depth 1; 75 | pushd libgpg-error; 76 | ./autogen.sh; 77 | ./configure $TARGET_OPTS $OPTS --disable-languages --disable-doc; 78 | make; 79 | if [ -z "$WINE_TESTS" ]; then 80 | LD_LIBRARY_PATH="$HOME/lib" make check; 81 | fi; 82 | make install; 83 | popd; 84 | OPTS="$OPTS --with-libgcrypt-prefix=$HOME"; 85 | git clone git://git.gnupg.org/libgcrypt.git -b libgcrypt-1.5.4 --depth 1; 86 | pushd libgcrypt; 87 | ./autogen.sh; 88 | ./configure $TARGET_OPTS $OPTS --disable-ciphers --disable-pubkey-ciphers --disable-random --disable-asm; 89 | make; 90 | if [ -z "$WINE_TESTS" ]; then 91 | LD_LIBRARY_PATH="$HOME/lib" make check; 92 | fi; 93 | make install; 94 | popd; 95 | 96 | git clone https://github.com/akheron/jansson.git -b "$JANSSON_VERSION" --depth 1; 97 | pushd jansson; 98 | autoreconf -f -i; 99 | ./configure $TARGET_OPTS $OPTS; 100 | make AM_CFLAGS= ; 101 | if [ -z "$WINE_TESTS" ]; then 102 | LD_LIBRARY_PATH="$HOME/lib" make check; 103 | fi; 104 | make install; 105 | popd; 106 | fi 107 | - git clone git://github.com/bitcoin/libbase58 -b v0.1.4 --depth 1 108 | - pushd libbase58 109 | - ./autogen.sh 110 | - ./configure $TARGET_OPTS $OPTS 111 | - make 112 | - if [ -z "$WINE_TESTS" ]; then 113 | LD_LIBRARY_PATH="$HOME/lib" make check VERBOSE=1; 114 | fi 115 | - make install 116 | - popd 117 | - 118 | - ./autogen.sh 119 | - ./configure $TARGET_OPTS $OPTS $CONFIGURE_OPTS || { tail -n 1000 config.log; false; }; 120 | - make 121 | - make example$EXEEXT 122 | - make test$EXEEXT 123 | - if [ -z "$WINE_TESTS" ]; then 124 | LSAN_OPTIONS=1 LD_LIBRARY_PATH="$HOME/lib" make check VERBOSE=1; 125 | else 126 | ln -s $HOME/bin/*.dll .libs/; 127 | LSAN_OPTIONS=1 WINEDLLPATH="$PWD/.libs" wine .libs/test.exe; 128 | fi 129 | - make install 130 | -------------------------------------------------------------------------------- /blktemplate.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2016 Luke Dashjr 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the standard MIT license. See COPYING for more details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | static const char *capnames[] = { 18 | "coinbasetxn", 19 | "coinbasevalue", 20 | "workid", 21 | 22 | "longpoll", 23 | "proposal", 24 | "serverlist", 25 | NULL, NULL, 26 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 27 | 28 | "coinbase/append", 29 | "coinbase", 30 | "generation", 31 | "time/increment", 32 | "time/decrement", 33 | "transactions/add", 34 | "prevblock", 35 | "version/force", 36 | "version/reduce", 37 | 38 | "submit/hash", 39 | "submit/coinbase", 40 | "submit/truncate", 41 | "share/coinbase", 42 | "share/merkle", 43 | "share/truncate", 44 | }; 45 | 46 | const char *blktmpl_capabilityname(gbt_capabilities_t caps) { 47 | for (unsigned int i = 0; i < GBT_CAPABILITY_COUNT; ++i) 48 | if (caps & (1 << i)) 49 | return capnames[i]; 50 | return NULL; 51 | } 52 | 53 | uint32_t blktmpl_getcapability(const char *n) { 54 | for (unsigned int i = 0; i < GBT_CAPABILITY_COUNT; ++i) 55 | if (capnames[i] && !strcasecmp(n, capnames[i])) 56 | return ((uint32_t)1) << i; 57 | if (!strcasecmp(n, "time")) { 58 | // multi-capability 59 | return BMM_TIMEINC | BMM_TIMEDEC; 60 | } 61 | if (!strcasecmp(n, "transactions")) 62 | return BMM_TXNADD; // Odd one as it's overloaded w/"transactions/add" per spec 63 | return 0; 64 | } 65 | 66 | void blktxn_init(struct blktxn_t * const txn) { 67 | txn->data = NULL; 68 | txn->datasz = 0; 69 | txn->hash = NULL; 70 | txn->hash_ = NULL; 71 | txn->txid = NULL; 72 | 73 | txn->dependscount = -1; 74 | txn->depends = NULL; 75 | 76 | txn->fee_ = -1; 77 | txn->required = false; 78 | txn->sigops_ = -1; 79 | txn->weight = -1; 80 | } 81 | 82 | blktemplate_t *blktmpl_create() { 83 | blktemplate_t *tmpl; 84 | tmpl = calloc(1, sizeof(*tmpl)); 85 | if (!tmpl) 86 | return NULL; 87 | 88 | tmpl->sigoplimit = USHRT_MAX; 89 | tmpl->sizelimit = ULONG_MAX; 90 | tmpl->weightlimit = INT64_MAX; 91 | 92 | tmpl->maxtime = 0xffffffff; 93 | tmpl->maxtimeoff = 0x7fff; 94 | tmpl->mintimeoff = -0x7fff; 95 | tmpl->expires = 0x7fff; 96 | 97 | return tmpl; 98 | } 99 | 100 | uint32_t blktmpl_addcaps(const blktemplate_t *tmpl) { 101 | // TODO: make this a lot more flexible for merging 102 | // For now, it's a simple "filled" vs "not filled" 103 | if (tmpl->version) 104 | return 0; 105 | return GBT_CBTXN | GBT_WORKID | BMM_TIMEINC | BMM_CBAPPEND | BMM_VERFORCE | BMM_VERDROP | BMAb_COINBASE | BMAb_TRUNCATE; 106 | } 107 | 108 | const struct blktmpl_longpoll_req *blktmpl_get_longpoll(blktemplate_t *tmpl) { 109 | if (!tmpl->lp.id) 110 | return NULL; 111 | return &tmpl->lp; 112 | } 113 | 114 | bool blktmpl_get_submitold(blktemplate_t *tmpl) { 115 | return tmpl->submitold; 116 | } 117 | 118 | void blktxn_clean(struct blktxn_t * const bt) { 119 | free(bt->data); 120 | free(bt->hash); 121 | free(bt->hash_); 122 | free(bt->depends); 123 | free(bt->txid); 124 | } 125 | 126 | static 127 | void blkaux_clean(struct blkaux_t * const aux) { 128 | free(aux->auxname); 129 | free(aux->data); 130 | } 131 | 132 | void blktmpl_free(blktemplate_t *tmpl) { 133 | for (unsigned long i = 0; i < tmpl->txncount; ++i) 134 | blktxn_clean(&tmpl->txns[i]); 135 | free(tmpl->txns); 136 | if (tmpl->cbtxn) 137 | { 138 | blktxn_clean(tmpl->cbtxn); 139 | free(tmpl->cbtxn); 140 | } 141 | free(tmpl->_mrklbranch); 142 | free(tmpl->_witnessmrklroot); 143 | for (unsigned i = 0; i < tmpl->aux_count; ++i) 144 | blkaux_clean(&tmpl->auxs[i]); 145 | free(tmpl->auxs); 146 | free(tmpl->workid); 147 | free(tmpl->target); 148 | free(tmpl->lp.id); 149 | free(tmpl->lp.uri); 150 | 151 | if (tmpl->rules) { 152 | for (char **currule = tmpl->rules; *currule; ++currule) { 153 | free(*currule); 154 | } 155 | free(tmpl->rules); 156 | } 157 | if (tmpl->vbavailable) { 158 | for (struct blktmpl_vbassoc **curvb = tmpl->vbavailable; *curvb; ++curvb) { 159 | free((*curvb)->name); 160 | free(*curvb); 161 | } 162 | free(tmpl->vbavailable); 163 | } 164 | 165 | free(tmpl); 166 | } 167 | -------------------------------------------------------------------------------- /blktemplate.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2016 Luke Dashjr 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the standard MIT license. See COPYING for more details. 6 | */ 7 | 8 | #ifndef BLKTEMPLATE_H 9 | #define BLKTEMPLATE_H 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | typedef uint32_t blkheight_t; 20 | typedef uint32_t libblkmaker_hash_t[8]; 21 | typedef libblkmaker_hash_t blkhash_t; 22 | typedef libblkmaker_hash_t txnhash_t; 23 | typedef uint32_t blktime_t; 24 | typedef int16_t blktime_diff_t; 25 | typedef uint32_t blknonce_t; 26 | 27 | #define libblkmaker_blkheader_size (80) 28 | #define libblkmaker_coinbase_size_minimum (4) 29 | #define libblkmaker_coinbase_size_limit (100) 30 | 31 | struct blktxn_t { 32 | unsigned char *data; 33 | size_t datasz; 34 | // NOTE: The byte order of hash is backward; use hash_ instead 35 | txnhash_t *hash; 36 | 37 | signed long dependscount; 38 | unsigned long *depends; 39 | 40 | int64_t fee_; 41 | bool required; 42 | int16_t sigops_; 43 | int32_t weight; 44 | 45 | txnhash_t *hash_; 46 | txnhash_t *txid; 47 | }; 48 | 49 | struct blkaux_t { 50 | char *auxname; 51 | unsigned char *data; 52 | uint8_t datasz; 53 | }; 54 | 55 | // BIP 23: Long Polling 56 | struct blktmpl_longpoll_req { 57 | char *id; 58 | char *uri; 59 | }; 60 | 61 | 62 | typedef enum { 63 | GBT_CBTXN = 1 << 0, 64 | GBT_CBVALUE = 1 << 1, 65 | GBT_WORKID = 1 << 2, 66 | 67 | GBT_LONGPOLL = 1 << 3, // BIP 22: Long Polling 68 | GBT_PROPOSAL = 1 << 4, // BIP 23: Block Proposal 69 | GBT_SERVICE = 1 << 5, // BIP 23: Logical Services 70 | 71 | // BIP 23: Mutations 72 | BMM_CBAPPEND = 1 << 0x10, 73 | BMM_CBSET = 1 << 0x11, 74 | BMM_GENERATE = 1 << 0x12, 75 | BMM_TIMEINC = 1 << 0x13, 76 | BMM_TIMEDEC = 1 << 0x14, 77 | BMM_TXNADD = 1 << 0x15, 78 | BMM_PREVBLK = 1 << 0x16, 79 | BMM_VERFORCE = 1 << 0x17, 80 | BMM_VERDROP = 1 << 0x18, 81 | 82 | // BIP 23: Submission Abbreviation 83 | BMA_TXNHASH = 1 << 0x19, 84 | BMAb_COINBASE = 1 << 0x1a, 85 | BMAb_TRUNCATE = 1 << 0x1b, 86 | BMAs_COINBASE = 1 << 0x1c, 87 | BMAs_MERKLE = 1 << 0x1d, 88 | BMAs_TRUNCATE = 1 << 0x1e, 89 | } gbt_capabilities_t; 90 | #define GBT_CAPABILITY_COUNT (0x1f) 91 | 92 | extern const char *blktmpl_capabilityname(gbt_capabilities_t); 93 | #define BLKTMPL_LONGEST_CAPABILITY_NAME (16) 94 | // NOTE: blktmpl_getcapability("time") yields a combination of gbt_capabilities_t 95 | extern uint32_t blktmpl_getcapability(const char *); 96 | 97 | 98 | typedef gbt_capabilities_t blkmutations_t; 99 | 100 | struct blktmpl_vbassoc { 101 | char *name; 102 | uint8_t bitnum; 103 | }; 104 | 105 | // WARNING: Do not allocate this (ABI is not guaranteed to remain fixed-size) 106 | typedef struct { 107 | uint32_t version; 108 | unsigned char diffbits[4]; 109 | blkheight_t height; 110 | blkhash_t prevblk; 111 | 112 | unsigned short sigoplimit; 113 | unsigned long sizelimit; 114 | 115 | unsigned long txncount; 116 | struct blktxn_t *txns; 117 | struct blktxn_t *cbtxn; 118 | uint64_t cbvalue; 119 | 120 | time_t _time_rcvd; 121 | blktime_t curtime; 122 | 123 | char *workid; 124 | 125 | // BIP 22: Long Polling 126 | struct blktmpl_longpoll_req lp; 127 | bool submitold; 128 | 129 | // BIP 23: Basic Pool Extensions 130 | int16_t expires; 131 | blkhash_t *target; 132 | 133 | // BIP 23: Mutations 134 | uint32_t mutations; 135 | blktime_t maxtime; 136 | blktime_diff_t maxtimeoff; 137 | blktime_t mintime; 138 | blktime_diff_t mintimeoff; 139 | 140 | // TEMPORARY HACK 141 | libblkmaker_hash_t *_mrklbranch; 142 | int _mrklbranchcount; 143 | unsigned int next_dataid; 144 | 145 | unsigned aux_count; 146 | struct blkaux_t *auxs; 147 | 148 | unsigned long txns_datasz; 149 | signed long txns_sigops; 150 | 151 | char **rules; 152 | bool unsupported_rule; 153 | struct blktmpl_vbassoc **vbavailable; 154 | uint32_t vbrequired; 155 | 156 | bool _bip141_sigops; 157 | bool _calculated_witness; 158 | libblkmaker_hash_t *_witnessmrklroot; 159 | int64_t weightlimit; 160 | int64_t txns_weight; 161 | 162 | bool has_cbvalue; 163 | } blktemplate_t; 164 | 165 | extern void blktxn_init(struct blktxn_t *); 166 | extern void blktxn_clean(struct blktxn_t *); 167 | 168 | extern blktemplate_t *blktmpl_create(); 169 | extern uint32_t blktmpl_addcaps(const blktemplate_t *); 170 | extern const struct blktmpl_longpoll_req *blktmpl_get_longpoll(blktemplate_t *); 171 | extern bool blktmpl_get_submitold(blktemplate_t *tmpl); 172 | extern void blktmpl_free(blktemplate_t *); 173 | 174 | #ifdef __cplusplus 175 | } 176 | #endif 177 | 178 | #endif 179 | -------------------------------------------------------------------------------- /blkmaker_jansson.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2016 Luke Dashjr 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the standard MIT license. See COPYING for more details. 6 | */ 7 | 8 | #define _BSD_SOURCE 9 | #define _DEFAULT_SOURCE 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #include 19 | #include 20 | 21 | #include "private.h" 22 | 23 | #ifndef JSON_INTEGER_IS_LONG_LONG 24 | # error "Jansson 2.0 with long long support required!" 25 | #endif 26 | 27 | json_t *blktmpl_request_jansson2(const uint32_t caps, const char * const lpid, const char * const * const rulelist) { 28 | json_t *req, *jcaps, *jstr, *reqf, *reqa; 29 | if (!(req = json_object())) 30 | return NULL; 31 | jstr = reqa = jcaps = NULL; 32 | if (!(reqf = json_object())) 33 | goto err; 34 | if (!(reqa = json_array())) 35 | goto err; 36 | if (!(jcaps = json_array())) 37 | goto err; 38 | for (int i = 0; i < GBT_CAPABILITY_COUNT; ++i) 39 | if (caps & (1 << i)) 40 | { 41 | jstr = json_string(blktmpl_capabilityname(1 << i)); 42 | if (!jstr) 43 | goto err; 44 | if (json_array_append_new(jcaps, jstr)) 45 | goto err; 46 | } 47 | jstr = NULL; 48 | if (json_object_set_new(req, "capabilities", jcaps)) 49 | goto err; 50 | jcaps = NULL; 51 | if (!(jstr = json_integer(0))) 52 | goto err; 53 | if (json_object_set_new(reqf, "id", jstr)) 54 | goto err; 55 | if (!(jstr = json_integer(BLKMAKER_MAX_BLOCK_VERSION))) 56 | goto err; 57 | if (json_object_set_new(req, "maxversion", jstr)) 58 | goto err; 59 | if (lpid) 60 | { 61 | if (!(jstr = json_string(lpid))) 62 | goto err; 63 | if (json_object_set_new(req, "longpollid", jstr)) 64 | goto err; 65 | } 66 | jstr = NULL; 67 | 68 | // Add rules list 69 | if (!(jcaps = json_array())) { 70 | goto err; 71 | } 72 | for (const char * const *currule = rulelist; *currule; ++currule) { 73 | if (!(jstr = json_string(*currule))) { 74 | goto err; 75 | } 76 | if (json_array_append_new(jcaps, jstr)) { 77 | goto err; 78 | } 79 | } 80 | jstr = NULL; 81 | if (json_object_set_new(req, "rules", jcaps)) 82 | goto err; 83 | jcaps = NULL; 84 | 85 | // Put together main JSON-RPC request Object 86 | if (!(jstr = json_string("getblocktemplate"))) 87 | goto err; 88 | if (json_object_set_new(reqf, "method", jstr)) 89 | goto err; 90 | jstr = NULL; 91 | if (json_array_append_new(reqa, req)) 92 | goto err; 93 | req = NULL; 94 | if (json_object_set_new(reqf, "params", reqa)) 95 | goto err; 96 | 97 | return reqf; 98 | 99 | err: 100 | if (req ) json_decref(req ); 101 | if (reqa ) json_decref(reqa ); 102 | if (reqf ) json_decref(reqf ); 103 | if (jcaps) json_decref(jcaps); 104 | if (jstr ) json_decref(jstr ); 105 | return NULL; 106 | } 107 | 108 | json_t *blktmpl_request_jansson(const uint32_t caps, const char * const lpid) { 109 | return blktmpl_request_jansson2(caps, lpid, blkmk_supported_rules); 110 | } 111 | 112 | 113 | #define my_hex2bin _blkmk_hex2bin 114 | 115 | #define GET(key, type) do { \ 116 | if (!(v = json_object_get(json, #key))) \ 117 | return "Missing '" #key "'"; \ 118 | if (!json_is_ ## type(v)) \ 119 | return "Wrong type for '" #key "'"; \ 120 | } while(0) 121 | 122 | #define GETHEX(key, skey) do { \ 123 | GET(key, string); \ 124 | if (!my_hex2bin(tmpl->skey, json_string_value(v), sizeof(tmpl->skey))) \ 125 | return "Error decoding '" #key "'"; \ 126 | } while(0) 127 | 128 | #define GETNUM(key, type) do { \ 129 | GET(key, number); \ 130 | const double tmpd = json_number_value(v); \ 131 | const type tmp = tmpd; \ 132 | if (tmpd != tmp) { \ 133 | return "Invalid number value for '" #key "'"; \ 134 | } \ 135 | tmpl->key = tmp; \ 136 | } while(0) 137 | 138 | #define GETNUM_T(key, type) do { \ 139 | GET(key, number); \ 140 | const double tmpd = json_number_value(v); \ 141 | const type tmp = tmpd; \ 142 | /* This checks if it's merely being truncated, and tolerates it */ \ 143 | if (tmpd != tmp && !((tmpd < 0) ? (tmpd < tmp && tmpd + 1 > tmp) : (tmpd > tmp && tmpd - 1 < tmp))) { \ 144 | return "Invalid number value for '" #key "'"; \ 145 | } \ 146 | tmpl->key = tmp; \ 147 | } while(0) 148 | 149 | #define GETNUM_O2(key, skey, type) do { \ 150 | if ((v = json_object_get(json, #skey)) && json_is_number(v)) { \ 151 | const double tmpd = json_number_value(v); \ 152 | const type tmp = tmpd; \ 153 | if (tmpd == tmp) { \ 154 | tmpl->key = tmp; \ 155 | } \ 156 | } \ 157 | } while(0) 158 | 159 | #define GETNUM_O(key, type) GETNUM_O2(key, key, type) 160 | 161 | #define GETNUM_OT(key, type) do { \ 162 | if ((v = json_object_get(json, #key)) && json_is_number(v)) { \ 163 | const double tmpd = json_number_value(v); \ 164 | const type tmp = tmpd; \ 165 | /* This checks if it's merely being truncated, and tolerates it */ \ 166 | if (tmpd == tmp || ((tmpd < 0) ? (tmpd < tmp && tmpd + 1 > tmp) : (tmpd > tmp && tmpd - 1 < tmp))) { \ 167 | tmpl->key = tmp; \ 168 | } \ 169 | } \ 170 | } while(0) 171 | 172 | #define GETSTR(key, skey) do { \ 173 | if ((v = json_object_get(json, #key)) && json_is_string(v)) \ 174 | if (!(tmpl->skey = strdup(json_string_value(v)))) \ 175 | return "Error copying '" #key "'"; \ 176 | } while(0) 177 | 178 | #define GETBOOL(key, skey, def) do { \ 179 | if ((v = json_object_get(json, #key)) && json_is_boolean(v)) \ 180 | tmpl->skey = json_is_true(v); \ 181 | else \ 182 | if (def) \ 183 | tmpl->skey = true; \ 184 | } while(0) 185 | 186 | static void my_flip(void *, size_t); 187 | 188 | static 189 | const char *parse_txn(struct blktxn_t *txn, json_t *txnj, size_t my_tx_index) { 190 | json_t *vv; 191 | 192 | blktxn_init(txn); 193 | 194 | if (!((vv = json_object_get(txnj, "data")) && json_is_string(vv))) 195 | return "Missing or invalid type for transaction data"; 196 | const char *hexdata = json_string_value(vv); 197 | size_t datasz = strlen(hexdata) / 2; 198 | txn->data = malloc(datasz); 199 | txn->datasz = datasz; 200 | if (!my_hex2bin(txn->data, hexdata, datasz)) 201 | return "Error decoding transaction data"; 202 | 203 | if ((vv = json_object_get(txnj, "hash")) && json_is_string(vv)) 204 | { 205 | hexdata = json_string_value(vv); 206 | txn->hash_ = malloc(sizeof(*txn->hash_)); 207 | if (!my_hex2bin(*txn->hash_, hexdata, sizeof(*txn->hash_))) 208 | { 209 | free(txn->hash_); 210 | txn->hash_ = NULL; 211 | } 212 | else 213 | my_flip(*txn->hash_, sizeof(*txn->hash_)); 214 | } 215 | 216 | if ((vv = json_object_get(txnj, "txid")) && json_is_string(vv)) { 217 | hexdata = json_string_value(vv); 218 | txn->txid = malloc(sizeof(*txn->txid)); 219 | if (!my_hex2bin(*txn->txid, hexdata, sizeof(*txn->txid))) { 220 | return "Error decoding txid field"; 221 | } else { 222 | my_flip(*txn->txid, sizeof(*txn->txid)); 223 | } 224 | } 225 | 226 | txn->weight = -1; 227 | if ((vv = json_object_get(txnj, "weight")) && json_is_number(vv)) { 228 | const double f = json_number_value(txnj); 229 | const int32_t i32 = f; 230 | if (f == i32) { 231 | txn->weight = i32; 232 | } 233 | } 234 | 235 | if ((vv = json_object_get(txnj, "depends")) && json_is_array(vv)) { 236 | size_t depcount = json_array_size(vv); 237 | if (depcount <= LONG_MAX) { 238 | json_t *v; 239 | long i; 240 | double f; 241 | unsigned long ul; 242 | 243 | txn->depends = malloc(sizeof(*txn->depends) * depcount); 244 | for (i = 0; i < depcount; ++i) { 245 | v = json_array_get(vv, i); 246 | if (!json_is_number(v)) { 247 | break; 248 | } 249 | f = json_number_value(v); 250 | ul = f; 251 | if (f != ul || ul >= my_tx_index) { 252 | // Out of range for storage type, fractional number, forward dependency, etc 253 | break; 254 | } 255 | txn->depends[i] = ul; 256 | } 257 | if (i != depcount) { 258 | // We failed somewhere 259 | free(txn->depends); 260 | txn->depends = NULL; 261 | } else { 262 | // Success, finish up with storing the count 263 | txn->dependscount = depcount; 264 | } 265 | } 266 | } 267 | 268 | if ((vv = json_object_get(txnj, "fee")) && json_is_number(vv)) { 269 | double f; 270 | int64_t i64; 271 | 272 | f = json_number_value(vv); 273 | i64 = f; 274 | if (i64 == f && i64 >= 0) { 275 | txn->fee_ = i64; 276 | } 277 | } 278 | 279 | if ((vv = json_object_get(txnj, "required")) && json_is_true(vv)) { 280 | txn->required = true; 281 | } 282 | 283 | if ((vv = json_object_get(txnj, "sigops")) && json_is_number(vv)) { 284 | const double f = json_number_value(vv); 285 | int16_t i16 = f; 286 | if (i16 == f && i16 >= 0) { 287 | txn->sigops_ = i16; 288 | } 289 | } 290 | 291 | return NULL; 292 | } 293 | 294 | static 295 | void my_flip(void *data, size_t datasz) { 296 | char *cdata = (char*)data; 297 | --datasz; 298 | size_t hds = datasz / 2; 299 | for (size_t i = 0; i <= hds; ++i) 300 | { 301 | int altp = datasz - i; 302 | char c = cdata[i]; 303 | cdata[i] = cdata[altp]; 304 | cdata[altp] = c; 305 | } 306 | } 307 | 308 | const char *blktmpl_add_jansson(blktemplate_t *tmpl, const json_t *json, time_t time_rcvd) { 309 | if (tmpl->version) 310 | return "Template already populated (combining not supported)"; 311 | 312 | json_t *v, *v2; 313 | const char *s; 314 | 315 | if ((v = json_object_get(json, "result"))) 316 | { 317 | json_t *je; 318 | if ((je = json_object_get(json, "error")) && !json_is_null(je)) 319 | return "JSON result is error"; 320 | json = v; 321 | } 322 | 323 | GETHEX(bits, diffbits); 324 | my_flip(tmpl->diffbits, 4); 325 | GETNUM_T(curtime, blktime_t); 326 | GETNUM(height, blkheight_t); 327 | GETHEX(previousblockhash, prevblk); 328 | my_flip(tmpl->prevblk, 32); 329 | GETNUM_O(sigoplimit, unsigned short); 330 | GETNUM_O(sizelimit, unsigned long); 331 | GETNUM_O(weightlimit, int64_t); 332 | GETNUM(version, uint32_t); 333 | 334 | if ((v = json_object_get(json, "mutable")) && json_is_array(v)) 335 | { 336 | for (size_t i = json_array_size(v); i--; ) 337 | { 338 | v2 = json_array_get(v, i); 339 | if (!json_is_string(v2)) 340 | continue; 341 | tmpl->mutations |= blktmpl_getcapability(json_string_value(v2)); 342 | } 343 | } 344 | 345 | 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)) { 346 | // calloc so that a failure doesn't result in freeing a random pointer 347 | size_t n = json_array_size(v); 348 | tmpl->rules = calloc(n + 1, sizeof(*tmpl->rules)); 349 | for (size_t i = 0; i < n; ++i) { 350 | v2 = json_array_get(v, i); 351 | if (!json_is_string(v2)) { 352 | return "Non-String data in template rules list"; 353 | } 354 | s = json_string_value(v2); 355 | if (s[0] == '!') { 356 | ++s; 357 | if (!blkmk_supports_rule(s)) { 358 | return "Unsupported rule strictly required by template"; 359 | } 360 | } else { 361 | if (!blkmk_supports_rule(s)) { 362 | tmpl->unsupported_rule = true; 363 | } 364 | } 365 | tmpl->rules[i] = strdup(s); 366 | if (!tmpl->rules[i]) { 367 | return "Memory allocation error parsing rules"; 368 | } 369 | if (!strcmp(s, "segwit")) { 370 | tmpl->_bip141_sigops = true; 371 | } 372 | } 373 | 374 | v = json_object_get(json, "vbavailable"); 375 | n = json_object_size(v); 376 | tmpl->vbavailable = calloc(n + 1, sizeof(*tmpl->vbavailable)); 377 | struct blktmpl_vbassoc **cur_vbassoc = tmpl->vbavailable; 378 | for (void *iter = json_object_iter(v); iter; (iter = json_object_iter_next(v, iter)), ++cur_vbassoc) { 379 | v2 = json_object_iter_value(iter); 380 | if (!json_is_number(v2)) { 381 | return "Invalid type for vbavailable bit"; 382 | } 383 | double bitnum = json_number_value(v2); 384 | if (bitnum < 0 || bitnum > 28 || (unsigned)bitnum != bitnum) { 385 | return "Invalid bit number in vbavailable"; 386 | } 387 | *cur_vbassoc = malloc(sizeof(**cur_vbassoc)); 388 | if (!*cur_vbassoc) { 389 | return "Memory allocation error for struct blktmpl_vbassoc"; 390 | } 391 | **cur_vbassoc = (struct blktmpl_vbassoc){ 392 | .name = strdup(json_object_iter_key(iter)), 393 | .bitnum = bitnum, 394 | }; 395 | if (!(*cur_vbassoc)->name) { 396 | return "Memory allocation error for vbavailable name"; 397 | } 398 | } 399 | 400 | v = json_object_get(json, "vbrequired"); 401 | if (v && json_is_number(v)) { 402 | double tmpd = json_number_value(v); 403 | tmpl->vbrequired = tmpd; 404 | if (tmpl->vbrequired != tmpd) { 405 | return "Unparsable vbrequired"; 406 | } 407 | } 408 | } 409 | else 410 | if (tmpl->version > BLKMAKER_MAX_PRERULES_BLOCK_VERSION || (tmpl->version >= 2 && !tmpl->height)) 411 | { 412 | if (tmpl->mutations & BMM_VERDROP) 413 | tmpl->version = tmpl->height ? BLKMAKER_MAX_PRERULES_BLOCK_VERSION : 1; 414 | else 415 | if (!(tmpl->mutations & BMM_VERFORCE)) 416 | return "Unrecognized block version, and not allowed to reduce or force it"; 417 | } 418 | 419 | if ((v = json_object_get(json, "coinbasevalue")) && json_is_number(v)) { 420 | const double tmpd = json_number_value(v); 421 | const uint64_t tmp = tmpd; 422 | if (tmpd == tmp) { 423 | tmpl->has_cbvalue = true; 424 | tmpl->cbvalue = tmp; 425 | } 426 | } 427 | 428 | GETSTR(workid, workid); 429 | 430 | GETNUM_OT(expires, int16_t); 431 | GETNUM_OT(maxtime, blktime_t); 432 | GETNUM_OT(maxtimeoff, blktime_diff_t); 433 | GETNUM_OT(mintime, blktime_t); 434 | GETNUM_OT(mintimeoff, blktime_diff_t); 435 | 436 | GETSTR(longpollid, lp.id); 437 | GETSTR(longpolluri, lp.uri); 438 | GETBOOL(submitold, submitold, true); 439 | 440 | v = json_object_get(json, "transactions"); 441 | size_t txns = tmpl->txncount = json_array_size(v); 442 | tmpl->txns = calloc(txns, sizeof(*tmpl->txns)); 443 | tmpl->txns_datasz = 0; 444 | tmpl->txns_sigops = 0; 445 | tmpl->txns_weight = 0; 446 | for (size_t i = 0; i < txns; ++i) 447 | { 448 | struct blktxn_t * const txn = &tmpl->txns[i]; 449 | if ((s = parse_txn(txn, json_array_get(v, i), i + 1))) { 450 | return s; 451 | } 452 | tmpl->txns_datasz += txn->datasz; 453 | if (tmpl->txns_sigops == -1) { 454 | ; // Impossible to tally the unknown 455 | } else if (txn->sigops_ == -1) { 456 | tmpl->txns_sigops = -1; 457 | } else { 458 | tmpl->txns_sigops += txn->sigops_; 459 | } 460 | if (tmpl->txns_weight == -1) { 461 | ; // Impossible to tally the unknown 462 | } else if (txn->weight == -1) { 463 | tmpl->txns_weight = -1; 464 | } else { 465 | tmpl->txns_weight += txn->weight; 466 | } 467 | } 468 | 469 | if ((v = json_object_get(json, "coinbasetxn")) && json_is_object(v)) 470 | { 471 | tmpl->cbtxn = calloc(1, sizeof(*tmpl->cbtxn)); 472 | if ((s = parse_txn(tmpl->cbtxn, v, 0))) 473 | return s; 474 | } else if (!tmpl->has_cbvalue) { 475 | return "Missing either coinbasetxn or coinbasevalue"; 476 | } 477 | 478 | if ((v = json_object_get(json, "coinbaseaux")) && json_is_object(v)) 479 | { 480 | tmpl->aux_count = json_object_size(v); 481 | tmpl->auxs = calloc(tmpl->aux_count, sizeof(*tmpl->auxs)); 482 | unsigned i = 0; 483 | for (void *iter = json_object_iter(v); iter; (iter = json_object_iter_next(v, iter)), ++i) 484 | { 485 | v2 = json_object_iter_value(iter); 486 | s = json_string_value(v2); 487 | if (!s) 488 | continue; 489 | size_t sz = strlen(s) / 2; 490 | tmpl->auxs[i] = (struct blkaux_t){ 491 | .auxname = strdup(json_object_iter_key(iter)), 492 | .data = malloc(sz), 493 | .datasz = sz, 494 | }; 495 | if (!my_hex2bin(tmpl->auxs[i].data, s, sz)) { 496 | return "Error decoding 'coinbaseaux' data"; 497 | } 498 | } 499 | } 500 | 501 | if ((v = json_object_get(json, "target")) && json_is_string(v)) 502 | { 503 | tmpl->target = malloc(sizeof(*tmpl->target)); 504 | if (!my_hex2bin(tmpl->target, json_string_value(v), sizeof(*tmpl->target))) 505 | return "Error decoding 'target'"; 506 | } 507 | 508 | tmpl->_time_rcvd = time_rcvd; 509 | 510 | return NULL; 511 | } 512 | 513 | json_t *blktmpl_propose_jansson(blktemplate_t * const tmpl, const uint32_t caps, const bool foreign) { 514 | json_t *jreq = blktmpl_request_jansson(caps, NULL), *ja = NULL, *jparams; 515 | if (!(jreq && json_is_object(jreq))) 516 | goto err; 517 | 518 | jparams = json_array_get(json_object_get(jreq, "params"), 0); 519 | if (!(jparams && json_is_object(jparams))) 520 | goto err; 521 | 522 | if (!(ja = json_string("proposal"))) 523 | goto err; 524 | if (json_object_set_new(jparams, "mode", ja)) 525 | goto err; 526 | 527 | if (tmpl->workid && !foreign) 528 | { 529 | if (!(ja = json_string(tmpl->workid))) 530 | goto err; 531 | if (json_object_set_new(jparams, "workid", ja)) 532 | goto err; 533 | } 534 | ja = NULL; 535 | 536 | unsigned int dataid = (tmpl->mutations & (BMM_CBAPPEND | BMM_CBSET) ? 1 : 0); 537 | 538 | uint8_t sdata[0x4c]; 539 | if (!blkmk_sample_data_(tmpl, sdata, dataid)) 540 | goto err; 541 | char *blkhex = blkmk_assemble_submission2_(tmpl, sdata, NULL, 0, dataid, 0, foreign); 542 | if (!blkhex) 543 | goto err; 544 | if (!(ja = json_string(blkhex))) 545 | goto err; 546 | free(blkhex); 547 | if (json_object_set_new(jparams, "data", ja)) 548 | goto err; 549 | 550 | return jreq; 551 | 552 | err: 553 | if (jreq) json_decref(jreq); 554 | if (ja) json_decref(ja); 555 | return NULL; 556 | } 557 | 558 | static 559 | 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) { 560 | char *blkhex = blkmk_assemble_submission2_(tmpl, data, extranonce, extranoncesz, dataid, nonce, foreign); 561 | if (!blkhex) 562 | return NULL; 563 | 564 | json_t *rv = json_array(), *ja, *jb; 565 | jb = NULL; 566 | ja = json_string(blkhex); 567 | free(blkhex); 568 | if (!ja) 569 | goto err; 570 | if (json_array_append_new(rv, ja)) 571 | goto err; 572 | if (!(ja = json_object())) 573 | goto err; 574 | if (tmpl->workid && !foreign) 575 | { 576 | if (!(jb = json_string(tmpl->workid))) 577 | goto err; 578 | if (json_object_set_new(ja, "workid", jb)) 579 | goto err; 580 | jb = NULL; 581 | } 582 | if (json_array_append_new(rv, ja)) 583 | goto err; 584 | 585 | if (!(ja = json_object())) 586 | goto err; 587 | if (!(jb = json_integer(0))) 588 | goto err; 589 | if (json_object_set_new(ja, "id", jb)) 590 | goto err; 591 | if (!(jb = json_string("submitblock"))) 592 | goto err; 593 | if (json_object_set_new(ja, "method", jb)) 594 | goto err; 595 | jb = NULL; 596 | if (json_object_set_new(ja, "params", rv)) 597 | goto err; 598 | 599 | return ja; 600 | 601 | err: 602 | json_decref(rv); 603 | if (ja) json_decref(ja); 604 | if (jb) json_decref(jb); 605 | return NULL; 606 | } 607 | 608 | json_t *blkmk_submit_jansson(blktemplate_t *tmpl, const unsigned char *data, unsigned int dataid, blknonce_t nonce) { 609 | return _blkmk_submit_jansson(tmpl, data, NULL, 0, dataid, nonce, false); 610 | } 611 | 612 | json_t *blkmk_submit_foreign_jansson(blktemplate_t *tmpl, const unsigned char *data, unsigned int dataid, blknonce_t nonce) { 613 | return _blkmk_submit_jansson(tmpl, data, NULL, 0, dataid, nonce, true); 614 | } 615 | 616 | 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) { 617 | return _blkmk_submit_jansson(tmpl, data, extranonce, extranoncesz, 0, nonce, foreign); 618 | } 619 | -------------------------------------------------------------------------------- /blkmaker.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2016 Luke Dashjr 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the standard MIT license. See COPYING for more details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #ifndef WIN32 17 | #include 18 | #else 19 | #include 20 | #endif 21 | 22 | #include 23 | #include 24 | 25 | #include "private.h" 26 | 27 | const char *blkmk_supported_rules[] = { 28 | "csv", 29 | "segwit", 30 | NULL 31 | }; 32 | 33 | bool blkmk_supports_rule(const char * const rulename) { 34 | for (const char **r = blkmk_supported_rules; *r; ++r) { 35 | if (!strcmp(rulename, *r)) { 36 | return true; 37 | } 38 | } 39 | return false; 40 | } 41 | 42 | static inline 43 | void my_htole32(unsigned char *buf, uint32_t n) { 44 | buf[0] = (n >> 0) % 256; 45 | buf[1] = (n >> 8) % 256; 46 | buf[2] = (n >> 16) % 256; 47 | buf[3] = (n >> 24) % 256; 48 | } 49 | 50 | static inline 51 | void my_htole64(unsigned char *buf, uint64_t n) { 52 | for (int i = 0; i < 8; ++i) 53 | buf[i] = (n >> (8*i)) & 0xff; 54 | } 55 | 56 | 57 | bool (*blkmk_sha256_impl)(void *, const void *, size_t) = NULL; 58 | 59 | bool _blkmk_dblsha256(void *hash, const void *data, size_t datasz) { 60 | return blkmk_sha256_impl(hash, data, datasz) && blkmk_sha256_impl(hash, hash, 32); 61 | } 62 | 63 | #define dblsha256 _blkmk_dblsha256 64 | 65 | static 66 | size_t varintDecode(const uint8_t *p, size_t size, uint64_t *n) 67 | { 68 | if (size > 8 && p[0] == 0xff) 69 | { 70 | *n = upk_u64le(p, 1); 71 | return 9; 72 | } 73 | if (size > 4 && p[0] == 0xfe) 74 | { 75 | *n = upk_u32le(p, 1); 76 | return 5; 77 | } 78 | if (size > 2 && p[0] == 0xfd) 79 | { 80 | *n = upk_u16le(p, 1); 81 | return 3; 82 | } 83 | if (size > 0 && p[0] <= 0xfc) 84 | { 85 | *n = p[0]; 86 | return 1; 87 | } 88 | return 0; 89 | } 90 | 91 | #define max_varint_size (9) 92 | 93 | static 94 | char varintEncode(unsigned char *out, uint64_t n) { 95 | if (n < 0xfd) 96 | { 97 | out[0] = n; 98 | return 1; 99 | } 100 | char L; 101 | if (n <= 0xffff) 102 | { 103 | out[0] = '\xfd'; 104 | L = 3; 105 | } 106 | else 107 | if (n <= 0xffffffff) 108 | { 109 | out[0] = '\xfe'; 110 | L = 5; 111 | } 112 | else 113 | { 114 | out[0] = '\xff'; 115 | L = 9; 116 | } 117 | for (unsigned char i = 1; i < L; ++i) 118 | out[i] = (n >> ((i - 1) * 8)) % 256; 119 | return L; 120 | } 121 | 122 | static uint8_t blkmk_varint_encode_size(const uint64_t n) { 123 | uint8_t dummy[max_varint_size]; 124 | return varintEncode(dummy, n); 125 | } 126 | 127 | static 128 | int16_t blkmk_count_sigops(const uint8_t * const script, const size_t scriptsz, const bool bip141) { 129 | int16_t sigops = 0; 130 | for (size_t i = 0; i < scriptsz; ++i) { 131 | if (script[i] <= 0x4c /* OP_PUSHDATA1 */) { 132 | if (script[i] == 0x4c) { 133 | if (i + 1 >= scriptsz) { 134 | break; 135 | } 136 | ++i; 137 | } 138 | i += script[i]; 139 | } else if (script[i] == 0x4d /* OP_PUSHDATA2 */) { 140 | if (i + 2 >= scriptsz) { 141 | break; 142 | } 143 | i += 2 + upk_u16le(script, i + 1); 144 | } else if (script[i] == 0x4e /* OP_PUSHDATA4 */) { 145 | if (i + 4 >= scriptsz) { 146 | break; 147 | } 148 | i += 4 + upk_u32le(script, i + 1); 149 | } else if (script[i] == 0xac /* OP_CHECKSIG */ || script[i] == 0xad /* OP_CHECKSIGVERIFY */) { 150 | ++sigops; 151 | } else if (script[i] == 0xae /* OP_CHECKMULTISIG */ || script[i] == 0xaf /* OP_CHECKMULTISIGVERIFY */) { 152 | sigops += 20; 153 | } 154 | } 155 | if (bip141) { 156 | sigops *= 4; 157 | } 158 | return sigops; 159 | } 160 | 161 | static int64_t blkmk_calc_gentx_weight(const void * const data, const size_t datasz) { 162 | return (datasz * 4) + 2 /* marker & flag */ + 1 /* witness stack count */ + 1 /* stack item size */ + 32 /* stack item: nonce */; 163 | } 164 | 165 | static int64_t blktxn_set_gentx_weight(struct blktxn_t * const gentx) { 166 | if (gentx->weight < 0) { 167 | gentx->weight = blkmk_calc_gentx_weight(gentx->data, gentx->datasz); 168 | } 169 | return gentx->weight; 170 | } 171 | 172 | uint64_t blkmk_init_generation3(blktemplate_t * const tmpl, const void * const script, const size_t scriptsz, bool * const inout_newcb) { 173 | const bool replace_existing = *inout_newcb; 174 | *inout_newcb = false; 175 | 176 | if (tmpl->cbtxn && !(replace_existing && (tmpl->mutations & BMM_GENERATE))) 177 | { 178 | return 0; 179 | } 180 | 181 | if (!tmpl->has_cbvalue) { 182 | // TODO: Figure it out from the existing cbtxn 183 | return 0; 184 | } 185 | 186 | if (scriptsz >= 0xfd) 187 | return 0; 188 | 189 | unsigned char *data = malloc(168 + scriptsz); 190 | size_t off = 0; 191 | if (!data) 192 | return 0; 193 | 194 | memcpy(&data[0], 195 | "\x01\0\0\0" // txn ver 196 | "\x01" // input count 197 | "\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 198 | "\xff\xff\xff\xff" // index (-1) 199 | "\x02" // scriptSig length 200 | // height serialization length (set later) 201 | , 42); 202 | off += 43; 203 | 204 | blkheight_t h = tmpl->height; 205 | while (h > 127) 206 | { 207 | ++data[41]; 208 | data[off++] = h & 0xff; 209 | h >>= 8; 210 | } 211 | data[off++] = h; 212 | data[42] = data[41] - 1; 213 | 214 | if (tmpl->aux_count) 215 | { 216 | unsigned auxsz = off++; 217 | data[auxsz] = 0; 218 | ++data[41]; 219 | 220 | for (unsigned i = 0; i < tmpl->aux_count; ++i) 221 | { 222 | struct blkaux_t * const aux = &tmpl->auxs[i]; 223 | if ((size_t)data[41] + aux->datasz > libblkmaker_coinbase_size_limit) 224 | { 225 | free(data); 226 | return 0; 227 | } 228 | memcpy(&data[off], tmpl->auxs[i].data, aux->datasz); 229 | data[41] += aux->datasz; 230 | data[auxsz] += aux->datasz; 231 | off += aux->datasz; 232 | } 233 | } 234 | 235 | memcpy(&data[off], 236 | "\xff\xff\xff\xff" // sequence 237 | "\x01" // output count 238 | , 5); 239 | off += 5; 240 | my_htole64(&data[off], tmpl->cbvalue); 241 | off += 8; 242 | data[off++] = scriptsz; 243 | if (scriptsz) { 244 | memcpy(&data[off], script, scriptsz); 245 | off += scriptsz; 246 | } 247 | memset(&data[off], 0, 4); // lock time 248 | off += 4; 249 | 250 | const unsigned long pretx_size = libblkmaker_blkheader_size + blkmk_varint_encode_size(1 + tmpl->txncount); 251 | const int16_t sigops_counted = blkmk_count_sigops(script, scriptsz, tmpl->_bip141_sigops); 252 | const int64_t gentx_weight = blkmk_calc_gentx_weight(data, off); 253 | if (pretx_size + tmpl->txns_datasz + off > tmpl->sizelimit 254 | || (tmpl->txns_weight >= 0 && tmpl->txns_weight + gentx_weight > tmpl->weightlimit) 255 | || (tmpl->txns_sigops >= 0 && tmpl->txns_sigops + sigops_counted > tmpl->sigoplimit)) { 256 | free(data); 257 | return 0; 258 | } 259 | 260 | struct blktxn_t *txn = malloc(sizeof(*tmpl->cbtxn)); 261 | if (!txn) 262 | { 263 | free(data); 264 | return 0; 265 | } 266 | blktxn_init(txn); 267 | 268 | txn->data = data; 269 | txn->datasz = off; 270 | txn->sigops_ = sigops_counted; 271 | txn->weight = gentx_weight; 272 | 273 | if (tmpl->cbtxn) 274 | { 275 | blktxn_clean(tmpl->cbtxn); 276 | free(tmpl->cbtxn); 277 | } 278 | tmpl->cbtxn = txn; 279 | 280 | tmpl->mutations |= BMM_CBAPPEND | BMM_CBSET | BMM_GENERATE; 281 | 282 | *inout_newcb = true; 283 | return tmpl->cbvalue; 284 | } 285 | 286 | uint64_t blkmk_init_generation2(blktemplate_t *tmpl, void *script, size_t scriptsz, bool *out_newcb) { 287 | bool tmp; 288 | if (!out_newcb) 289 | out_newcb = &tmp; 290 | *out_newcb = false; 291 | return blkmk_init_generation3(tmpl, script, scriptsz, out_newcb); 292 | } 293 | 294 | uint64_t blkmk_init_generation(blktemplate_t *tmpl, void *script, size_t scriptsz) { 295 | return blkmk_init_generation2(tmpl, script, scriptsz, NULL); 296 | } 297 | 298 | static 299 | bool blkmk_hash_transactions(blktemplate_t * const tmpl) 300 | { 301 | for (unsigned long i = 0; i < tmpl->txncount; ++i) 302 | { 303 | struct blktxn_t * const txn = &tmpl->txns[i]; 304 | if (txn->hash_) 305 | continue; 306 | txn->hash_ = malloc(sizeof(*txn->hash_)); 307 | if (!dblsha256(txn->hash_, txn->data, txn->datasz)) 308 | { 309 | free(txn->hash_); 310 | return false; 311 | } 312 | } 313 | return true; 314 | } 315 | 316 | static 317 | bool blkmk_build_merkle_branches(blktemplate_t * const tmpl) 318 | { 319 | int branchcount, i; 320 | libblkmaker_hash_t *branches; 321 | 322 | if (tmpl->_mrklbranch) 323 | return true; 324 | 325 | if (!blkmk_hash_transactions(tmpl)) 326 | return false; 327 | 328 | branchcount = blkmk_flsl(tmpl->txncount); 329 | if (!branchcount) 330 | { 331 | tmpl->_mrklbranchcount = 0; 332 | tmpl->_mrklbranch = NULL; 333 | return true; 334 | } 335 | 336 | branches = malloc(branchcount * sizeof(*branches)); 337 | if (!branches) { 338 | return false; 339 | } 340 | 341 | size_t hashcount = tmpl->txncount + 1; 342 | libblkmaker_hash_t * const hashes = malloc((hashcount + 1) * sizeof(*hashes)); // +1 for when the last needs duplicating 343 | if (!hashes) { 344 | free(branches); 345 | return false; 346 | } 347 | 348 | for (i = 0; i < tmpl->txncount; ++i) 349 | { 350 | struct blktxn_t * const txn = &tmpl->txns[i]; 351 | txnhash_t * const txid = txn->txid ? txn->txid : txn->hash_; 352 | memcpy(&hashes[i + 1], txid, sizeof(*hashes)); 353 | } 354 | 355 | for (i = 0; i < branchcount; ++i) 356 | { 357 | memcpy(&branches[i], &hashes[1], sizeof(*hashes)); 358 | if (hashcount % 2) 359 | { 360 | memcpy(&hashes[hashcount], &hashes[hashcount - 1], sizeof(*hashes)); 361 | ++hashcount; 362 | } 363 | for (size_t i = 2; i < hashcount; i += 2) 364 | // This is where we overlap input and output, on the first pair 365 | if (!dblsha256(&hashes[i / 2], &hashes[i], sizeof(*hashes) * 2)) 366 | { 367 | free(branches); 368 | free(hashes); 369 | return false; 370 | } 371 | hashcount /= 2; 372 | } 373 | 374 | free(hashes); 375 | 376 | tmpl->_mrklbranch = branches; 377 | tmpl->_mrklbranchcount = branchcount; 378 | 379 | return true; 380 | } 381 | 382 | static 383 | bool build_merkle_root(unsigned char *mrklroot_out, blktemplate_t *tmpl, unsigned char *cbtxndata, size_t cbtxndatasz) { 384 | int i; 385 | libblkmaker_hash_t hashes[0x40]; 386 | 387 | if (!blkmk_build_merkle_branches(tmpl)) 388 | return false; 389 | 390 | if (!dblsha256(&hashes[0], cbtxndata, cbtxndatasz)) 391 | return false; 392 | 393 | for (i = 0; i < tmpl->_mrklbranchcount; ++i) 394 | { 395 | memcpy(&hashes[1], tmpl->_mrklbranch[i], 0x20); 396 | // This is where we overlap input and output, on the first pair 397 | if (!dblsha256(&hashes[0], &hashes[0], 0x40)) 398 | return false; 399 | } 400 | 401 | memcpy(mrklroot_out, &hashes[0], 32); 402 | 403 | return true; 404 | } 405 | 406 | static 407 | bool _blkmk_calculate_witness_mrklroot(blktemplate_t * const tmpl, libblkmaker_hash_t * const out, bool * const witness_needed) { 408 | if (!blkmk_hash_transactions(tmpl)) 409 | return false; 410 | 411 | // Step 1: Populate hashes with the witness hashes for all transactions 412 | size_t hashcount = tmpl->txncount + 1; 413 | libblkmaker_hash_t * const hashes = malloc((hashcount + 1) * sizeof(*hashes)); // +1 for when the last needs duplicating 414 | if (!hashes) { 415 | return false; 416 | } 417 | memset(&hashes[0], 0, sizeof(hashes[0])); // Gen tx gets a null entry 418 | *witness_needed = false; 419 | for (unsigned long i = 0; i < tmpl->txncount; ++i) { 420 | struct blktxn_t * const txn = &tmpl->txns[i]; 421 | if (txn->txid && memcmp(txn->hash_, txn->txid, sizeof(*txn->txid))) { 422 | *witness_needed = true; 423 | } 424 | memcpy(&hashes[i + 1], txn->hash_, sizeof(*hashes)); 425 | } 426 | if (!*witness_needed) { 427 | free(hashes); 428 | return true; 429 | } 430 | 431 | // Step 2: Reduce it to a merkle root 432 | for ( ; hashcount > 1 ; hashcount /= 2) { 433 | if (hashcount % 2 == 1) { 434 | // Odd number, duplicate the last 435 | memcpy(&hashes[hashcount], &hashes[hashcount - 1], sizeof(*hashes)); 436 | ++hashcount; 437 | } 438 | for (size_t i = 0; i < hashcount; i += 2) { 439 | // We overlap input and output here, on the first pair 440 | if (!dblsha256(&hashes[i / 2], &hashes[i], sizeof(*hashes) * 2)) { 441 | free(hashes); 442 | return false; 443 | } 444 | } 445 | } 446 | 447 | memcpy(out, hashes, sizeof(*out)); 448 | free(hashes); 449 | return true; 450 | } 451 | 452 | static 453 | bool _blkmk_witness_mrklroot(blktemplate_t * const tmpl) { 454 | if (tmpl->_calculated_witness) { 455 | // Already calculated 456 | return true; 457 | } 458 | tmpl->_witnessmrklroot = malloc(sizeof(libblkmaker_hash_t)); 459 | if (!tmpl->_witnessmrklroot) { 460 | return false; 461 | } 462 | bool witness_needed; 463 | if (!_blkmk_calculate_witness_mrklroot(tmpl, tmpl->_witnessmrklroot, &witness_needed)) { 464 | free(tmpl->_witnessmrklroot); 465 | tmpl->_witnessmrklroot = NULL; 466 | return false; 467 | } 468 | if (!witness_needed) { 469 | free(tmpl->_witnessmrklroot); 470 | tmpl->_witnessmrklroot = NULL; 471 | } 472 | tmpl->_calculated_witness = true; 473 | return true; 474 | } 475 | 476 | static const int cbScriptSigLen = 4 + 1 + 36; 477 | 478 | static 479 | 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) { 480 | unsigned char *out = vout; 481 | unsigned char *in = tmpl->cbtxn->data; 482 | size_t insz = tmpl->cbtxn->datasz; 483 | 484 | if (appendsz > libblkmaker_coinbase_size_limit || in[cbScriptSigLen] > libblkmaker_coinbase_size_limit - appendsz) { 485 | return false; 486 | } 487 | 488 | const unsigned long pretx_size = libblkmaker_blkheader_size + blkmk_varint_encode_size(1 + tmpl->txncount); 489 | if (pretx_size + tmpl->cbtxn->datasz + tmpl->txns_datasz + appendsz > tmpl->sizelimit) { 490 | return false; 491 | } 492 | 493 | if (tmpl->txns_weight >= 0 && (blktxn_set_gentx_weight(tmpl->cbtxn) + tmpl->txns_weight + (appendsz * 4) > tmpl->weightlimit)) { 494 | return false; 495 | } 496 | 497 | const int16_t orig_scriptSig_sigops = blkmk_count_sigops(&in[cbScriptSigLen + 1], in[cbScriptSigLen], tmpl->_bip141_sigops); 498 | int cbPostScriptSig = cbScriptSigLen + 1 + in[cbScriptSigLen]; 499 | if (appended_at_offset) 500 | *appended_at_offset = cbPostScriptSig; 501 | unsigned char *outPostScriptSig = &out[cbPostScriptSig]; 502 | void *outExtranonce = (void*)outPostScriptSig; 503 | outPostScriptSig += appendsz; 504 | 505 | if (out != in) 506 | { 507 | memcpy(out, in, cbPostScriptSig+1); 508 | memcpy(outPostScriptSig, &in[cbPostScriptSig], insz - cbPostScriptSig); 509 | } 510 | else 511 | memmove(outPostScriptSig, &in[cbPostScriptSig], insz - cbPostScriptSig); 512 | 513 | out[cbScriptSigLen] += appendsz; 514 | memcpy(outExtranonce, append, appendsz); 515 | 516 | const int16_t sigops_counted = tmpl->cbtxn->sigops_ + blkmk_count_sigops(&out[cbScriptSigLen + 1], out[cbScriptSigLen], tmpl->_bip141_sigops) - orig_scriptSig_sigops; 517 | if (tmpl->txns_sigops >= 0 && tmpl->txns_sigops + sigops_counted > tmpl->sigoplimit) { 518 | // Overflowed :( 519 | if (out == in) { 520 | // Revert it! 521 | out[cbScriptSigLen] -= appendsz; 522 | memmove(&out[cbPostScriptSig], outPostScriptSig, insz - cbPostScriptSig); 523 | } 524 | return false; 525 | } 526 | 527 | if (sigops_counted_p) { 528 | *sigops_counted_p = sigops_counted; 529 | } 530 | 531 | return true; 532 | } 533 | 534 | ssize_t blkmk_append_coinbase_safe2(blktemplate_t * const tmpl, const void * const append, const size_t appendsz, int extranoncesz, const bool merkle_only) 535 | { 536 | if (!(tmpl->mutations & (BMM_CBAPPEND | BMM_CBSET))) 537 | return -1; 538 | 539 | size_t datasz = tmpl->cbtxn->datasz; 540 | if (extranoncesz == sizeof(unsigned int)) { 541 | ++extranoncesz; 542 | } else 543 | if (!merkle_only) 544 | { 545 | if (extranoncesz < sizeof(unsigned int)) 546 | extranoncesz = sizeof(unsigned int); 547 | } 548 | if (tmpl->cbtxn->datasz <= cbScriptSigLen || tmpl->cbtxn->datasz <= cbScriptSigLen + tmpl->cbtxn->data[cbScriptSigLen]) { 549 | return -6; 550 | } 551 | if (extranoncesz > libblkmaker_coinbase_size_limit || tmpl->cbtxn->data[cbScriptSigLen] > libblkmaker_coinbase_size_limit || extranoncesz + tmpl->cbtxn->data[cbScriptSigLen] > libblkmaker_coinbase_size_limit) { 552 | return -5; 553 | } 554 | size_t availsz = libblkmaker_coinbase_size_limit - extranoncesz - tmpl->cbtxn->data[cbScriptSigLen]; 555 | { 556 | const unsigned long pretx_size = libblkmaker_blkheader_size + blkmk_varint_encode_size(1 + tmpl->txncount); 557 | const size_t current_blocksize = pretx_size + tmpl->cbtxn->datasz + tmpl->txns_datasz; 558 | if (current_blocksize > tmpl->sizelimit) { 559 | return -4; 560 | } 561 | const size_t availsz2 = tmpl->sizelimit - current_blocksize; 562 | if (availsz2 < availsz) { 563 | availsz = availsz2; 564 | } 565 | } 566 | if (tmpl->txns_weight >= 0) { 567 | const size_t current_blockweight = blktxn_set_gentx_weight(tmpl->cbtxn) + tmpl->txns_weight; 568 | if (current_blockweight > tmpl->weightlimit) { 569 | return false; 570 | } 571 | const size_t availsz2 = (tmpl->weightlimit - current_blockweight) / 4; 572 | if (availsz2 < availsz) { 573 | availsz = availsz2; 574 | } 575 | } 576 | if (appendsz > availsz) 577 | return availsz; 578 | 579 | void *newp = realloc(tmpl->cbtxn->data, datasz + appendsz); 580 | if (!newp) 581 | return -2; 582 | 583 | tmpl->cbtxn->data = newp; 584 | if (!_blkmk_append_cb(tmpl, newp, append, appendsz, NULL, &tmpl->cbtxn->sigops_)) 585 | return -3; 586 | tmpl->cbtxn->datasz += appendsz; 587 | tmpl->cbtxn->weight += appendsz * 4; 588 | 589 | return availsz; 590 | } 591 | 592 | ssize_t blkmk_append_coinbase_safe(blktemplate_t * const tmpl, const void * const append, const size_t appendsz) { 593 | return blkmk_append_coinbase_safe2(tmpl, append, appendsz, 0, false); 594 | } 595 | 596 | bool _blkmk_extranonce(blktemplate_t *tmpl, void *vout, unsigned int workid, size_t *offs) { 597 | unsigned char *in = tmpl->cbtxn->data; 598 | size_t insz = tmpl->cbtxn->datasz; 599 | 600 | if (!workid) 601 | { 602 | memcpy(vout, in, insz); 603 | *offs += insz; 604 | return true; 605 | } 606 | 607 | if (!_blkmk_append_cb(tmpl, vout, &workid, sizeof(workid), NULL, NULL)) 608 | return false; 609 | 610 | *offs += insz + sizeof(workid); 611 | 612 | return true; 613 | } 614 | 615 | static const unsigned char witness_magic[] = { 0x6a /* OP_RETURN */, 0x24, 0xaa, 0x21, 0xa9, 0xed }; 616 | #define commitment_spk_size (sizeof(witness_magic) + sizeof(libblkmaker_hash_t) /* witness mrklroot */) 617 | #define commitment_txout_size (8 /* value */ + 1 /* scriptPubKey length */ + commitment_spk_size) 618 | static const size_t max_witness_commitment_insert = max_varint_size + commitment_txout_size - 1; 619 | static const libblkmaker_hash_t witness_nonce = { 0 }; 620 | 621 | static 622 | bool _blkmk_insert_witness_commitment(blktemplate_t * const tmpl, unsigned char * const gentxdata, size_t * const gentxsize) { 623 | if (!_blkmk_witness_mrklroot(tmpl)) { 624 | return false; 625 | } 626 | if (!tmpl->_witnessmrklroot) { 627 | // No commitment needed 628 | return true; 629 | } 630 | 631 | libblkmaker_hash_t merkle_with_nonce[2]; 632 | libblkmaker_hash_t commitment; 633 | memcpy(&merkle_with_nonce[0], tmpl->_witnessmrklroot, sizeof(*tmpl->_witnessmrklroot)); 634 | memcpy(&merkle_with_nonce[1], &witness_nonce, sizeof(witness_nonce)); 635 | if(!dblsha256(&commitment, &merkle_with_nonce[0], sizeof(merkle_with_nonce))) 636 | return false; 637 | 638 | if (cbScriptSigLen >= *gentxsize) { 639 | return false; 640 | } 641 | const uint8_t coinbasesz = gentxdata[cbScriptSigLen]; 642 | const size_t offset_of_txout_count = cbScriptSigLen + coinbasesz + sizeof(coinbasesz) + 4 /* nSequence */; 643 | if (offset_of_txout_count >= *gentxsize) { 644 | return false; 645 | } 646 | uint64_t txout_count; 647 | const size_t in_txout_count_size = varintDecode(&gentxdata[offset_of_txout_count], *gentxsize - offset_of_txout_count, &txout_count); 648 | if (!in_txout_count_size) { 649 | return false; 650 | } 651 | ++txout_count; 652 | unsigned char insertbuf[max_varint_size + commitment_txout_size]; 653 | const size_t out_txout_count_size = varintEncode(insertbuf, txout_count); 654 | unsigned char * const commitment_txout = &insertbuf[out_txout_count_size]; 655 | memset(commitment_txout, 0, 8); // value 656 | commitment_txout[8] = commitment_spk_size; 657 | memcpy(&commitment_txout[9], witness_magic, sizeof(witness_magic)); 658 | memcpy(&commitment_txout[9 + sizeof(witness_magic)], &commitment, sizeof(commitment)); 659 | 660 | const size_t offset_of_txout_data = (offset_of_txout_count + in_txout_count_size); 661 | const size_t new_offset_of_preexisting_txout_data = (offset_of_txout_count + out_txout_count_size); 662 | const size_t length_of_txtail = 4; 663 | const size_t length_of_preexisting_txout_data = (*gentxsize - length_of_txtail) - offset_of_txout_data; 664 | const size_t offset_of_txtail_i = *gentxsize - length_of_txtail; // just the lock time 665 | const size_t offset_of_txtail_o = offset_of_txtail_i + (out_txout_count_size - in_txout_count_size) + commitment_txout_size; 666 | memmove(&gentxdata[offset_of_txtail_o], &gentxdata[offset_of_txtail_i], length_of_txtail); 667 | if (offset_of_txout_data != new_offset_of_preexisting_txout_data) { 668 | memmove(&gentxdata[new_offset_of_preexisting_txout_data], &gentxdata[offset_of_txout_data], length_of_preexisting_txout_data); 669 | } 670 | memcpy(&gentxdata[offset_of_txout_count], insertbuf, out_txout_count_size); 671 | const size_t offset_of_commitment_txout_o = new_offset_of_preexisting_txout_data + length_of_preexisting_txout_data; 672 | memcpy(&gentxdata[offset_of_commitment_txout_o], commitment_txout, commitment_txout_size); 673 | 674 | *gentxsize = offset_of_txtail_o + length_of_txtail; 675 | 676 | return true; 677 | } 678 | 679 | static 680 | 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) 681 | { 682 | double time_passed = difftime(usetime, tmpl->_time_rcvd); 683 | blktime_t timehdr = tmpl->curtime + time_passed; 684 | if (timehdr > tmpl->maxtime) 685 | timehdr = tmpl->maxtime; 686 | my_htole32(out_hdrbuf, timehdr); 687 | if (out_expire) 688 | { 689 | *out_expire = tmpl->expires - time_passed - 1; 690 | 691 | if (can_roll_ntime) 692 | { 693 | // If the caller can roll the time header, we need to expire before reaching the maxtime 694 | int16_t maxtime_expire_limit = (tmpl->maxtime - timehdr) + 1; 695 | if (*out_expire > maxtime_expire_limit) 696 | *out_expire = maxtime_expire_limit; 697 | } 698 | } 699 | } 700 | 701 | bool blkmk_sample_data_(blktemplate_t * const tmpl, uint8_t * const cbuf, const unsigned int dataid) { 702 | my_htole32(&cbuf[0], tmpl->version); 703 | memcpy(&cbuf[4], &tmpl->prevblk, 32); 704 | 705 | unsigned char cbtxndata[tmpl->cbtxn->datasz + sizeof(dataid) + max_witness_commitment_insert]; 706 | size_t cbtxndatasz = 0; 707 | if (!_blkmk_extranonce(tmpl, cbtxndata, dataid, &cbtxndatasz)) 708 | return false; 709 | if (!_blkmk_insert_witness_commitment(tmpl, cbtxndata, &cbtxndatasz)) { 710 | return false; 711 | } 712 | if (!build_merkle_root(&cbuf[36], tmpl, cbtxndata, cbtxndatasz)) 713 | return false; 714 | 715 | my_htole32(&cbuf[0x44], tmpl->curtime); 716 | memcpy(&cbuf[72], &tmpl->diffbits, 4); 717 | 718 | return true; 719 | } 720 | 721 | size_t blkmk_get_data(blktemplate_t *tmpl, void *buf, size_t bufsz, time_t usetime, int16_t *out_expire, unsigned int *out_dataid) { 722 | if (!(blkmk_time_left(tmpl, usetime) && blkmk_work_left(tmpl) && tmpl->cbtxn)) 723 | return 0; 724 | if (bufsz < 76) 725 | return 76; 726 | 727 | if (tmpl->cbtxn->datasz > cbScriptSigLen && tmpl->cbtxn->data[cbScriptSigLen] + sizeof(*out_dataid) < libblkmaker_coinbase_size_minimum) { 728 | // Add some padding 729 | const size_t padding_required = libblkmaker_coinbase_size_minimum - (tmpl->cbtxn->data[cbScriptSigLen] + sizeof(*out_dataid)); 730 | uint8_t padding[padding_required]; 731 | static const uint8_t opcode_nop = '\x61'; 732 | memset(padding, opcode_nop, padding_required); 733 | if (padding_required != blkmk_append_coinbase_safe2(tmpl, padding, padding_required, 0, false)) { 734 | return 0; 735 | } 736 | } 737 | 738 | unsigned char *cbuf = buf; 739 | 740 | *out_dataid = tmpl->next_dataid++; 741 | if (!blkmk_sample_data_(tmpl, cbuf, *out_dataid)) 742 | return 0; 743 | blkmk_set_times(tmpl, &cbuf[68], usetime, out_expire, false); 744 | 745 | return 76; 746 | } 747 | 748 | 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) 749 | { 750 | if (!(true 751 | && blkmk_time_left(tmpl, usetime) 752 | && tmpl->cbtxn 753 | && blkmk_build_merkle_branches(tmpl) 754 | && bufsz >= 76 755 | && (tmpl->mutations & (BMM_CBAPPEND | BMM_CBSET)) 756 | )) 757 | return false; 758 | 759 | if (extranoncesz == sizeof(unsigned int)) 760 | // Avoid overlapping with blkmk_get_data use 761 | ++extranoncesz; 762 | 763 | if (tmpl->cbtxn->datasz > cbScriptSigLen && tmpl->cbtxn->data[cbScriptSigLen] + extranoncesz < libblkmaker_coinbase_size_minimum) { 764 | extranoncesz = libblkmaker_coinbase_size_minimum - tmpl->cbtxn->data[cbScriptSigLen]; 765 | } 766 | 767 | void ** const out_branches = _out_branches; 768 | void ** const out_cbtxn = _out_cbtxn; 769 | unsigned char *cbuf = buf; 770 | 771 | my_htole32(&cbuf[0], tmpl->version); 772 | memcpy(&cbuf[4], &tmpl->prevblk, 32); 773 | 774 | *out_cbtxnsz = tmpl->cbtxn->datasz + extranoncesz; 775 | *out_cbtxn = malloc(*out_cbtxnsz + max_witness_commitment_insert); 776 | if (!*out_cbtxn) 777 | return false; 778 | unsigned char dummy[extranoncesz]; 779 | memset(dummy, 0, extranoncesz); 780 | if (!_blkmk_append_cb(tmpl, *out_cbtxn, dummy, extranoncesz, cbextranonceoffset, NULL)) 781 | { 782 | free(*out_cbtxn); 783 | return false; 784 | } 785 | if (!_blkmk_insert_witness_commitment(tmpl, *out_cbtxn, out_cbtxnsz)) { 786 | free(*out_cbtxn); 787 | return false; 788 | } 789 | 790 | blkmk_set_times(tmpl, &cbuf[68], usetime, out_expire, can_roll_ntime); 791 | memcpy(&cbuf[72], &tmpl->diffbits, 4); 792 | 793 | *out_branchcount = tmpl->_mrklbranchcount; 794 | const size_t branches_bytesz = (sizeof(libblkmaker_hash_t) * tmpl->_mrklbranchcount); 795 | *out_branches = malloc(branches_bytesz); 796 | if (!*out_branches) 797 | { 798 | free(*out_cbtxn); 799 | return false; 800 | } 801 | if (branches_bytesz) { 802 | memcpy(*out_branches, tmpl->_mrklbranch, branches_bytesz); 803 | } 804 | 805 | return true; 806 | } 807 | 808 | blktime_diff_t blkmk_time_left(const blktemplate_t *tmpl, time_t nowtime) { 809 | double age = difftime(nowtime, tmpl->_time_rcvd); 810 | if (age >= tmpl->expires) 811 | return 0; 812 | return tmpl->expires - age; 813 | } 814 | 815 | unsigned long blkmk_work_left(const blktemplate_t *tmpl) { 816 | if (!tmpl->version) 817 | return 0; 818 | if (!(tmpl->mutations & (BMM_CBAPPEND | BMM_CBSET))) 819 | return (tmpl->next_dataid) ? 0 : 1; 820 | return UINT_MAX - tmpl->next_dataid; 821 | } 822 | 823 | 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) 824 | { 825 | const bool incl_gentxn = (foreign || (!(tmpl->mutations & BMAb_TRUNCATE && !extranoncesz))); 826 | const bool incl_alltxn = (foreign || !(tmpl->mutations & BMAb_COINBASE)); 827 | 828 | size_t blkbuf_sz = libblkmaker_blkheader_size; 829 | if (incl_gentxn) { 830 | blkbuf_sz += max_varint_size /* tx count */; 831 | blkbuf_sz += tmpl->cbtxn->datasz + extranoncesz + (max_varint_size - 1) /* possible enlargement to txout count when adding commitment output */ + commitment_txout_size; 832 | if (incl_alltxn) { 833 | blkbuf_sz += tmpl->txns_datasz; 834 | } 835 | } 836 | 837 | unsigned char * const blk = malloc(blkbuf_sz); 838 | if (!blk) { 839 | return NULL; 840 | } 841 | 842 | const size_t header_before_nonce_sz = libblkmaker_blkheader_size - sizeof(nonce); 843 | memcpy(blk, data, header_before_nonce_sz); 844 | nonce = htonl(nonce); 845 | memcpy(&blk[header_before_nonce_sz], &nonce, sizeof(nonce)); 846 | size_t offs = libblkmaker_blkheader_size; 847 | 848 | if (incl_gentxn) { 849 | offs += varintEncode(&blk[offs], 1 + tmpl->txncount); 850 | 851 | size_t cbtxnlen = 0; 852 | // Essentially _blkmk_extranonce 853 | if (extranoncesz) { 854 | if (!_blkmk_append_cb(tmpl, &blk[offs], extranonce, extranoncesz, NULL, NULL)) { 855 | free(blk); 856 | return NULL; 857 | } 858 | 859 | cbtxnlen += tmpl->cbtxn->datasz + extranoncesz; 860 | } else { 861 | memcpy(&blk[offs], tmpl->cbtxn->data, tmpl->cbtxn->datasz); 862 | cbtxnlen += tmpl->cbtxn->datasz; 863 | } 864 | if (!_blkmk_insert_witness_commitment(tmpl, &blk[offs], &cbtxnlen)) { 865 | return NULL; 866 | } 867 | offs += cbtxnlen; 868 | 869 | if (incl_alltxn) { 870 | for (unsigned long i = 0; i < tmpl->txncount; ++i) 871 | { 872 | memcpy(&blk[offs], tmpl->txns[i].data, tmpl->txns[i].datasz); 873 | offs += tmpl->txns[i].datasz; 874 | } 875 | } 876 | } 877 | 878 | char *blkhex = malloc((offs * 2) + 1); 879 | _blkmk_bin2hex(blkhex, blk, offs); 880 | free(blk); 881 | 882 | return blkhex; 883 | } 884 | 885 | 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) 886 | { 887 | if (dataid) { 888 | if (extranoncesz) { 889 | // Cannot specify both! 890 | return NULL; 891 | } 892 | extranonce = &dataid; 893 | extranoncesz = sizeof(dataid); 894 | } else if (extranoncesz == sizeof(unsigned int)) { 895 | // Avoid overlapping with blkmk_get_data use 896 | unsigned char extended_extranonce[extranoncesz + 1]; 897 | memcpy(extended_extranonce, extranonce, extranoncesz); 898 | extended_extranonce[extranoncesz] = 0; 899 | return blkmk_assemble_submission2_internal(tmpl, data, extended_extranonce, extranoncesz + 1, nonce, foreign); 900 | } 901 | return blkmk_assemble_submission2_internal(tmpl, data, extranonce, extranoncesz, nonce, foreign); 902 | } 903 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Luke Dashjr 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the standard MIT license. See COPYING for more details. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include "blktemplate.h" 17 | #include "blkmaker.h" 18 | #include "blkmaker_jansson.h" 19 | 20 | static bool my_sha256(void *digest, const void *buffer, size_t length) { 21 | gcry_md_hash_buffer(GCRY_MD_SHA256, digest, buffer, length); 22 | return true; 23 | } 24 | 25 | static bool bad_sha256(void *digest, const void *buffer, size_t length) { 26 | return false; 27 | } 28 | 29 | static void capabilityname_test() { 30 | for (unsigned int i = 0; i < GBT_CAPABILITY_COUNT; ++i) { 31 | const gbt_capabilities_t capid = (1 << i); 32 | const char * const capname = blktmpl_capabilityname(capid); 33 | if (!capname) { 34 | continue; 35 | } 36 | const size_t strlen_capname = strlen(capname); 37 | assert(strlen_capname > 0); 38 | assert(strlen_capname <= BLKTMPL_LONGEST_CAPABILITY_NAME); 39 | assert(blktmpl_getcapability(capname) == capid); 40 | } 41 | assert(!blktmpl_getcapability("foo")); 42 | assert(!blktmpl_capabilityname((uint32_t)1 << GBT_CAPABILITY_COUNT)); 43 | } 44 | 45 | static void blktxn_test(const int c) { 46 | struct blktxn_t * const txn = malloc(sizeof(*txn)); 47 | memset(txn, c, sizeof(*txn)); 48 | blktxn_init(txn); 49 | blktxn_clean(txn); 50 | free(txn); 51 | } 52 | 53 | static bool caps_includes(const uint32_t caps, const uint32_t expected_caps) { 54 | return (caps & expected_caps) == expected_caps; 55 | } 56 | 57 | static void blktmpl_test() { 58 | blktemplate_t * const tmpl = blktmpl_create(); 59 | 60 | { 61 | static const uint32_t expected_fresh_caps = GBT_CBTXN | GBT_WORKID | BMM_TIMEINC | BMM_CBAPPEND | BMM_VERFORCE | BMM_VERDROP | BMAb_COINBASE | BMAb_TRUNCATE; 62 | assert(caps_includes(blktmpl_addcaps(tmpl), expected_fresh_caps)); 63 | } 64 | 65 | assert(!tmpl->version); 66 | assert(!blktmpl_get_longpoll(tmpl)); 67 | assert(!blktmpl_get_submitold(tmpl)); 68 | 69 | blktmpl_free(tmpl); 70 | } 71 | 72 | static bool json_are_equal(json_t * const ja, json_t * const jb) { 73 | char *sa, *sb; 74 | sa = json_dumps(ja, JSON_COMPACT | JSON_SORT_KEYS); 75 | sb = json_dumps(jb, JSON_COMPACT | JSON_SORT_KEYS); 76 | const bool rv = !strcmp(sa, sb); 77 | free(sa); 78 | free(sb); 79 | return rv; 80 | } 81 | 82 | static void rulecompare(json_t * const jb, const char * const * const rulelist) { 83 | const size_t z = json_array_size(jb); 84 | const char *sa; 85 | json_t *jc; 86 | 87 | for (size_t i = 0; i < z; ++i) { 88 | assert((jc = json_array_get(jb, i))); 89 | assert((sa = json_string_value(jc))); 90 | assert(!strcmp(sa, rulelist[i])); 91 | } 92 | assert(!rulelist[z]); 93 | } 94 | 95 | static void check_request(json_t * const ja, const char * const * const rulelist, uint32_t * const out_caps) { 96 | const char *sa; 97 | json_t *jb, *jc; 98 | 99 | assert(json_object_get(ja, "id")); 100 | assert((jb = json_object_get(ja, "method"))); 101 | assert((sa = json_string_value(jb))); 102 | assert(!strcmp(sa, "getblocktemplate")); 103 | assert((jb = json_object_get(ja, "params"))); 104 | assert(json_is_array(jb)); 105 | assert(json_array_size(jb) >= 1); 106 | jc = json_array_get(jb, 0); 107 | assert(json_is_object(jc)); 108 | assert((jb = json_object_get(jc, "maxversion"))); 109 | assert(json_number_value(jb) == BLKMAKER_MAX_BLOCK_VERSION); 110 | assert((jb = json_object_get(jc, "rules"))); 111 | assert(json_is_array(jb)); 112 | rulecompare(jb, rulelist); 113 | if (out_caps) { 114 | *out_caps = 0; 115 | if ((jb = json_object_get(jc, "capabilities")) && json_is_array(jb)) { 116 | const size_t z = json_array_size(jb); 117 | for (size_t i = 0; i < z; ++i) { 118 | assert((jc = json_array_get(jb, i))); 119 | assert((sa = json_string_value(jc))); 120 | uint32_t capid = blktmpl_getcapability(sa); 121 | assert(capid); 122 | *out_caps |= capid; 123 | } 124 | } 125 | } 126 | } 127 | 128 | static void blktmpl_request_jansson_test_old() { 129 | blktemplate_t * const tmpl = blktmpl_create(); 130 | json_t *ja, *jb; 131 | 132 | ja = blktmpl_request_jansson2(0, NULL, blkmk_supported_rules); 133 | jb = blktmpl_request_jansson(0, NULL); 134 | assert(json_are_equal(ja, jb)); 135 | json_decref(jb); 136 | 137 | check_request(ja, blkmk_supported_rules, NULL); 138 | 139 | json_decref(ja); 140 | blktmpl_free(tmpl); 141 | } 142 | 143 | static void blktmpl_request_jansson_test_custom_rulelist() { 144 | blktemplate_t * const tmpl = blktmpl_create(); 145 | json_t *ja; 146 | const char *custom_rulelist[] = { 147 | "abc", 148 | "xyz", 149 | NULL 150 | }; 151 | 152 | ja = blktmpl_request_jansson2(0, NULL, custom_rulelist); 153 | check_request(ja, custom_rulelist, NULL); 154 | 155 | json_decref(ja); 156 | blktmpl_free(tmpl); 157 | } 158 | 159 | static void blktmpl_request_jansson_test_custom_caps_i(json_t * const ja, const uint32_t test_caps) { 160 | uint32_t caps; 161 | check_request(ja, blkmk_supported_rules, &caps); 162 | assert(caps == test_caps); 163 | json_decref(ja); 164 | } 165 | 166 | static void blktmpl_request_jansson_test_custom_caps() { 167 | blktemplate_t * const tmpl = blktmpl_create(); 168 | json_t *ja; 169 | uint32_t test_caps = GBT_SERVICE | GBT_LONGPOLL; 170 | 171 | ja = blktmpl_request_jansson2(test_caps, NULL, blkmk_supported_rules); 172 | blktmpl_request_jansson_test_custom_caps_i(ja, test_caps); 173 | 174 | test_caps |= blktmpl_addcaps(tmpl); 175 | ja = blktmpl_request_jansson2(test_caps, NULL, blkmk_supported_rules); 176 | blktmpl_request_jansson_test_custom_caps_i(ja, test_caps); 177 | 178 | blktmpl_free(tmpl); 179 | } 180 | 181 | static void blktmpl_request_jansson_test_longpoll() { 182 | blktemplate_t * const tmpl = blktmpl_create(); 183 | static const char * const lpid = "mylpid00"; 184 | const char *sa; 185 | json_t *ja, *jb, *jc; 186 | 187 | ja = blktmpl_request_jansson2(0, lpid, blkmk_supported_rules); 188 | check_request(ja, blkmk_supported_rules, NULL); 189 | 190 | jb = json_array_get(json_object_get(ja, "params"), 0); 191 | assert((jc = json_object_get(jb, "longpollid"))); 192 | assert((sa = json_string_value(jc))); 193 | assert(!strcmp(sa, lpid)); 194 | 195 | json_decref(ja); 196 | blktmpl_free(tmpl); 197 | } 198 | 199 | static const char *blktmpl_add_jansson_str(blktemplate_t * const tmpl, const char * const s, const time_t time_rcvd) { 200 | json_t * const j = json_loads(s, 0, NULL); 201 | assert(j); 202 | const char * const rv = blktmpl_add_jansson(tmpl, j, time_rcvd); 203 | json_decref(j); 204 | return rv; 205 | } 206 | 207 | static const time_t simple_time_rcvd = 0x777; 208 | 209 | static void blktmpl_jansson_simple() { 210 | blktemplate_t *tmpl = blktmpl_create(); 211 | 212 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":2,\"height\":3,\"bits\":\"1d00ffff\",\"curtime\":777,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512}", simple_time_rcvd)); 213 | assert(blktmpl_addcaps(tmpl) == 0); // Until we support merging templates 214 | assert(tmpl->version == 2); 215 | assert(tmpl->height == 3); 216 | assert(!memcmp(tmpl->diffbits, "\xff\xff\0\x1d", 4)); 217 | assert(tmpl->curtime == 777); 218 | for (int i = 0; i < 7; ++i) { 219 | assert(tmpl->prevblk[i] == 0x77777777); 220 | } 221 | assert(!tmpl->prevblk[7]); 222 | assert(tmpl->has_cbvalue); 223 | assert(tmpl->cbvalue == 512); 224 | 225 | // Check clear values 226 | assert(tmpl->txncount == 0); 227 | assert(tmpl->txns_datasz == 0); 228 | assert(tmpl->txns_sigops == 0); 229 | assert(!tmpl->cbtxn); 230 | assert(!tmpl->workid); 231 | assert(!blktmpl_get_longpoll(tmpl)); 232 | assert(blktmpl_get_submitold(tmpl)); 233 | assert(!tmpl->target); 234 | assert(!tmpl->mutations); 235 | assert(tmpl->aux_count == 0); 236 | assert(!tmpl->rules); 237 | assert(!tmpl->unsupported_rule); 238 | assert(!tmpl->vbavailable); 239 | assert(!tmpl->vbrequired); 240 | 241 | // Check reasonable default ranges 242 | assert(tmpl->sigoplimit >= 20000); 243 | assert(tmpl->sizelimit >= 1000000); 244 | assert(tmpl->expires >= 60); 245 | assert(tmpl->maxtime >= tmpl->curtime + 60); 246 | assert(tmpl->maxtimeoff >= 60); 247 | assert(tmpl->mintime <= tmpl->curtime - 60); 248 | assert(tmpl->mintimeoff <= -60); 249 | 250 | blktmpl_free(tmpl); 251 | tmpl = blktmpl_create(); 252 | 253 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":2,\"height\":3,\"bits\":\"1d00ffff\",\"curtime\":777,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":0}", simple_time_rcvd)); 254 | assert(tmpl->has_cbvalue); 255 | assert(tmpl->cbvalue == 0); 256 | 257 | blktmpl_free(tmpl); 258 | tmpl = blktmpl_create(); 259 | 260 | assert(blktmpl_add_jansson_str(tmpl, "{\"height\":3,\"bits\":\"1d00ffff\",\"curtime\":777,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512}", simple_time_rcvd)); 261 | blktmpl_free(tmpl); 262 | tmpl = blktmpl_create(); 263 | assert(blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"bits\":\"1d00ffff\",\"curtime\":777,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512}", simple_time_rcvd)); 264 | blktmpl_free(tmpl); 265 | tmpl = blktmpl_create(); 266 | assert(blktmpl_add_jansson_str(tmpl, "{\"version\":2,\"height\":3,\"curtime\":777,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512}", simple_time_rcvd)); 267 | blktmpl_free(tmpl); 268 | tmpl = blktmpl_create(); 269 | assert(blktmpl_add_jansson_str(tmpl, "{\"version\":2,\"height\":3,\"bits\":\"1d00ffff\",\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512}", simple_time_rcvd)); 270 | blktmpl_free(tmpl); 271 | tmpl = blktmpl_create(); 272 | assert(blktmpl_add_jansson_str(tmpl, "{\"version\":2,\"height\":3,\"bits\":\"1d00ffff\",\"curtime\":777,\"coinbasevalue\":512}", simple_time_rcvd)); 273 | blktmpl_free(tmpl); 274 | tmpl = blktmpl_create(); 275 | assert(blktmpl_add_jansson_str(tmpl, "{\"version\":2,\"height\":3,\"bits\":\"1d00ffff\",\"curtime\":777,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\"}", simple_time_rcvd)); 276 | blktmpl_free(tmpl); 277 | tmpl = blktmpl_create(); 278 | assert(blktmpl_add_jansson_str(tmpl, "{\"version\":2,\"height\":3,\"bits\":\"1d00ffff\",\"curtime\":777,\"previousblockhash\":\"0??0000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512}", simple_time_rcvd)); 279 | blktmpl_free(tmpl); 280 | tmpl = blktmpl_create(); 281 | assert(blktmpl_add_jansson_str(tmpl, "{\"version\":2,\"height\":3,\"bits\":\"1d00ffff\",\"curtime\":777,\"previousblockhash\":\"00000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512}", simple_time_rcvd)); 282 | 283 | blktmpl_free(tmpl); 284 | } 285 | 286 | static void blktmpl_jansson_bip22_required() { 287 | blktemplate_t * const tmpl = blktmpl_create(); 288 | 289 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"sigoplimit\":100,\"sizelimit\":1000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaAaaaa00222222220100100000015100000000\",\"required\":true},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62F2cdd80937c9c0857cEDeC005b11d3B902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1],\"fee\":12,\"required\":false,\"sigops\":4},{\"data\":\"01000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000\"}],\"coinbaseaux\":{\"dummy\":\"deadbeef\"},\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"workid\":\"mywork\"}", simple_time_rcvd)); 290 | assert(tmpl->version == 3); 291 | assert(tmpl->height == 4); 292 | assert(!memcmp(tmpl->diffbits, "\xff\x7f\0\x1d", 4)); 293 | assert(tmpl->curtime == 877); 294 | for (int i = 0; i < 7; ++i) { 295 | assert(tmpl->prevblk[i] == 0xa7777777); 296 | } 297 | assert(!tmpl->prevblk[7]); 298 | assert(tmpl->has_cbvalue); 299 | assert(tmpl->cbvalue == 640); 300 | assert(tmpl->sigoplimit == 100); 301 | assert(tmpl->sizelimit == 1000); 302 | assert(tmpl->txncount == 3); 303 | assert(tmpl->txns); 304 | assert(tmpl->txns[0].data); 305 | assert(tmpl->txns[0].datasz == 57); 306 | assert(!memcmp(tmpl->txns[0].data, "\x01\0\0\0\x01\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\xaa\xaa\xaa\xaa\0\x22\x22\x22\x22\x01\0\x10\0\0\x01\x51\0\0\0\0", 57)); 307 | assert(tmpl->txns[0].dependscount == -1); 308 | assert(tmpl->txns[0].fee_ == -1); 309 | assert(tmpl->txns[0].required); 310 | assert(tmpl->txns[0].sigops_ == -1); 311 | assert(tmpl->txns[1].data); 312 | assert(tmpl->txns[1].datasz == 57); 313 | assert(!memcmp(tmpl->txns[1].data, "\x01\0\0\0\x01\x1c\x69\xf2\x12\xe6\x2f\x2c\xdd\x80\x93\x7c\x9c\x08\x57\xce\xde\xc0\x05\xb1\x1d\x3b\x90\x2d\x21\0\x7c\x93\x2c\x1c\x7c\xd2\x0f\0\0\0\0\0\x44\x44\x44\x44\x01\0\x10\0\0\x01\x51\0\0\0\0", 57)); 314 | assert(tmpl->txns[1].dependscount == 1); 315 | assert(tmpl->txns[1].depends); 316 | assert(tmpl->txns[1].depends[0] == 1); 317 | assert(tmpl->txns[1].fee_ == 12); 318 | assert(!tmpl->txns[1].required); 319 | assert(tmpl->txns[1].sigops_ == 4); 320 | assert(!memcmp(tmpl->txns[1].hash_, "\x8d\x7e\x01\x67\x43\x9d\xab\x18\x6e\x86\xf9\x13\xb2\x7f\x3a\xc2\x15\x67\xdd\x4e\xde\xf8\x9a\xa8\x01\x64\x99\x67\x8b\x1a\xda\x8e", 32)); 321 | assert(tmpl->txns[2].data); 322 | assert(tmpl->txns[2].datasz == 57); 323 | assert(!memcmp(tmpl->txns[2].data, "\x01\0\0\0\x01\0\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\xaa\xaa\xaa\xaa\0\x55\x55\x55\x55\x01\0\x10\0\0\x01\x51\0\0\0\0", 57)); 324 | assert(tmpl->txns[2].dependscount == -1); 325 | assert(tmpl->txns[2].fee_ == -1); 326 | assert(!tmpl->txns[2].required); 327 | assert(tmpl->txns[2].sigops_ == -1); 328 | assert(tmpl->cbtxn->data); 329 | assert(tmpl->cbtxn->datasz == 64); 330 | assert(!memcmp(tmpl->cbtxn->data, "\x01\0\0\0\x01\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\xff\xff\xff\xff\x07\x01\x04\x04\xde\xad\xbe\xef\x33\x33\x33\x33\x01\0\x10\0\0\x01\x51\0\0\0\0", 64)); 331 | assert(tmpl->aux_count == 1); 332 | assert(tmpl->auxs); 333 | assert(tmpl->auxs[0].auxname); 334 | assert(!strcmp(tmpl->auxs[0].auxname, "dummy")); 335 | assert(tmpl->auxs[0].datasz == 4); 336 | assert(!memcmp(tmpl->auxs[0].data, "\xde\xad\xbe\xef", 4)); 337 | assert(tmpl->workid); 338 | assert(!strcmp(tmpl->workid, "mywork")); 339 | assert(blktmpl_get_submitold(tmpl)); 340 | 341 | blktmpl_free(tmpl); 342 | } 343 | 344 | static void blktmpl_jansson_bip22_longpoll() { 345 | blktemplate_t *tmpl = blktmpl_create(); 346 | const struct blktmpl_longpoll_req *lp; 347 | 348 | assert(!blktmpl_get_longpoll(tmpl)); 349 | 350 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"longpollid\":\"mylpid\"}", simple_time_rcvd)); 351 | lp = blktmpl_get_longpoll(tmpl); 352 | assert(lp->id); 353 | assert(!strcmp(lp->id, "mylpid")); 354 | assert(!lp->uri); 355 | assert(blktmpl_get_submitold(tmpl)); 356 | 357 | blktmpl_free(tmpl); 358 | tmpl = blktmpl_create(); 359 | 360 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"longpollid\":\"myLPid\",\"longpolluri\":\"/LP\",\"submitold\":false}", simple_time_rcvd)); 361 | lp = blktmpl_get_longpoll(tmpl); 362 | assert(lp->id); 363 | assert(!strcmp(lp->id, "myLPid")); 364 | assert(lp->uri); 365 | assert(!strcmp(lp->uri, "/LP")); 366 | assert(!blktmpl_get_submitold(tmpl)); 367 | 368 | blktmpl_free(tmpl); 369 | } 370 | 371 | static void blktmpl_jansson_bip23_bpe() { 372 | blktemplate_t *tmpl = blktmpl_create(); 373 | 374 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"expires\":99,\"target\":\"0000000077777777777777777777777777777777777777777777777777777777\"}", simple_time_rcvd)); 375 | assert(tmpl->expires == 99); 376 | assert(!(*tmpl->target)[0]); 377 | for (int i = 1; i < 8; ++i) { 378 | assert((*tmpl->target)[i] == 0x77777777); 379 | } 380 | 381 | blktmpl_free(tmpl); 382 | } 383 | 384 | static void blktmpl_jansson_bip23_mutations() { 385 | blktemplate_t *tmpl = blktmpl_create(); 386 | 387 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"maxtime\":2113929216,\"maxtimeoff\":50,\"mintime\":800,\"mintimeoff\":-50,\"mutable\":[\"prevblock\",\"version/force\"],\"noncerange\":\"01000000f0000000\"}", simple_time_rcvd)); 388 | assert(tmpl->maxtime == 2113929216); 389 | assert(tmpl->maxtimeoff == 50); 390 | assert(tmpl->mintime == 800); 391 | assert(tmpl->mintimeoff == -50); 392 | // As of right now, implied mutations are not included in the value 393 | // assert(tmpl->mutations == (BMM_CBAPPEND | BMM_CBSET | BMM_GENERATE | BMM_TIMEINC | BMM_TIMEDEC | BMM_TXNADD | BMM_PREVBLK | BMM_VERFORCE)); 394 | assert(caps_includes(tmpl->mutations, BMM_PREVBLK | BMM_VERFORCE)); 395 | 396 | blktmpl_free(tmpl); 397 | tmpl = blktmpl_create(); 398 | 399 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"mutable\":[\"version/reduce\",\"coinbase/append\",\"generation\",\"time\",\"transactions\"],\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"transactions\":[]}", simple_time_rcvd)); 400 | assert(tmpl->mutations == (BMM_CBAPPEND | BMM_GENERATE | BMM_TIMEINC | BMM_TIMEDEC | BMM_TXNADD | BMM_VERDROP)); 401 | 402 | blktmpl_free(tmpl); 403 | } 404 | 405 | static void blktmpl_jansson_bip23_abbrev() { 406 | blktemplate_t * const tmpl = blktmpl_create(); 407 | 408 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"mutable\":[\"submit/hash\",\"submit/coinbase\",\"submit/truncate\"]}", simple_time_rcvd)); 409 | assert(tmpl->mutations == (BMA_TXNHASH | BMAb_COINBASE | BMAb_TRUNCATE)); 410 | 411 | blktmpl_free(tmpl); 412 | } 413 | 414 | static void blktmpl_jansson_bip9() { 415 | blktemplate_t *tmpl; 416 | 417 | tmpl = blktmpl_create(); 418 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":536871040,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"rules\":[\"csv\"],\"vbavailable\":{\"!segwit\":7}}", simple_time_rcvd)); 419 | assert(tmpl->version == 0x20000080); 420 | assert(tmpl->rules); 421 | assert(tmpl->rules[0]); 422 | assert(!strcmp(tmpl->rules[0], "csv")); 423 | assert(!tmpl->rules[1]); 424 | assert(!tmpl->unsupported_rule); 425 | assert(tmpl->vbavailable); 426 | assert(tmpl->vbavailable[0]); 427 | assert(tmpl->vbavailable[0]->name); 428 | assert(!strcmp(tmpl->vbavailable[0]->name, "!segwit")); 429 | assert(tmpl->vbavailable[0]->bitnum == 7); 430 | assert(!tmpl->vbavailable[1]); 431 | assert(!tmpl->vbrequired); 432 | 433 | blktmpl_free(tmpl); 434 | tmpl = blktmpl_create(); 435 | 436 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":536871040,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"rules\":[\"csv\"],\"vbavailable\":{\"!segwit\":7},\"vbrequired\":128}", simple_time_rcvd)); 437 | assert(tmpl->version == 0x20000080); 438 | assert(tmpl->rules); 439 | assert(tmpl->rules[0]); 440 | assert(!strcmp(tmpl->rules[0], "csv")); 441 | assert(!tmpl->rules[1]); 442 | assert(!tmpl->unsupported_rule); 443 | assert(tmpl->vbavailable); 444 | assert(tmpl->vbavailable[0]); 445 | assert(tmpl->vbavailable[0]->name); 446 | assert(!strcmp(tmpl->vbavailable[0]->name, "!segwit")); 447 | assert(tmpl->vbavailable[0]->bitnum == 7); 448 | assert(!tmpl->vbavailable[1]); 449 | assert(tmpl->vbrequired == 0x80); 450 | 451 | blktmpl_free(tmpl); 452 | tmpl = blktmpl_create(); 453 | 454 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":536871040,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"rules\":[\"csv\",\"foo\"],\"vbavailable\":{}}", simple_time_rcvd)); 455 | assert(tmpl->version == 0x20000080); 456 | assert(tmpl->rules); 457 | assert(tmpl->rules[0]); 458 | assert(!strcmp(tmpl->rules[0], "csv")); 459 | assert(tmpl->rules[1]); 460 | assert(!strcmp(tmpl->rules[1], "foo")); 461 | assert(!tmpl->rules[2]); 462 | assert(tmpl->unsupported_rule); 463 | assert(tmpl->vbavailable); 464 | assert(!tmpl->vbavailable[0]); 465 | assert(!tmpl->vbrequired); 466 | 467 | blktmpl_free(tmpl); 468 | tmpl = blktmpl_create(); 469 | 470 | assert(blktmpl_add_jansson_str(tmpl, "{\"version\":536871040,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"rules\":[\"csv\",\"!foo\"],\"vbavailable\":{}}", simple_time_rcvd)); 471 | 472 | blktmpl_free(tmpl); 473 | } 474 | 475 | static void test_blktmpl_jansson_floaty() { 476 | blktemplate_t *tmpl = blktmpl_create(); 477 | 478 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":536871040.0,\"height\":3.0,\"bits\":\"1d00ffff\",\"curtime\":777.0,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512.000,\"sigoplimit\":1000.0,\"sizelimit\":10000.0,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\"},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1.0],\"fee\":12.0,\"sigops\":4.0}],\"expires\":33.0,\"maxtime\":2113929216.0,\"maxtimeoff\":50.0,\"mintime\":800.0,\"mintimeoff\":-50.0,\"rules\":[\"csv\"],\"vbavailable\":{\"!segwit\":7.0},\"vbrequired\":128.0}", simple_time_rcvd)); 479 | assert(tmpl->version == 536871040); 480 | assert(tmpl->height == 3); 481 | assert(!memcmp(tmpl->diffbits, "\xff\xff\0\x1d", 4)); 482 | assert(tmpl->curtime == 777); 483 | for (int i = 0; i < 7; ++i) { 484 | assert(tmpl->prevblk[i] == 0x77777777); 485 | } 486 | assert(!tmpl->prevblk[7]); 487 | assert(tmpl->has_cbvalue); 488 | assert(tmpl->cbvalue == 512); 489 | 490 | assert(tmpl->txncount == 2); 491 | assert(tmpl->txns_datasz == 114); 492 | assert(tmpl->txns_sigops == -1); 493 | assert(tmpl->txns); 494 | assert(tmpl->txns[0].data); 495 | assert(tmpl->txns[0].datasz == 57); 496 | assert(!memcmp(tmpl->txns[0].data, "\x01\0\0\0\x01\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\xaa\xaa\xaa\xaa\0\x22\x22\x22\x22\x01\0\x10\0\0\x01\x51\0\0\0\0", 57)); 497 | assert(tmpl->txns[0].dependscount == -1); 498 | assert(tmpl->txns[0].fee_ == -1); 499 | assert(tmpl->txns[0].sigops_ == -1); 500 | assert(tmpl->txns[1].data); 501 | assert(tmpl->txns[1].datasz == 57); 502 | assert(!memcmp(tmpl->txns[1].data, "\x01\0\0\0\x01\x1c\x69\xf2\x12\xe6\x2f\x2c\xdd\x80\x93\x7c\x9c\x08\x57\xce\xde\xc0\x05\xb1\x1d\x3b\x90\x2d\x21\0\x7c\x93\x2c\x1c\x7c\xd2\x0f\0\0\0\0\0\x44\x44\x44\x44\x01\0\x10\0\0\x01\x51\0\0\0\0", 57)); 503 | assert(tmpl->txns[1].dependscount == 1); 504 | assert(tmpl->txns[1].depends); 505 | assert(tmpl->txns[1].depends[0] == 1); 506 | assert(tmpl->txns[1].fee_ == 12); 507 | assert(!tmpl->txns[1].required); 508 | assert(tmpl->txns[1].sigops_ == 4); 509 | assert(!memcmp(tmpl->txns[1].hash_, "\x8d\x7e\x01\x67\x43\x9d\xab\x18\x6e\x86\xf9\x13\xb2\x7f\x3a\xc2\x15\x67\xdd\x4e\xde\xf8\x9a\xa8\x01\x64\x99\x67\x8b\x1a\xda\x8e", 32)); 510 | 511 | assert(tmpl->rules); 512 | assert(tmpl->rules[0]); 513 | assert(!strcmp(tmpl->rules[0], "csv")); 514 | assert(!tmpl->rules[1]); 515 | assert(!tmpl->unsupported_rule); 516 | assert(tmpl->vbavailable); 517 | assert(tmpl->vbavailable[0]); 518 | assert(tmpl->vbavailable[0]->name); 519 | assert(!strcmp(tmpl->vbavailable[0]->name, "!segwit")); 520 | assert(tmpl->vbavailable[0]->bitnum == 7); 521 | assert(!tmpl->vbavailable[1]); 522 | assert(tmpl->vbrequired == 0x80); 523 | 524 | assert(tmpl->sigoplimit == 1000); 525 | assert(tmpl->sizelimit == 10000); 526 | assert(tmpl->expires == 33); 527 | assert(tmpl->maxtime == 2113929216); 528 | assert(tmpl->maxtimeoff == 50); 529 | assert(tmpl->mintime == 800); 530 | assert(tmpl->mintimeoff == -50); 531 | 532 | blktmpl_free(tmpl); 533 | tmpl = blktmpl_create(); 534 | 535 | // Truncate times (curtime perhaps ought to pull limits closer to it, but it's a fraction of a second anyway, so don't bother) 536 | // Ignore coinbasevalue problems if we have coinbasetxn 537 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":2.0,\"height\":3.0,\"bits\":\"1d00ffff\",\"curtime\":777.5,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512.333,\"expires\":33.4,\"maxtime\":2113929216.6,\"maxtimeoff\":50.3,\"mintime\":800.4,\"mintimeoff\":-50.5,\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000000000\"}}", simple_time_rcvd)); 538 | 539 | assert(tmpl->version == 2); 540 | assert(tmpl->height == 3); 541 | assert(!memcmp(tmpl->diffbits, "\xff\xff\0\x1d", 4)); 542 | assert(tmpl->curtime == 777); 543 | for (int i = 0; i < 7; ++i) { 544 | assert(tmpl->prevblk[i] == 0x77777777); 545 | } 546 | assert(!tmpl->prevblk[7]); 547 | assert(!tmpl->has_cbvalue); 548 | assert(!tmpl->cbvalue); 549 | 550 | assert(tmpl->expires == 33); 551 | assert(tmpl->maxtime == 2113929216); 552 | assert(tmpl->maxtimeoff == 50); 553 | assert(tmpl->mintime == 800); 554 | assert(tmpl->mintimeoff == -50); 555 | 556 | blktmpl_free(tmpl); 557 | tmpl = blktmpl_create(); 558 | 559 | // Most values with a fraction should fail 560 | assert(blktmpl_add_jansson_str(tmpl, "{\"version\":2.3,\"height\":3.0,\"bits\":\"1d00ffff\",\"curtime\":777.0,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512.000}", simple_time_rcvd)); 561 | blktmpl_free(tmpl); 562 | tmpl = blktmpl_create(); 563 | assert(blktmpl_add_jansson_str(tmpl, "{\"version\":2.0,\"height\":3.5,\"bits\":\"1d00ffff\",\"curtime\":777.0,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512.000}", simple_time_rcvd)); 564 | blktmpl_free(tmpl); 565 | tmpl = blktmpl_create(); 566 | assert(blktmpl_add_jansson_str(tmpl, "{\"version\":2.0,\"height\":3.0,\"bits\":\"1d00ffff\",\"curtime\":777.0,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512.5}", simple_time_rcvd)); 567 | blktmpl_free(tmpl); 568 | tmpl = blktmpl_create(); 569 | assert(blktmpl_add_jansson_str(tmpl, "{\"version\":536871040.0,\"height\":3.0,\"bits\":\"1d00ffff\",\"curtime\":777.0,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512.000,\"rules\":[\"csv\"],\"vbavailable\":{\"!segwit\":7.2},\"vbrequired\":128.0}", simple_time_rcvd)); 570 | blktmpl_free(tmpl); 571 | tmpl = blktmpl_create(); 572 | assert(blktmpl_add_jansson_str(tmpl, "{\"version\":536871040.0,\"height\":3.0,\"bits\":\"1d00ffff\",\"curtime\":777.0,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512.000,\"rules\":[\"csv\"],\"vbavailable\":{\"!segwit\":7.0},\"vbrequired\":128.6}", simple_time_rcvd)); 573 | 574 | blktmpl_free(tmpl); 575 | tmpl = blktmpl_create(); 576 | 577 | // Transaction-related values are optional, so it's safe to ignore them 578 | // Even though they could indicate varying rules, we have BIP9 to deal with that, and don't enforce the limits when missing tx info anyway 579 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3.0,\"height\":3.0,\"bits\":\"1d00ffff\",\"curtime\":777.0,\"previousblockhash\":\"0000000077777777777777777777777777777777777777777777777777777777\",\"coinbasevalue\":512.000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\"},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1.5],\"fee\":12.3,\"sigops\":4.6}],\"sigoplimit\":4444.4,\"sizelimit\":323333.3}", simple_time_rcvd)); 580 | 581 | assert(tmpl->version == 3); 582 | assert(tmpl->height == 3); 583 | 584 | // These should be defaults 585 | assert(tmpl->sigoplimit >= 20000); 586 | assert(tmpl->sizelimit >= 1000000); 587 | 588 | assert(tmpl->txncount == 2); 589 | assert(tmpl->txns_datasz == 114); 590 | assert(tmpl->txns_sigops == -1); 591 | assert(tmpl->txns); 592 | assert(tmpl->txns[0].data); 593 | assert(tmpl->txns[0].datasz == 57); 594 | assert(!memcmp(tmpl->txns[0].data, "\x01\0\0\0\x01\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\x99\xaa\xaa\xaa\xaa\0\x22\x22\x22\x22\x01\0\x10\0\0\x01\x51\0\0\0\0", 57)); 595 | assert(tmpl->txns[0].dependscount == -1); 596 | assert(tmpl->txns[0].fee_ == -1); 597 | assert(tmpl->txns[0].sigops_ == -1); 598 | assert(tmpl->txns[1].data); 599 | assert(tmpl->txns[1].datasz == 57); 600 | assert(!memcmp(tmpl->txns[1].data, "\x01\0\0\0\x01\x1c\x69\xf2\x12\xe6\x2f\x2c\xdd\x80\x93\x7c\x9c\x08\x57\xce\xde\xc0\x05\xb1\x1d\x3b\x90\x2d\x21\0\x7c\x93\x2c\x1c\x7c\xd2\x0f\0\0\0\0\0\x44\x44\x44\x44\x01\0\x10\0\0\x01\x51\0\0\0\0", 57)); 601 | assert(tmpl->txns[1].dependscount == -1); 602 | assert(tmpl->txns[1].fee_ == -1); 603 | assert(tmpl->txns[1].sigops_ == -1); 604 | assert(!memcmp(tmpl->txns[1].hash_, "\x8d\x7e\x01\x67\x43\x9d\xab\x18\x6e\x86\xf9\x13\xb2\x7f\x3a\xc2\x15\x67\xdd\x4e\xde\xf8\x9a\xa8\x01\x64\x99\x67\x8b\x1a\xda\x8e", 32)); 605 | 606 | blktmpl_free(tmpl); 607 | } 608 | 609 | static void blktmpl_jansson_submit_data_check(const char * const sa, const int level) { 610 | assert(strlen(sa) >= 160); 611 | assert(!memcmp(sa, "03000000777777a7777777a7777777a7777777a7777777a7777777a7777777a700000000", 72)); 612 | // Don't check merkle root 613 | assert(!memcmp(&sa[136], "6d030000ff7f001d", 16)); 614 | // Don't check nonce 615 | size_t pos = 160; 616 | if (level > 0) { 617 | assert(!strncmp(&sa[pos], "0401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000", 130)); 618 | pos += 130; 619 | if (level > 1) { 620 | assert(!strcmp(&sa[pos], "01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa0022222222010010000001510000000001000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f000000000044444444010010000001510000000001000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000")); 621 | pos += strlen(&sa[pos]); 622 | } 623 | } 624 | if (level >= 0) { 625 | assert(sa[pos] == '\0'); 626 | } 627 | } 628 | 629 | static void blktmpl_jansson_propose_check(json_t *j, const int level) { 630 | const char *sa; 631 | 632 | j = json_array_get(json_object_get(j, "params"), 0); 633 | assert((j = json_object_get(j, "data"))); 634 | assert((sa = json_string_value(j))); 635 | return blktmpl_jansson_submit_data_check(sa, level); 636 | } 637 | 638 | static void blktmpl_jansson_propose() { 639 | blktemplate_t * const tmpl = blktmpl_create(); 640 | const char *sa; 641 | json_t *j, *ja, *jb; 642 | 643 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"sigoplimit\":100,\"sizelimit\":1000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\",\"required\":true},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1],\"fee\":12,\"required\":false,\"sigops\":4},{\"data\":\"01000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000\"}],\"coinbaseaux\":{\"dummy\":\"deadbeef\"},\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"workid\":\"mywork\"}", simple_time_rcvd)); 644 | 645 | assert((j = blktmpl_propose_jansson(tmpl, 0, false))); 646 | check_request(j, blkmk_supported_rules, NULL); 647 | 648 | ja = json_array_get(json_object_get(j, "params"), 0); 649 | assert((jb = json_object_get(ja, "mode"))); 650 | assert((sa = json_string_value(jb))); 651 | assert(!strcmp(sa, "proposal")); 652 | assert((jb = json_object_get(ja, "workid"))); 653 | assert((sa = json_string_value(jb))); 654 | assert(!strcmp(sa, "mywork")); 655 | blktmpl_jansson_propose_check(j, 2); 656 | json_decref(j); 657 | 658 | tmpl->mutations |= BMAb_COINBASE; 659 | assert((j = blktmpl_propose_jansson(tmpl, 0, false))); 660 | check_request(j, blkmk_supported_rules, NULL); 661 | blktmpl_jansson_propose_check(j, 1); 662 | json_decref(j); 663 | 664 | tmpl->mutations |= BMAb_TRUNCATE; 665 | assert((j = blktmpl_propose_jansson(tmpl, 0, false))); 666 | check_request(j, blkmk_supported_rules, NULL); 667 | blktmpl_jansson_propose_check(j, 0); 668 | json_decref(j); 669 | 670 | blktmpl_free(tmpl); 671 | } 672 | 673 | static void blktmpl_jansson_submit() { 674 | blktemplate_t * const tmpl = blktmpl_create(); 675 | const char *sa; 676 | uint8_t data[76]; 677 | int16_t i16; 678 | unsigned int dataid; 679 | json_t *j, *ja, *jb, *jc; 680 | 681 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"sigoplimit\":100,\"sizelimit\":1000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\",\"required\":true},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1],\"fee\":12,\"required\":false,\"sigops\":4},{\"data\":\"01000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000\"}],\"coinbaseaux\":{\"dummy\":\"deadbeef\"},\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"workid\":\"mywork\",\"mutable\":[\"submit/coinbase\",\"submit/truncate\",\"coinbase/append\"]}", simple_time_rcvd)); 682 | 683 | assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &dataid)); 684 | 685 | assert((j = blkmk_submit_foreign_jansson(tmpl, data, 0, 0x12345678))); 686 | assert((ja = json_object_get(j, "params"))); 687 | assert(json_is_array(ja)); 688 | assert(json_array_size(ja) >= 1); 689 | assert((sa = json_string_value(json_array_get(ja, 0)))); 690 | blktmpl_jansson_submit_data_check(sa, 2); 691 | if (json_array_size(ja) >= 2) { 692 | assert(json_is_object((jb = json_array_get(ja, 1)))); 693 | assert(!json_object_get(jb, "workid")); 694 | } 695 | json_decref(j); 696 | 697 | assert((j = blkmk_submit_jansson(tmpl, data, 0, 0x12345678))); 698 | assert(json_object_get(j, "id")); 699 | assert((ja = json_object_get(j, "method"))); 700 | assert((sa = json_string_value(ja))); 701 | assert(!strcmp(sa, "submitblock")); 702 | assert((ja = json_object_get(j, "params"))); 703 | assert(json_is_array(ja)); 704 | assert(json_array_size(ja) >= 2); 705 | assert((sa = json_string_value(json_array_get(ja, 0)))); 706 | blktmpl_jansson_submit_data_check(sa, 0); 707 | assert(!memcmp(&sa[72], "512a63f45f96f0269a2d23ccd96bcf0322ee4f60254748e30b89e2b59431aba16d030000ff7f001d12345678", 64)); // merkle root 708 | assert(!memcmp(&sa[152], "12345678", 8)); // nonce 709 | assert(json_is_object((jb = json_array_get(ja, 1)))); 710 | assert((jc = json_object_get(jb, "workid"))); 711 | assert((sa = json_string_value(jc))); 712 | assert(!strcmp(sa, "mywork")); 713 | json_decref(j); 714 | 715 | assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &dataid)); 716 | 717 | assert((j = blkmk_submit_jansson(tmpl, data, dataid, 0x12345678))); 718 | assert((ja = json_object_get(j, "params"))); 719 | assert(json_is_array(ja)); 720 | assert(json_array_size(ja) >= 2); 721 | assert((sa = json_string_value(json_array_get(ja, 0)))); 722 | blktmpl_jansson_submit_data_check(sa, -1); 723 | // TODO: Check inserted dataid 724 | assert(json_is_object((jb = json_array_get(ja, 1)))); 725 | assert((jc = json_object_get(jb, "workid"))); 726 | assert((sa = json_string_value(jc))); 727 | assert(!strcmp(sa, "mywork")); 728 | json_decref(j); 729 | 730 | blktmpl_free(tmpl); 731 | } 732 | 733 | static void blktmpl_jansson_submitm() { 734 | blktemplate_t * const tmpl = blktmpl_create(); 735 | const char *sa; 736 | uint8_t data[76], *cbtxn, *branches, extranonce[10]; 737 | size_t cbextranonceoffset, cbtxnsize; 738 | int branchcount; 739 | int16_t i16; 740 | json_t *j, *ja, *jb, *jc; 741 | 742 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"sigoplimit\":100,\"sizelimit\":1000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\",\"required\":true},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1],\"fee\":12,\"required\":false,\"sigops\":4},{\"data\":\"01000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000\"}],\"coinbaseaux\":{\"dummy\":\"deadbeef\"},\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"workid\":\"mywork\",\"mutable\":[\"submit/coinbase\",\"submit/truncate\",\"coinbase/append\"]}", simple_time_rcvd)); 743 | 744 | assert(blkmk_get_mdata(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, 1, false)); 745 | free(cbtxn); 746 | free(branches); 747 | memset(&data[36], '\xee', 32); // merkle root, must be provided by caller 748 | 749 | extranonce[0] = 11; 750 | assert((j = blkmk_submitm_jansson(tmpl, data, extranonce, 1, 0x12345678, false))); 751 | assert(json_object_get(j, "id")); 752 | assert((ja = json_object_get(j, "method"))); 753 | assert((sa = json_string_value(ja))); 754 | assert(!strcmp(sa, "submitblock")); 755 | assert((ja = json_object_get(j, "params"))); 756 | assert(json_is_array(ja)); 757 | assert(json_array_size(ja) >= 2); 758 | assert((sa = json_string_value(json_array_get(ja, 0)))); 759 | blktmpl_jansson_submit_data_check(sa, -1); 760 | assert(!strcmp(&sa[160], "0401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08010404deadbeef0b333333330100100000015100000000")); 761 | assert(json_is_object((jb = json_array_get(ja, 1)))); 762 | assert((jc = json_object_get(jb, "workid"))); 763 | assert((sa = json_string_value(jc))); 764 | assert(!strcmp(sa, "mywork")); 765 | json_decref(j); 766 | 767 | extranonce[0] = 22; 768 | assert((j = blkmk_submitm_jansson(tmpl, data, extranonce, 1, 0x12345678, true))); 769 | assert((ja = json_object_get(j, "params"))); 770 | assert(json_is_array(ja)); 771 | assert(json_array_size(ja) >= 2); 772 | assert((sa = json_string_value(json_array_get(ja, 0)))); 773 | blktmpl_jansson_submit_data_check(sa, -1); 774 | assert(!strcmp(&sa[160], "0401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08010404deadbeef1633333333010010000001510000000001000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa0022222222010010000001510000000001000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f000000000044444444010010000001510000000001000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000")); 775 | json_decref(j); 776 | 777 | assert(blkmk_get_mdata(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, 3, false)); 778 | free(cbtxn); 779 | free(branches); 780 | 781 | extranonce[0] = 0x11; 782 | extranonce[1] = 0x22; 783 | extranonce[2] = 0x33; 784 | assert((j = blkmk_submitm_jansson(tmpl, data, extranonce, 3, 0x12345678, false))); 785 | assert((ja = json_object_get(j, "params"))); 786 | assert(json_is_array(ja)); 787 | assert(json_array_size(ja) >= 2); 788 | assert((sa = json_string_value(json_array_get(ja, 0)))); 789 | blktmpl_jansson_submit_data_check(sa, -1); 790 | assert(!strcmp(&sa[160], "0401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0a010404deadbeef112233333333330100100000015100000000")); 791 | json_decref(j); 792 | 793 | extranonce[2] = 0xed; 794 | assert((j = blkmk_submitm_jansson(tmpl, data, extranonce, 3, 0x12345678, true))); 795 | assert((ja = json_object_get(j, "params"))); 796 | assert(json_is_array(ja)); 797 | assert(json_array_size(ja) >= 2); 798 | assert((sa = json_string_value(json_array_get(ja, 0)))); 799 | blktmpl_jansson_submit_data_check(sa, -1); 800 | assert(!strcmp(&sa[160], "0401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0a010404deadbeef1122ed33333333010010000001510000000001000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa0022222222010010000001510000000001000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f000000000044444444010010000001510000000001000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000")); 801 | json_decref(j); 802 | 803 | blktmpl_free(tmpl); 804 | } 805 | 806 | static void test_blkmk_varint_encode_internal(const unsigned long txncount, const char * const expected, const size_t expectedsz) { 807 | blktemplate_t * const tmpl = blktmpl_create(); 808 | const char *sa; 809 | uint8_t data[76]; 810 | int16_t i16; 811 | unsigned int dataid; 812 | json_t *j, *ja, *jb; 813 | 814 | j = json_loads("{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"transactions\":[{\"data\":\"01\"}],\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"mutable\":[\"submit/coinbase\"]}", 0, NULL); 815 | assert(j); 816 | assert((ja = json_object_get(j, "transactions"))); 817 | assert((jb = json_array_get(ja, 0))); 818 | for (unsigned int i = 2; i < txncount; ++i) { 819 | assert(!json_array_append(ja, jb)); 820 | } 821 | assert(json_array_size(ja) == txncount - 1); 822 | assert(!blktmpl_add_jansson(tmpl, j, simple_time_rcvd)); 823 | json_decref(j); 824 | 825 | assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &dataid)); 826 | 827 | assert((j = blkmk_submit_jansson(tmpl, data, 0, 0x12345678))); 828 | assert((ja = json_object_get(j, "params"))); 829 | assert(json_is_array(ja)); 830 | assert(json_array_size(ja) >= 1); 831 | assert((sa = json_string_value(json_array_get(ja, 0)))); 832 | blktmpl_jansson_submit_data_check(sa, -1); 833 | assert(!memcmp(&sa[160], expected, expectedsz)); // tx count + gentx version 834 | json_decref(j); 835 | 836 | blktmpl_free(tmpl); 837 | } 838 | 839 | static void test_blkmk_varint_encode() { 840 | test_blkmk_varint_encode_internal(4, "0401000000", 10); 841 | test_blkmk_varint_encode_internal(0xfc, "fc01000000", 10); 842 | test_blkmk_varint_encode_internal(0xfd, "fdfd0001000000", 14); 843 | test_blkmk_varint_encode_internal(0xffff, "fdffff01000000", 14); 844 | test_blkmk_varint_encode_internal(0x10000, "fe0000010001000000", 18); 845 | // TODO: Find a way to test 64-bit and upper 32-bit 846 | } 847 | 848 | static void test_blkmk_supports_rule() { 849 | for (const char **rule = blkmk_supported_rules; *rule; ++rule) { 850 | assert(blkmk_supports_rule(*rule)); 851 | char important_rule[strlen(*rule) + 2]; 852 | important_rule[0] = '!'; 853 | strcpy(&important_rule[1], *rule); 854 | assert(!blkmk_supports_rule(important_rule)); 855 | } 856 | assert(!blkmk_supports_rule("foo")); 857 | assert(!blkmk_supports_rule("")); 858 | } 859 | 860 | static void test_blkmk_address_to_script() { 861 | uint8_t script[0x100]; 862 | 863 | assert(blkmk_address_to_script(script, sizeof(script), "1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh") == 25); 864 | assert(!memcmp(script, "\x76\xa9\x14\xfe\x14\xc4\xc6\x8d\x83\xda\x61\xfc\x57\x7b\x04\xcb\x6e\xcb\x6d\x31\xba\x1d\x52\x88\xac", 25)); 865 | 866 | assert(blkmk_address_to_script(script, sizeof(script), "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy") == 23); 867 | assert(!memcmp(script, "\xa9\x14\xb4\x72\xa2\x66\xd0\xbd\x89\xc1\x37\x06\xa4\x13\x2c\xcf\xb1\x6f\x7c\x3b\x9f\xcb\x87", 23)); 868 | 869 | assert(blkmk_address_to_script(script, sizeof(script), "1BitcoinEaterAddressDontSendf59kuE") == 25); 870 | assert(!memcmp(script, "\x76\xa9\x14\x75\x9d\x66\x77\x09\x1e\x97\x3b\x9e\x9d\x99\xf1\x9c\x68\xfb\xf4\x3e\x3f\x05\xf9\x88\xac", 25)); 871 | 872 | assert(blkmk_address_to_script(script, 25, "1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh") == 25); 873 | assert(!memcmp(script, "\x76\xa9\x14\xfe\x14\xc4\xc6\x8d\x83\xda\x61\xfc\x57\x7b\x04\xcb\x6e\xcb\x6d\x31\xba\x1d\x52\x88\xac", 25)); 874 | 875 | assert(blkmk_address_to_script(script, 23, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy") == 23); 876 | assert(!memcmp(script, "\xa9\x14\xb4\x72\xa2\x66\xd0\xbd\x89\xc1\x37\x06\xa4\x13\x2c\xcf\xb1\x6f\x7c\x3b\x9f\xcb\x87", 23)); 877 | 878 | assert(blkmk_address_to_script(script, 25, "1BitcoinEaterAddressDontSendf59kuE") == 25); 879 | assert(!memcmp(script, "\x76\xa9\x14\x75\x9d\x66\x77\x09\x1e\x97\x3b\x9e\x9d\x99\xf1\x9c\x68\xfb\xf4\x3e\x3f\x05\xf9\x88\xac", 25)); 880 | 881 | // Missing last letter 882 | assert(!blkmk_address_to_script(script, sizeof(script), "1QATWksNFGeUJCWBrN4g6hGM178Lovm7W")); 883 | // Extra letters/symbols 884 | assert(!blkmk_address_to_script(script, sizeof(script), "1QATWksNFGeUJCWBrN4g6hGM178Lovm7Whz")); 885 | assert(!blkmk_address_to_script(script, sizeof(script), "1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh\xff")); 886 | assert(!blkmk_address_to_script(script, sizeof(script), "1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh\x01")); 887 | assert(!blkmk_address_to_script(script, sizeof(script), "1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh/")); 888 | // Missing last byte (decoded) 889 | assert(!blkmk_address_to_script(script, sizeof(script), "16FNsF1zNp3bjQuNwgfSdBUwq4CdfGoh")); 890 | // Extra byte (decoded) 891 | assert(!blkmk_address_to_script(script, sizeof(script), "12mEk2LdJmz4PUumptsyDa8ijHU3QS8Hhh1")); 892 | assert(!blkmk_address_to_script(script, sizeof(script), "")); 893 | assert(!blkmk_address_to_script(script, sizeof(script), "\x01")); 894 | assert(!blkmk_address_to_script(script, sizeof(script), "\xff")); 895 | 896 | // Too little buffer space 897 | assert(blkmk_address_to_script(script, 20, "1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh") == 25); 898 | assert(blkmk_address_to_script(script, 0, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy") == 23); 899 | assert(blkmk_address_to_script(script, 24, "1BitcoinEaterAddressDontSendf59kuE") == 25); 900 | } 901 | 902 | static void test_blkmk_x_left() { 903 | blktemplate_t *tmpl = blktmpl_create(); 904 | uint8_t data[76]; 905 | int16_t i16; 906 | unsigned int dataid, orig_work_left; 907 | 908 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"transactions\":[],\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"expires\":44}", simple_time_rcvd)); 909 | 910 | assert(blkmk_work_left(tmpl) == 1); 911 | assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &dataid)); 912 | assert(blkmk_work_left(tmpl) == 0); 913 | 914 | assert(blkmk_time_left(tmpl, simple_time_rcvd) == 44); 915 | assert(blkmk_time_left(tmpl, simple_time_rcvd + 1) == 43); 916 | assert(blkmk_time_left(tmpl, simple_time_rcvd + 43) == 1); 917 | assert(blkmk_time_left(tmpl, simple_time_rcvd + 50) == 0); 918 | 919 | blktmpl_free(tmpl); 920 | tmpl = blktmpl_create(); 921 | 922 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"transactions\":[],\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"mutable\":[\"coinbase/append\"]}", simple_time_rcvd)); 923 | 924 | orig_work_left = blkmk_work_left(tmpl); 925 | assert(orig_work_left > 0xf0); 926 | assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &dataid)); 927 | assert(blkmk_work_left(tmpl) == orig_work_left - 1); 928 | assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &dataid)); 929 | assert(blkmk_work_left(tmpl) == orig_work_left - 2); 930 | 931 | blktmpl_free(tmpl); 932 | } 933 | 934 | static void test_blkmk_get_data() { 935 | blktemplate_t *tmpl = blktmpl_create(); 936 | uint8_t data[76]; 937 | int16_t i16; 938 | unsigned int dataid, first_dataid; 939 | 940 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"sigoplimit\":100,\"sizelimit\":1000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\",\"required\":true},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1],\"fee\":12,\"required\":false,\"sigops\":4},{\"data\":\"01000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000\"}],\"coinbaseaux\":{\"dummy\":\"deadbeef\"},\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"workid\":\"mywork\",\"mutable\":[\"submit/coinbase\",\"submit/truncate\",\"coinbase/append\"],\"expires\":32}", simple_time_rcvd)); 941 | 942 | assert(blkmk_work_left(tmpl) > 0xf0); 943 | assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &first_dataid)); 944 | assert(first_dataid == 0); 945 | assert(i16 == 31 || i16 == 32); 946 | assert(!memcmp(data, "\x03\0\0\0\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\0\0\0\0\x51\x2a\x63\xf4\x5f\x96\xf0\x26\x9a\x2d\x23\xcc\xd9\x6b\xcf\x03\x22\xee\x4f\x60\x25\x47\x48\xe3\x0b\x89\xe2\xb5\x94\x31\xab\xa1\x6d\x03\0\0\xff\x7f\0\x1d", 76)); 947 | 948 | assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd + 4, &i16, &dataid)); 949 | assert(dataid == first_dataid + 1); 950 | assert(i16 == 27 || i16 == 28); 951 | assert(!memcmp(data, "\x03\0\0\0\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\0\0\0\0\x2a\x73\x99\xbc\x0a\x19\xa1\x11\x03\xfc\x3b\x8f\x4b\xe4\0\x68\x18\xea\x3f\x2a\0\xcf\x42\x8b\xd7\x09\x1c\x8d\xe2\xea\xe7\x38\x71\x03\0\0\xff\x7f\0\x1d", 76)); 952 | 953 | assert(76 == blkmk_get_data(tmpl, data, sizeof(data) + 1, simple_time_rcvd + 8, &i16, &dataid)); 954 | assert(dataid == first_dataid + 2); 955 | assert(i16 == 23 || i16 == 24); 956 | assert(!memcmp(data, "\x03\0\0\0\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\0\0\0\0\xe2\xe4\xbc\x8e\x65\x8b\x52\x2e\xe5\xeb\x69\xd5\xe5\xd4\xa6\x25\xfd\x8f\x32\x2d\x71\x0f\xc0\xb2\x38\xe1\x71\x01\x61\x56\x2c\x2e\x75\x03\0\0\xff\x7f\0\x1d", 76)); 957 | 958 | // Too-small buffer fails with desired buffer size 959 | assert(76 == blkmk_get_data(tmpl, data, sizeof(data) - 1, simple_time_rcvd + 8, &i16, &dataid)); 960 | // Make sure dataid wasn't incremented for the failure 961 | assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd + 8, &i16, &dataid)); 962 | assert(dataid == first_dataid + 3); 963 | 964 | // Bad hash function should fail 965 | blkmk_sha256_impl = bad_sha256; 966 | assert(0 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd + 8, &i16, &dataid)); 967 | blkmk_sha256_impl = my_sha256; 968 | 969 | // No more time, fail 970 | assert(0 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd + 35, &i16, &dataid)); 971 | 972 | blktmpl_free(tmpl); 973 | tmpl = blktmpl_create(); 974 | 975 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"sigoplimit\":100,\"sizelimit\":1000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\",\"required\":true},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1],\"fee\":12,\"required\":false,\"sigops\":4},{\"data\":\"01000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000\"}],\"coinbaseaux\":{\"dummy\":\"deadbeef\"},\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"workid\":\"mywork\",\"expires\":32}", simple_time_rcvd)); 976 | // Make sure a non-appendable fails the second get_data 977 | assert(76 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &first_dataid)); 978 | assert(first_dataid == 0); 979 | assert(0 == blkmk_get_data(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &first_dataid)); 980 | 981 | // TODO: ensure a scriptsig with <4 bytes cannot be produced through to get_data; but this requires a platform where sizeof(unsigned int) < 4 and no height-in-coinbase... 982 | 983 | blktmpl_free(tmpl); 984 | } 985 | 986 | static void test_blkmk_get_mdata() { 987 | blktemplate_t *tmpl = blktmpl_create(); 988 | uint8_t data[76], *cbtxn, *branches; 989 | size_t cbextranonceoffset, cbtxnsize; 990 | int branchcount; 991 | int16_t i16; 992 | 993 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"sigoplimit\":100,\"sizelimit\":1000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\",\"required\":true},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1],\"fee\":12,\"required\":false,\"sigops\":4},{\"data\":\"01000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000\"}],\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000\"},\"workid\":\"mywork\",\"mutable\":[\"submit/coinbase\",\"submit/truncate\",\"coinbase/append\"],\"expires\":99}", simple_time_rcvd)); 994 | 995 | assert(blkmk_get_mdata(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, 1, false)); 996 | assert(!memcmp(data, "\x03\0\0\0\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\0\0\0\0", 36)); 997 | // Skip merkle root 998 | assert(!memcmp(&data[68], "\x6d\x03\0\0\xff\x7f\0\x1d", 8)); 999 | assert(i16 == 98 || i16 == 99); 1000 | assert(cbtxnsize == 65); 1001 | assert(cbextranonceoffset == 49); 1002 | assert(!memcmp(cbtxn, "\x01\0\0\0\x01\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\xff\xff\xff\xff\x08\x01\x04\x04\xde\xad\xbe\xef", 49)); 1003 | assert(!memcmp(&cbtxn[50], "\x33\x33\x33\x33\x01\0\x10\0\0\x01\x51\0\0\0\0", 65-50)); 1004 | assert(branchcount == 2); 1005 | assert(!memcmp(branches, "\x0f\xd2\x7c\x1c\x2c\x93\x7c\0\x21\x2d\x90\x3b\x1d\xb1\x05\xc0\xde\xce\x57\x08\x9c\x7c\x93\x80\xdd\x2c\x2f\xe6\x12\xf2\x69\x1c\x2b\x07\x3c\xb8\x85\xbf\x62\x3b\x1c\xd5\xac\xda\x81\xce\xe8\x9f\xe9\x19\x0e\x10\x85\xff\x54\x98\xc3\x33\x4c\x2c\x63\xf8\xdd\x4d", 64)); 1006 | free(cbtxn); 1007 | free(branches); 1008 | 1009 | assert(blkmk_get_mdata(tmpl, data, sizeof(data), simple_time_rcvd + 4, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, 3, false)); 1010 | assert(!memcmp(data, "\x03\0\0\0\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\0\0\0\0", 36)); 1011 | // Skip merkle root 1012 | assert(!memcmp(&data[68], "\x71\x03\0\0\xff\x7f\0\x1d", 8)); 1013 | assert(i16 == 94 || i16 == 95); 1014 | assert(cbtxnsize == 67); 1015 | assert(cbextranonceoffset == 49); 1016 | assert(!memcmp(cbtxn, "\x01\0\0\0\x01\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\xff\xff\xff\xff\x0a\x01\x04\x04\xde\xad\xbe\xef", 49)); 1017 | assert(!memcmp(&cbtxn[52], "\x33\x33\x33\x33\x01\0\x10\0\0\x01\x51\0\0\0\0", 67-52)); 1018 | assert(branchcount == 2); 1019 | assert(!memcmp(branches, "\x0f\xd2\x7c\x1c\x2c\x93\x7c\0\x21\x2d\x90\x3b\x1d\xb1\x05\xc0\xde\xce\x57\x08\x9c\x7c\x93\x80\xdd\x2c\x2f\xe6\x12\xf2\x69\x1c\x2b\x07\x3c\xb8\x85\xbf\x62\x3b\x1c\xd5\xac\xda\x81\xce\xe8\x9f\xe9\x19\x0e\x10\x85\xff\x54\x98\xc3\x33\x4c\x2c\x63\xf8\xdd\x4d", 64)); 1020 | free(cbtxn); 1021 | free(branches); 1022 | 1023 | size_t sizeof_dataid = sizeof(unsigned int); 1024 | size_t expected_space = sizeof_dataid + 1; 1025 | assert(blkmk_get_mdata(tmpl, data, sizeof(data), simple_time_rcvd + 8, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, sizeof_dataid, false)); 1026 | assert(!memcmp(data, "\x03\0\0\0\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\x77\x77\x77\xa7\0\0\0\0", 36)); 1027 | // Skip merkle root 1028 | assert(!memcmp(&data[68], "\x75\x03\0\0\xff\x7f\0\x1d", 8)); 1029 | assert(i16 == 90 || i16 == 91); 1030 | assert(cbtxnsize == 64 + expected_space); 1031 | assert(cbextranonceoffset == 49); 1032 | assert(!memcmp(cbtxn, "\x01\0\0\0\x01\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\xff\xff\xff\xff", 41)); 1033 | assert(cbtxn[41] == 7 + expected_space); 1034 | assert(!memcmp(&cbtxn[42], "\x01\x04\x04\xde\xad\xbe\xef", 7)); 1035 | assert(!memcmp(&cbtxn[49 + expected_space], "\x33\x33\x33\x33\x01\0\x10\0\0\x01\x51\0\0\0\0", 15)); 1036 | assert(branchcount == 2); 1037 | assert(!memcmp(branches, "\x0f\xd2\x7c\x1c\x2c\x93\x7c\0\x21\x2d\x90\x3b\x1d\xb1\x05\xc0\xde\xce\x57\x08\x9c\x7c\x93\x80\xdd\x2c\x2f\xe6\x12\xf2\x69\x1c\x2b\x07\x3c\xb8\x85\xbf\x62\x3b\x1c\xd5\xac\xda\x81\xce\xe8\x9f\xe9\x19\x0e\x10\x85\xff\x54\x98\xc3\x33\x4c\x2c\x63\xf8\xdd\x4d", 64)); 1038 | free(cbtxn); 1039 | free(branches); 1040 | 1041 | // If hashing fails, so must get_mdata 1042 | blkmk_sha256_impl = bad_sha256; 1043 | assert(!blkmk_get_mdata(tmpl, data, sizeof(data) - 1, simple_time_rcvd + 8, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, sizeof_dataid, false)); 1044 | blkmk_sha256_impl = my_sha256; 1045 | 1046 | // Buffer too small must fail 1047 | assert(!blkmk_get_mdata(tmpl, data, sizeof(data) - 1, simple_time_rcvd + 8, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, sizeof_dataid, false)); 1048 | 1049 | // Without cb append/set mutations, we must fail too 1050 | tmpl->mutations &= ~(BMM_CBAPPEND | BMM_CBSET); 1051 | assert(!blkmk_get_mdata(tmpl, data, sizeof(data), simple_time_rcvd + 8, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, sizeof_dataid, false)); 1052 | // ... but only one or the other should be sufficient 1053 | tmpl->mutations |= BMM_CBAPPEND; 1054 | assert(blkmk_get_mdata(tmpl, data, sizeof(data), simple_time_rcvd + 8, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, sizeof_dataid, false)); 1055 | free(cbtxn); 1056 | free(branches); 1057 | tmpl->mutations = (tmpl->mutations & ~BMM_CBAPPEND) | BMM_CBSET; 1058 | assert(blkmk_get_mdata(tmpl, data, sizeof(data), simple_time_rcvd + 8, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, sizeof_dataid, false)); 1059 | free(cbtxn); 1060 | free(branches); 1061 | 1062 | blktmpl_free(tmpl); 1063 | tmpl = blktmpl_create(); 1064 | 1065 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"sigoplimit\":100,\"sizelimit\":1000,\"transactions\":[{\"data\":\"01000000019999999999999999999999999999999999999999999999999999999999999999aaaaaaaa00222222220100100000015100000000\",\"required\":true},{\"hash\":\"8eda1a8b67996401a89af8de4edd6715c23a7fb213f9866e18ab9d4367017e8d\",\"data\":\"01000000011c69f212e62f2cdd80937c9c0857cedec005b11d3b902d21007c932c1c7cd20f0000000000444444440100100000015100000000\",\"depends\":[1],\"fee\":12,\"required\":false,\"sigops\":4},{\"data\":\"01000000010099999999999999999999999999999999999999999999999999999999999999aaaaaaaa00555555550100100000015100000000\"}],\"mutable\":[\"coinbase/append\"]}", simple_time_rcvd)); 1066 | 1067 | // No generation transaction, fail 1068 | assert(!blkmk_get_mdata(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, 1, false)); 1069 | 1070 | // Initialising it should make us work though 1071 | assert(blkmk_init_generation(tmpl, NULL, 0) == 640); 1072 | assert(blkmk_get_mdata(tmpl, data, sizeof(data), simple_time_rcvd, &i16, &cbtxn, &cbtxnsize, &cbextranonceoffset, &branchcount, &branches, 1, false)); 1073 | assert(cbtxn[41] >= 4 /* libblkmaker_coinbase_size_minimum */); 1074 | free(cbtxn); 1075 | free(branches); 1076 | 1077 | blktmpl_free(tmpl); 1078 | } 1079 | 1080 | static const void *my_memmemr(const void * const haystack_p, const size_t haystacklen, const void * const needle, const size_t needlelen) { 1081 | if (needlelen > haystacklen) 1082 | return NULL; 1083 | const uint8_t * const haystack = haystack_p, *p; 1084 | for (ssize_t i = haystacklen - needlelen; i >= 0; --i) { 1085 | p = &haystack[i]; 1086 | if (!memcmp(p, needle, needlelen)) { 1087 | return p; 1088 | } 1089 | } 1090 | return NULL; 1091 | } 1092 | 1093 | static void test_blkmk_init_generation() { 1094 | blktemplate_t *tmpl; 1095 | bool newcb; 1096 | 1097 | tmpl = blktmpl_create(); 1098 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640}", simple_time_rcvd)); 1099 | assert(!tmpl->cbtxn); 1100 | assert(blkmk_init_generation(tmpl, NULL, 0) == 640); 1101 | assert(tmpl->cbtxn); 1102 | assert(tmpl->cbtxn->datasz == 62); 1103 | assert(!memcmp(tmpl->cbtxn->data, "\x01\0\0\0\x01\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\xff\xff\xff\xff\x02\x01\x04\xff\xff\xff\xff\x01\x80\x02\0\0\0\0\0\0\0\0\0\0\0", tmpl->cbtxn->datasz)); 1104 | 1105 | newcb = false; 1106 | assert(!blkmk_init_generation3(tmpl, "\0", 1, &newcb)); 1107 | 1108 | newcb = true; 1109 | assert(blkmk_init_generation3(tmpl, "\x04" "test", 5, &newcb)); 1110 | assert(newcb); 1111 | assert(tmpl->cbtxn); 1112 | assert(tmpl->cbtxn->datasz == 67); 1113 | assert(!memcmp(tmpl->cbtxn->data, "\x01\0\0\0\x01\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\xff\xff\xff\xff\x02\x01\x04\xff\xff\xff\xff\x01\x80\x02\0\0\0\0\0\0\x05\x04" "test\0\0\0\0", tmpl->cbtxn->datasz)); 1114 | 1115 | assert(!blkmk_init_generation2(tmpl, "\0", 1, &newcb)); 1116 | assert(!newcb); 1117 | 1118 | tmpl->mutations &= ~BMM_GENERATE; 1119 | newcb = true; 1120 | assert(!blkmk_init_generation3(tmpl, "\0", 1, &newcb)); 1121 | 1122 | blktmpl_free(tmpl); 1123 | tmpl = blktmpl_create(); 1124 | 1125 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":40000000,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"coinbaseaux\":{\"dummy\":\"aabbccddeeff0011\"}}", simple_time_rcvd)); 1126 | assert(blkmk_init_generation(tmpl, NULL, 0) == 640); 1127 | assert(my_memmemr(&tmpl->cbtxn->data[42], tmpl->cbtxn->data[41], "\xaa\xbb\xcc\xdd\xee\xff\0\x11", 8)); 1128 | 1129 | blktmpl_free(tmpl); 1130 | tmpl = blktmpl_create(); 1131 | 1132 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":128,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"coinbaseaux\":{\"dummy\":\"aabbccddeeff0011aabbccddeeff0011aabbccddeeff0011aabbccddeeff0011aabbccddeeff0011aabbccddeeff0011aabbccddeeff0011aabbccddeeff0011aabbccddeeff0011aabbccddeeff0011aabbccddeeff0011aabbccddeeff001199\"}}", simple_time_rcvd)); 1133 | assert(!blkmk_init_generation(tmpl, NULL, 0)); 1134 | tmpl->height = 4; 1135 | assert(blkmk_init_generation(tmpl, NULL, 0) == 640); 1136 | tmpl->has_cbvalue = false; 1137 | tmpl->cbvalue = 0; 1138 | newcb = true; 1139 | // Unknown cbvalue needs to either fail, or figure it out from an existing cbtxn (which we don't support yet) 1140 | assert(!blkmk_init_generation3(tmpl, NULL, 0, &newcb)); 1141 | 1142 | blktmpl_free(tmpl); 1143 | tmpl = blktmpl_create(); 1144 | 1145 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":40000000,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":10000000000}", simple_time_rcvd)); 1146 | newcb = false; 1147 | assert(blkmk_init_generation3(tmpl, "\x04" "test", 5, &newcb)); 1148 | assert(newcb); 1149 | assert(tmpl->cbtxn); 1150 | assert(tmpl->cbtxn->datasz == 70); 1151 | assert(!memcmp(tmpl->cbtxn->data, "\x01\0\0\0\x01\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\xff\xff\xff\xff\x05\x04\0\x5a\x62\x02\xff\xff\xff\xff\x01\0\xe4\x0b\x54\x02\0\0\0\x05\x04" "test\0\0\0\0", tmpl->cbtxn->datasz)); 1152 | 1153 | blktmpl_free(tmpl); 1154 | tmpl = blktmpl_create(); 1155 | 1156 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":40000000,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000000000\"},\"mutable\":[\"generation\"],\"coinbasevalue\":89064736821248}", simple_time_rcvd)); 1157 | newcb = false; 1158 | assert(!blkmk_init_generation3(tmpl, "\x04" "test", 5, &newcb)); 1159 | assert(!newcb); 1160 | newcb = true; 1161 | assert(blkmk_init_generation3(tmpl, "\x04" "test", 5, &newcb)); 1162 | assert(newcb); 1163 | assert(tmpl->cbtxn); 1164 | assert(tmpl->cbtxn->datasz == 70); 1165 | assert(!memcmp(tmpl->cbtxn->data, "\x01\0\0\0\x01\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\xff\xff\xff\xff\x05\x04\0\x5a\x62\x02\xff\xff\xff\xff\x01\0\x10\0\0\x01\x51\0\0\x05\x04" "test\0\0\0\0", tmpl->cbtxn->datasz)); 1166 | 1167 | tmpl->sizelimit = 151; 1168 | assert(blkmk_init_generation3(tmpl, "\x04" "test", 5, &newcb)); 1169 | assert(!blkmk_init_generation3(tmpl, "\x05" "testx", 6, &newcb)); 1170 | tmpl->sizelimit = 10000; 1171 | tmpl->sigoplimit = 1; 1172 | assert(blkmk_init_generation3(tmpl, "\x05" "testx", 6, &newcb)); 1173 | assert(blkmk_init_generation3(tmpl, "\x05" "testx\xac", 7, &newcb)); 1174 | assert(!blkmk_init_generation3(tmpl, "\x05" "testx\xac\xac", 8, &newcb)); 1175 | assert(blkmk_init_generation3(tmpl, "\x05" "testx\xac\x4c\0", 9, &newcb)); 1176 | assert(blkmk_init_generation3(tmpl, "\x05" "testx\xac\x4c", 8, &newcb)); 1177 | assert(blkmk_init_generation3(tmpl, "\x05" "testx\xac\x4d\x01", 9, &newcb)); 1178 | assert(blkmk_init_generation3(tmpl, "\x05" "testx\xac\x4e\x01", 9, &newcb)); 1179 | assert(blkmk_init_generation3(tmpl, "\x05" "testx\xac\x4e\0\0\0\0", 12, &newcb)); 1180 | assert(blkmk_init_generation3(tmpl, "\x4c\x04" "estx\xad", 7, &newcb)); 1181 | assert(!blkmk_init_generation3(tmpl, "\x4c\x04" "estx\xad\xad", 8, &newcb)); 1182 | assert(!blkmk_init_generation3(tmpl, "\x4c\x04" "estx\xac\xad", 8, &newcb)); 1183 | tmpl->sigoplimit = 21; 1184 | assert(blkmk_init_generation3(tmpl, "\x05" "testx\xac\xac", 8, &newcb)); 1185 | assert(blkmk_init_generation3(tmpl, "\x05" "testx\xac\xae", 8, &newcb)); 1186 | assert(!blkmk_init_generation3(tmpl, "\x05" "testx\xac\xae\xac", 9, &newcb)); 1187 | assert(blkmk_init_generation3(tmpl, "\x4d\x03\0" "stx\xac\xaf", 8, &newcb)); 1188 | assert(!blkmk_init_generation3(tmpl, "\x4d\x03\0" "stx\xac\xaf\xac", 9, &newcb)); 1189 | 1190 | blktmpl_free(tmpl); 1191 | } 1192 | 1193 | static void test_blkmk_append_coinbase_safe() { 1194 | blktemplate_t *tmpl; 1195 | bool newcb; 1196 | static const uint8_t lots_of_zero[100] = {0}; 1197 | 1198 | tmpl = blktmpl_create(); 1199 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000000000\"}}", simple_time_rcvd)); 1200 | // Should fail because we lack coinbase/append mutability 1201 | assert(blkmk_append_coinbase_safe(tmpl, "", 1) <= 0); 1202 | 1203 | blktmpl_free(tmpl); 1204 | tmpl = blktmpl_create(); 1205 | 1206 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef333333330100100000015100000000000000\"},\"mutable\":[\"coinbase/append\"]}", simple_time_rcvd)); 1207 | assert(blkmk_append_coinbase_safe(tmpl, "", 1) >= 1); 1208 | assert(tmpl->cbtxn); 1209 | assert(tmpl->cbtxn->datasz == 68); 1210 | assert(!memcmp(tmpl->cbtxn->data, "\x01\0\0\0\x01\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\xff\xff\xff\xff\x08\x01\x04\x04\xde\xad\xbe\xef\0\x33\x33\x33\x33\x01\0\x10\0\0\x01\x51\0\0\0\0\0\0\0", tmpl->cbtxn->datasz)); 1211 | 1212 | blktmpl_free(tmpl); 1213 | tmpl = blktmpl_create(); 1214 | 1215 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasevalue\":640,\"sigoplimit\":21}", simple_time_rcvd)); 1216 | assert(blkmk_init_generation(tmpl, NULL, 0) == 640); 1217 | assert(blkmk_append_coinbase_safe(tmpl, "", 1) >= 1); 1218 | assert(tmpl->cbtxn); 1219 | assert(tmpl->cbtxn->datasz == 63); 1220 | assert(!memcmp(tmpl->cbtxn->data, "\x01\0\0\0\x01\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\xff\xff\xff\xff\x03\x01\x04\0\xff\xff\xff\xff\x01\x80\x02\0\0\0\0\0\0\0\0\0\0\0", tmpl->cbtxn->datasz)); 1221 | 1222 | // With 99-byte extranonce, we're already beyond the limit 1223 | assert(blkmk_append_coinbase_safe2(tmpl, "", 1, 99, true) <= 0); 1224 | // This should just barely break the limit 1225 | assert(blkmk_append_coinbase_safe2(tmpl, "", 1, 100 - tmpl->cbtxn->data[41], true) == 0); 1226 | // This should be okay 1227 | assert(blkmk_append_coinbase_safe2(tmpl, "", 1, 100 - tmpl->cbtxn->data[41] - 1, true) == 1); 1228 | // Up to 21 sigops is okay 1229 | assert(blkmk_append_coinbase_safe2(tmpl, "\xae", 1, 3, true) >= 1); 1230 | assert(blkmk_append_coinbase_safe2(tmpl, "\xac", 1, 3, true) >= 1); 1231 | // But 22 should hit the limit 1232 | assert(blkmk_append_coinbase_safe2(tmpl, "\xac", 1, 3, true) < 0); 1233 | // Non-sigop stuff is fine to continue 1234 | assert(blkmk_append_coinbase_safe2(tmpl, "", 1, 3, true) >= 1); 1235 | const uint8_t padsz = 100 - tmpl->cbtxn->data[41] - 3; 1236 | assert(blkmk_append_coinbase_safe2(tmpl, lots_of_zero, padsz, 3, true) == padsz); 1237 | // One too many 1238 | assert(blkmk_append_coinbase_safe2(tmpl, "", 1, 3, true) == 0); 1239 | // Becomes okay if we reduce extranonce size 1240 | assert(blkmk_append_coinbase_safe2(tmpl, "", 1, 2, true) == 1); 1241 | assert(blkmk_append_coinbase_safe2(tmpl, lots_of_zero, 2, 0, true) == 2); 1242 | // Totally full now 1243 | assert(blkmk_append_coinbase_safe2(tmpl, "", 1, 0, true) == 0); 1244 | 1245 | newcb = true; 1246 | assert(blkmk_init_generation3(tmpl, NULL, 0, &newcb)); 1247 | tmpl->sizelimit = tmpl->cbtxn->datasz + 81 + 5; 1248 | assert(blkmk_append_coinbase_safe2(tmpl, "\x04" "test", 5, 0, true) == 5); 1249 | assert(blkmk_init_generation3(tmpl, NULL, 0, &newcb)); 1250 | assert(blkmk_append_coinbase_safe2(tmpl, "\x05" "testx", 6, 0, true) == 5); 1251 | 1252 | blktmpl_free(tmpl); 1253 | tmpl = blktmpl_create(); 1254 | 1255 | // Gen tx is cut off immediately after the coinbase. 1256 | // We don't *really* care that this works since it's not Bitcoin, but we need to make sure it doesn't corrupt memory or crash 1257 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbeef\"},\"mutable\":[\"coinbase/append\"]}", simple_time_rcvd)); 1258 | assert(blkmk_append_coinbase_safe(tmpl, "\x58", 1) >= 1); 1259 | assert(tmpl->cbtxn); 1260 | assert(tmpl->cbtxn->datasz == 50); 1261 | assert(!memcmp(tmpl->cbtxn->data, "\x01\0\0\0\x01\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\xff\xff\xff\xff\x08\x01\x04\x04\xde\xad\xbe\xef\x58", tmpl->cbtxn->datasz)); 1262 | 1263 | blktmpl_free(tmpl); 1264 | tmpl = blktmpl_create(); 1265 | 1266 | // Gen tx is cut off INSIDE the coinbase. 1267 | // Again, we need to make sure it doesn't corrupt memory or crash 1268 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07010404deadbe\"},\"mutable\":[\"coinbase/append\"]}", simple_time_rcvd)); 1269 | assert(blkmk_append_coinbase_safe(tmpl, "\x58", 1) <= 0); 1270 | assert(tmpl->cbtxn); 1271 | assert(tmpl->cbtxn->datasz == 48); 1272 | assert(!memcmp(tmpl->cbtxn->data, "\x01\0\0\0\x01\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\xff\xff\xff\xff\x07\x01\x04\x04\xde\xad\xbe", tmpl->cbtxn->datasz)); 1273 | 1274 | blktmpl_free(tmpl); 1275 | tmpl = blktmpl_create(); 1276 | 1277 | // Gen tx is cut off BEFORE the coinbase 1278 | assert(!blktmpl_add_jansson_str(tmpl, "{\"version\":3,\"height\":4,\"bits\":\"1d007fff\",\"curtime\":877,\"previousblockhash\":\"00000000a7777777a7777777a7777777a7777777a7777777a7777777a7777777\",\"coinbasetxn\":{\"data\":\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff\"},\"mutable\":[\"coinbase/append\"]}", simple_time_rcvd)); 1279 | assert(blkmk_append_coinbase_safe(tmpl, "\x58", 1) <= 0); 1280 | assert(tmpl->cbtxn); 1281 | assert(tmpl->cbtxn->datasz == 41); 1282 | assert(!memcmp(tmpl->cbtxn->data, "\x01\0\0\0\x01\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\xff\xff\xff\xff", tmpl->cbtxn->datasz)); 1283 | 1284 | blktmpl_free(tmpl); 1285 | } 1286 | 1287 | int main() { 1288 | blkmk_sha256_impl = my_sha256; 1289 | 1290 | puts("capabilityname"); 1291 | capabilityname_test(); 1292 | 1293 | puts("blktxn"); 1294 | blktxn_test('\0'); 1295 | blktxn_test('\xa5'); 1296 | blktxn_test('\xff'); 1297 | 1298 | puts("blktmpl"); 1299 | blktmpl_test(); 1300 | 1301 | puts("blktmpl_request_jansson"); 1302 | blktmpl_request_jansson_test_old(); 1303 | blktmpl_request_jansson_test_custom_rulelist(); 1304 | blktmpl_request_jansson_test_custom_caps(); 1305 | blktmpl_request_jansson_test_longpoll(); 1306 | 1307 | puts("blktmpl_jansson"); 1308 | blktmpl_jansson_simple(); 1309 | blktmpl_jansson_bip22_required(); 1310 | blktmpl_jansson_bip22_longpoll(); 1311 | blktmpl_jansson_bip23_bpe(); 1312 | blktmpl_jansson_bip23_mutations(); 1313 | blktmpl_jansson_bip23_abbrev(); 1314 | blktmpl_jansson_bip9(); 1315 | test_blktmpl_jansson_floaty(); 1316 | blktmpl_jansson_propose(); 1317 | blktmpl_jansson_submit(); 1318 | blktmpl_jansson_submitm(); 1319 | 1320 | puts("blkmk_varint_encode"); 1321 | test_blkmk_varint_encode(); 1322 | 1323 | puts("blkmk_supports_rule"); 1324 | test_blkmk_supports_rule(); 1325 | 1326 | puts("blkmk_address_to_script"); 1327 | test_blkmk_address_to_script(); 1328 | 1329 | puts("blkmk_*_left"); 1330 | test_blkmk_x_left(); 1331 | 1332 | puts("blkmk_get_data"); 1333 | test_blkmk_get_data(); 1334 | 1335 | puts("blkmk_get_mdata"); 1336 | test_blkmk_get_mdata(); 1337 | 1338 | puts("blkmk_init_generation"); 1339 | test_blkmk_init_generation(); 1340 | 1341 | puts("blkmk_append_coinbase_safe"); 1342 | test_blkmk_append_coinbase_safe(); 1343 | } 1344 | --------------------------------------------------------------------------------