diff --git a/README.md b/README.md index 47b12ed0..682e27ac 100644 --- a/README.md +++ b/README.md @@ -142,11 +142,11 @@ Donations cpuminer-opt has no fees of any kind but donations are accepted. -BTC: 12tdvfF7KmAsihBXQXynT6E6th2c2pByTT -ETH: 0x72122edabcae9d3f57eab0729305a425f6fef6d0 -LTC: LdUwoHJnux9r9EKqFWNvAi45kQompHk6e8 -BCH: 1QKYkB6atn4P7RFozyziAXLEnurwnUM1cQ -BTG: GVUyECtRHeC5D58z9F3nGGfVQndwnsPnHQ + BTC: 12tdvfF7KmAsihBXQXynT6E6th2c2pByTT + ETH: 0x72122edabcae9d3f57eab0729305a425f6fef6d0 + LTC: LdUwoHJnux9r9EKqFWNvAi45kQompHk6e8 + BCH: 1QKYkB6atn4P7RFozyziAXLEnurwnUM1cQ + BTG: GVUyECtRHeC5D58z9F3nGGfVQndwnsPnHQ Happy mining! diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 906fcf9c..5ca1f7b2 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -90,7 +90,8 @@ Additional optional compile flags, add the following to CFLAGS to activate: SPH may give slightly better performance on algos that use sha256 when using openssl 1.0.1 or older. Openssl 1.0.2 adds AVX2 and 1.1 adds SHA and perform -better than SPH. +better than SPH. This option is ignored when 4-way is used, even for CPUs +with SHA. Start mining. @@ -159,6 +160,12 @@ Support for even older x86_64 without AES_NI or SSE2 is not availble. Change Log ---------- +v3.8.3.3 + +Integrated getblocktemplate with algo_gate. +Added support for hodl gbt (untested). +Reworked some recent quick fixes. + v3.8.3.2 Reverted gbt changes from v3.8.0 that broke getwork. diff --git a/algo-gate-api.c b/algo-gate-api.c index acfe3745..c4bbcec8 100644 --- a/algo-gate-api.c +++ b/algo-gate-api.c @@ -119,9 +119,11 @@ void init_algo_gate( algo_gate_t* gate ) gate->gen_merkle_root = (void*)&sha256d_gen_merkle_root; gate->stratum_gen_work = (void*)&std_stratum_gen_work; gate->build_stratum_request = (void*)&std_le_build_stratum_request; + gate->malloc_txs_request = (void*)&std_malloc_txs_request; gate->set_target = (void*)&std_set_target; gate->work_decode = (void*)&std_le_work_decode; gate->submit_getwork_result = (void*)&std_le_submit_getwork_result; + gate->build_block_header = (void*)&std_build_block_header; gate->build_extraheader = (void*)&std_build_extraheader; gate->set_work_data_endian = (void*)&do_nothing; gate->calc_network_diff = (void*)&std_calc_network_diff; diff --git a/algo-gate-api.h b/algo-gate-api.h index 65e32e9d..7a68466e 100644 --- a/algo-gate-api.h +++ b/algo-gate-api.h @@ -127,7 +127,10 @@ void ( *set_target) ( struct work*, double ); bool ( *submit_getwork_result ) ( CURL*, struct work* ); void ( *gen_merkle_root ) ( char*, struct stratum_ctx* ); void ( *build_extraheader ) ( struct work*, struct stratum_ctx* ); +void ( *build_block_header ) ( struct work*, uint32_t, uint32_t*, + uint32_t*, uint32_t, uint32_t ); void ( *build_stratum_request ) ( char*, struct work*, struct stratum_ctx* ); +char* ( *malloc_txs_request ) ( struct work* ); void ( *set_work_data_endian ) ( struct work* ); double ( *calc_network_diff ) ( struct work* ); bool ( *ready_to_mine ) ( struct work*, struct stratum_ctx*, int ); @@ -228,11 +231,17 @@ void std_le_build_stratum_request( char *req, struct work *work ); void std_be_build_stratum_request( char *req, struct work *work ); void jr2_build_stratum_request ( char *req, struct work *work ); +char* std_malloc_txs_request( struct work *work ); + // Default is do_nothing (assumed LE) void set_work_data_big_endian( struct work *work ); double std_calc_network_diff( struct work *work ); +void std_build_block_header( struct work* g_work, uint32_t version, + uint32_t *prevhash, uint32_t *merkle_root, + uint32_t ntime, uint32_t nbits ); + void std_build_extraheader( struct work *work, struct stratum_ctx *sctx ); json_t* std_longpoll_rpc_call( CURL *curl, int *err, char *lp_url ); diff --git a/algo/hodl/hodl-gate.c b/algo/hodl/hodl-gate.c index 691a0abb..d9303894 100644 --- a/algo/hodl/hodl-gate.c +++ b/algo/hodl/hodl-gate.c @@ -42,15 +42,83 @@ void hodl_le_build_stratum_request( char* req, struct work* work, free( xnonce2str ); } +char* hodl_malloc_txs_request( struct work *work ) +{ + char* req; + json_t *val; + char data_str[2 * sizeof(work->data) + 1]; + int i; + + for ( i = 0; i < ARRAY_SIZE(work->data); i++ ) + be32enc( work->data + i, work->data[i] ); + + bin2hex( data_str, (unsigned char *)work->data, 88 ); + if ( work->workid ) + { + char *params; + val = json_object(); + json_object_set_new( val, "workid", json_string( work->workid ) ); + params = json_dumps( val, 0 ); + json_decref( val ); + req = malloc( 128 + 2*88 + strlen( work->txs ) + strlen( params ) ); + sprintf( req, + "{\"method\": \"submitblock\", \"params\": [\"%s%s\", %s], \"id\":1}\r\n", + data_str, work->txs, params); + free( params ); + } + else + { + req = malloc( 128 + 2*88 + strlen(work->txs)); + sprintf( req, + "{\"method\": \"submitblock\", \"params\": [\"%s%s\"], \"id\":1}\r\n", + data_str, work->txs); + } + return req; +} + + +void hodl_build_block_header( struct work* g_work, uint32_t version, + uint32_t *prevhash, uint32_t *merkle_tree, + uint32_t ntime, uint32_t nbits ) +{ + int i; + + memset( g_work->data, 0, sizeof(g_work->data) ); + g_work->data[0] = version; + + if ( have_stratum ) + for ( i = 0; i < 8; i++ ) + g_work->data[1 + i] = le32dec( prevhash + i ); + else + for (i = 0; i < 8; i++) + g_work->data[ 8-i ] = le32dec( prevhash + i ); + + for ( i = 0; i < 8; i++ ) + g_work->data[9 + i] = be32dec( merkle_tree + i ); + + g_work->data[ algo_gate.ntime_index ] = ntime; + g_work->data[ algo_gate.nbits_index ] = nbits; + g_work->data[22] = 0x80000000; + g_work->data[31] = 0x00000280; +} + +// hodl build_extra_header is redundant, hodl can use std_build_extra_header +// and call hodl_build_block_header. +#if 0 void hodl_build_extraheader( struct work* g_work, struct stratum_ctx *sctx ) { - uchar merkle_root[64] = { 0 }; + uchar merkle_tree[64] = { 0 }; size_t t; - int i; +// int i; - algo_gate.gen_merkle_root( merkle_root, sctx ); + algo_gate.gen_merkle_root( merkle_tree, sctx ); // Increment extranonce2 for ( t = 0; t < sctx->xnonce2_size && !( ++sctx->job.xnonce2[t] ); t++ ); + + algo_gate.build_block_header( g_work, le32dec( sctx->job.version ), + (uint32_t*) sctx->job.prevhash, (uint32_t*) merkle_tree, + le32dec( sctx->job.ntime ), le32dec( sctx->job.nbits ) ); +/* // Assemble block header memset( g_work->data, 0, sizeof(g_work->data) ); g_work->data[0] = le32dec( sctx->job.version ); @@ -63,7 +131,9 @@ void hodl_build_extraheader( struct work* g_work, struct stratum_ctx *sctx ) g_work->data[ algo_gate.nbits_index ] = le32dec( sctx->job.nbits ); g_work->data[22] = 0x80000000; g_work->data[31] = 0x00000280; +*/ } +#endif // called only by thread 0, saves a backup of g_work void hodl_get_new_work( struct work* work, struct work* g_work) @@ -73,6 +143,22 @@ void hodl_get_new_work( struct work* work, struct work* g_work) hodl_work.data[ algo_gate.nonce_index ] = ( clock() + rand() ) % 9999; } +json_t *hodl_longpoll_rpc_call( CURL *curl, int *err, char* lp_url ) +{ + json_t *val; + char *req = NULL; + + if ( have_gbt ) + { + req = malloc( strlen( gbt_lp_req ) + strlen( lp_id ) + 1 ); + sprintf( req, gbt_lp_req, lp_id ); + } + val = json_rpc_call( curl, lp_url, rpc_userpass, + req ? req : getwork_req, err, JSON_RPC_LONGPOLL ); + free( req ); + return val; +} + // called by every thread, copies the backup to each thread's work. void hodl_resync_threads( struct work* work ) { @@ -112,13 +198,17 @@ bool register_hodl_algo( algo_gate_t* gate ) gate->optimizations = SSE2_OPT | AES_OPT | AVX_OPT | AVX2_OPT; gate->scanhash = (void*)&hodl_scanhash; gate->get_new_work = (void*)&hodl_get_new_work; + gate->longpoll_rpc_call = (void*)&hodl_longpoll_rpc_call; gate->set_target = (void*)&hodl_set_target; gate->build_stratum_request = (void*)&hodl_le_build_stratum_request; - gate->build_extraheader = (void*)&hodl_build_extraheader; + gate->malloc_txs_request = (void*)&hodl_malloc_txs_request; + gate->build_block_header = (void*)&hodl_build_block_header; +// gate->build_extraheader = (void*)&hodl_build_extraheader; gate->resync_threads = (void*)&hodl_resync_threads; gate->do_this_thread = (void*)&hodl_do_this_thread; gate->work_cmp_size = 76; hodl_scratchbuf = (unsigned char*)malloc( 1 << 30 ); + allow_getwork = false; return ( hodl_scratchbuf != NULL ); } diff --git a/algo/ripemd/lbry-gate.c b/algo/ripemd/lbry-gate.c index 5e046626..c617b101 100644 --- a/algo/ripemd/lbry-gate.c +++ b/algo/ripemd/lbry-gate.c @@ -40,6 +40,35 @@ void lbry_le_build_stratum_request( char *req, struct work *work, rpc_user, work->job_id, xnonce2str, ntimestr, noncestr ); free(xnonce2str); } + +// don't use lbry_build_block_header, it can't handle clasim, do it inline +// in lbry_build_extraheader. The side effect is no gbt support for lbry. +void lbry_build_block_header( struct work* g_work, uint32_t version, + uint32_t *prevhash, uint32_t *merkle_root, + uint32_t ntime, uint32_t nbits ) +{ + int i; + memset( g_work->data, 0, sizeof(g_work->data) ); + g_work->data[0] = version; + + if ( have_stratum ) + for ( i = 0; i < 8; i++ ) + g_work->data[1 + i] = le32dec( prevhash + i ); + else + for (i = 0; i < 8; i++) + g_work->data[ 8-i ] = le32dec( prevhash + i ); + + for ( i = 0; i < 8; i++ ) + g_work->data[9 + i] = be32dec( merkle_root + i ); + +// for ( int i = 0; i < 8; i++ ) +// g_work->data[17 + i] = claim[i]; + + g_work->data[ LBRY_NTIME_INDEX ] = ntime; + g_work->data[ LBRY_NBITS_INDEX ] = nbits; + g_work->data[28] = 0x80000000; +} + void lbry_build_extraheader( struct work* g_work, struct stratum_ctx* sctx ) { unsigned char merkle_root[64] = { 0 }; @@ -50,14 +79,23 @@ void lbry_build_extraheader( struct work* g_work, struct stratum_ctx* sctx ) // Increment extranonce2 for ( t = 0; t < sctx->xnonce2_size && !( ++sctx->job.xnonce2[t] ); t++ ); // Assemble block header + +// algo_gate.build_block_header( g_work, le32dec( sctx->job.version ), +// (uint32_t*) sctx->job.prevhash, (uint32_t*) merkle_root, +// le32dec( sctx->job.ntime ), le32dec( sctx->job.nbits ) ); + memset( g_work->data, 0, sizeof(g_work->data) ); g_work->data[0] = le32dec( sctx->job.version ); + for ( i = 0; i < 8; i++ ) g_work->data[1 + i] = le32dec( (uint32_t *) sctx->job.prevhash + i ); + for ( i = 0; i < 8; i++ ) g_work->data[9 + i] = be32dec( (uint32_t *) merkle_root + i ); + for ( int i = 0; i < 8; i++ ) g_work->data[17 + i] = ((uint32_t*)sctx->job.claim)[i]; + g_work->data[ LBRY_NTIME_INDEX ] = le32dec(sctx->job.ntime); g_work->data[ LBRY_NBITS_INDEX ] = le32dec(sctx->job.nbits); g_work->data[28] = 0x80000000; @@ -86,6 +124,7 @@ bool register_lbry_algo( algo_gate_t* gate ) gate->calc_network_diff = (void*)&lbry_calc_network_diff; gate->get_max64 = (void*)&lbry_get_max64; gate->build_stratum_request = (void*)&lbry_le_build_stratum_request; +// gate->build_block_header = (void*)&build_block_header; gate->build_extraheader = (void*)&lbry_build_extraheader; gate->set_target = (void*)&lbry_set_target; gate->ntime_index = LBRY_NTIME_INDEX; diff --git a/configure b/configure index b962b19b..fa96f5df 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for cpuminer-opt 3.8.3.2. +# Generated by GNU Autoconf 2.69 for cpuminer-opt 3.8.3.3. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -577,8 +577,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='cpuminer-opt' PACKAGE_TARNAME='cpuminer-opt' -PACKAGE_VERSION='3.8.3.2' -PACKAGE_STRING='cpuminer-opt 3.8.3.2' +PACKAGE_VERSION='3.8.3.3' +PACKAGE_STRING='cpuminer-opt 3.8.3.3' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1321,7 +1321,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures cpuminer-opt 3.8.3.2 to adapt to many kinds of systems. +\`configure' configures cpuminer-opt 3.8.3.3 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1392,7 +1392,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of cpuminer-opt 3.8.3.2:";; + short | recursive ) echo "Configuration of cpuminer-opt 3.8.3.3:";; esac cat <<\_ACEOF @@ -1497,7 +1497,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -cpuminer-opt configure 3.8.3.2 +cpuminer-opt configure 3.8.3.3 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2000,7 +2000,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by cpuminer-opt $as_me 3.8.3.2, which was +It was created by cpuminer-opt $as_me 3.8.3.3, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2981,7 +2981,7 @@ fi # Define the identity of the package. PACKAGE='cpuminer-opt' - VERSION='3.8.3.2' + VERSION='3.8.3.3' cat >>confdefs.h <<_ACEOF @@ -6677,7 +6677,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by cpuminer-opt $as_me 3.8.3.2, which was +This file was extended by cpuminer-opt $as_me 3.8.3.3, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -6743,7 +6743,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -cpuminer-opt config.status 3.8.3.2 +cpuminer-opt config.status 3.8.3.3 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 5bd142e8..f1bc90d1 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([cpuminer-opt], [3.8.3.2]) +AC_INIT([cpuminer-opt], [3.8.3.3]) AC_PREREQ([2.59c]) AC_CANONICAL_SYSTEM diff --git a/cpu-miner.c b/cpu-miner.c index 7f9fe86b..9c71fc75 100644 --- a/cpu-miner.c +++ b/cpu-miner.c @@ -177,7 +177,7 @@ static struct work g_work = {{ 0 }}; time_t g_work_time = 0; static pthread_mutex_t g_work_lock; static bool submit_old = false; -static char* lp_id; +char* lp_id; static void workio_cmd_free(struct workio_cmd *wc); @@ -434,297 +434,319 @@ static bool get_mininginfo(CURL *curl, struct work *work) } // hodl needs 4 but leave it at 3 until gbt better understood -#define BLOCK_VERSION_CURRENT 3 - -static bool gbt_work_decode(const json_t *val, struct work *work) -{ - int i, n; - uint32_t version, curtime, bits; - uint32_t prevhash[8]; - uint32_t target[8]; - int cbtx_size; - uchar *cbtx = NULL; - int tx_count, tx_size; - uchar txc_vi[9]; - uchar(*merkle_tree)[32] = NULL; - bool coinbase_append = false; - bool submit_coinbase = false; - bool version_force = false; - bool version_reduce = false; - json_t *tmp, *txa; - bool rc = false; - - tmp = json_object_get(val, "mutable"); - if (tmp && json_is_array(tmp)) { - n = (int) json_array_size(tmp); - for (i = 0; i < n; i++) { - const char *s = json_string_value(json_array_get(tmp, i)); - if (!s) - continue; - if (!strcmp(s, "coinbase/append")) - coinbase_append = true; - else if (!strcmp(s, "submit/coinbase")) - submit_coinbase = true; - else if (!strcmp(s, "version/force")) - version_force = true; - else if (!strcmp(s, "version/reduce")) - version_reduce = true; - } - } +//#define BLOCK_VERSION_CURRENT 3 +#define BLOCK_VERSION_CURRENT 4 + +static bool gbt_work_decode( const json_t *val, struct work *work ) +{ + int i, n; + uint32_t version, curtime, bits; + uint32_t prevhash[8]; + uint32_t target[8]; + int cbtx_size; + uchar *cbtx = NULL; + int tx_count, tx_size; + uchar txc_vi[9]; + uchar(*merkle_tree)[32] = NULL; + bool coinbase_append = false; + bool submit_coinbase = false; + bool version_force = false; + bool version_reduce = false; + json_t *tmp, *txa; + bool rc = false; + + tmp = json_object_get( val, "mutable" ); + if ( tmp && json_is_array( tmp ) ) + { + n = (int) json_array_size( tmp ); + for ( i = 0; i < n; i++ ) + { + const char *s = json_string_value( json_array_get( tmp, i ) ); + if ( !s ) + continue; + if ( !strcmp( s, "coinbase/append" ) ) coinbase_append = true; + else if ( !strcmp( s, "submit/coinbase" ) ) submit_coinbase = true; + else if ( !strcmp( s, "version/force" ) ) version_force = true; + else if ( !strcmp( s, "version/reduce" ) ) version_reduce = true; + } + } - tmp = json_object_get(val, "height"); - if (!tmp || !json_is_integer(tmp)) { - applog(LOG_ERR, "JSON invalid height"); - goto out; - } - work->height = (int) json_integer_value(tmp); - applog(LOG_BLUE, "Current block is %d", work->height); + tmp = json_object_get( val, "height" ); + if ( !tmp || !json_is_integer( tmp ) ) + { + applog( LOG_ERR, "JSON invalid height" ); + goto out; + } + work->height = (int) json_integer_value( tmp ); + applog( LOG_BLUE, "Current block is %d", work->height ); - tmp = json_object_get(val, "version"); - if (!tmp || !json_is_integer(tmp)) { - applog(LOG_ERR, "JSON invalid version"); - goto out; - } - version = (uint32_t) json_integer_value(tmp); - if ((version & 0xffU) > BLOCK_VERSION_CURRENT) { - if (version_reduce) { - version = (version & ~0xffU) | BLOCK_VERSION_CURRENT; - } else if (have_gbt && allow_getwork && !version_force) { - applog(LOG_DEBUG, "Switching to getwork, gbt version %d", - version); - have_gbt = false; - goto out; - } else if (!version_force) { - applog(LOG_ERR, "Unrecognized block version: %u", version); - goto out; - } - } + tmp = json_object_get(val, "version"); + if ( !tmp || !json_is_integer( tmp ) ) + { + applog( LOG_ERR, "JSON invalid version" ); + goto out; + } + version = (uint32_t) json_integer_value( tmp ); + if ( (version & 0xffU) > BLOCK_VERSION_CURRENT ) + { + if ( version_reduce ) + { + version = ( version & ~0xffU ) | BLOCK_VERSION_CURRENT; + } + else if ( have_gbt && allow_getwork && !version_force ) + { + applog( LOG_DEBUG, "Switching to getwork, gbt version %d", version ); + have_gbt = false; + goto out; + } + else if ( !version_force ) + { + applog(LOG_ERR, "Unrecognized block version: %u", version); + goto out; + } + } - if ( unlikely( !jobj_binary(val, "previousblockhash", prevhash, - sizeof(prevhash)) ) ) - { - applog(LOG_ERR, "JSON invalid previousblockhash"); - goto out; - } + if ( unlikely( !jobj_binary(val, "previousblockhash", prevhash, + sizeof(prevhash)) ) ) + { + applog( LOG_ERR, "JSON invalid previousblockhash" ); + goto out; + } - tmp = json_object_get(val, "curtime"); - if (!tmp || !json_is_integer(tmp)) { - applog(LOG_ERR, "JSON invalid curtime"); - goto out; - } - curtime = (uint32_t) json_integer_value(tmp); + tmp = json_object_get( val, "curtime" ); + if ( !tmp || !json_is_integer( tmp ) ) + { + applog( LOG_ERR, "JSON invalid curtime" ); + goto out; + } + curtime = (uint32_t) json_integer_value(tmp); - if (unlikely(!jobj_binary(val, "bits", &bits, sizeof(bits)))) { - applog(LOG_ERR, "JSON invalid bits"); - goto out; - } + if ( unlikely( !jobj_binary( val, "bits", &bits, sizeof(bits) ) ) ) + { + applog(LOG_ERR, "JSON invalid bits"); + goto out; + } - /* find count and size of transactions */ - txa = json_object_get(val, "transactions"); - if (!txa || !json_is_array(txa)) { - applog(LOG_ERR, "JSON invalid transactions"); - goto out; - } - tx_count = (int) json_array_size(txa); - tx_size = 0; - for (i = 0; i < tx_count; i++) { - const json_t *tx = json_array_get(txa, i); - const char *tx_hex = json_string_value(json_object_get(tx, "data")); - if (!tx_hex) { - applog(LOG_ERR, "JSON invalid transactions"); - goto out; - } - tx_size += (int) (strlen(tx_hex) / 2); - } + /* find count and size of transactions */ + txa = json_object_get(val, "transactions" ); + if ( !txa || !json_is_array( txa ) ) + { + applog( LOG_ERR, "JSON invalid transactions" ); + goto out; + } + tx_count = (int) json_array_size( txa ); + tx_size = 0; + for ( i = 0; i < tx_count; i++ ) + { + const json_t *tx = json_array_get( txa, i ); + const char *tx_hex = json_string_value( json_object_get( tx, "data" ) ); + if ( !tx_hex ) + { + applog( LOG_ERR, "JSON invalid transactions" ); + goto out; + } + tx_size += (int) ( strlen( tx_hex ) / 2 ); + } - /* build coinbase transaction */ - tmp = json_object_get(val, "coinbasetxn"); - if (tmp) { - const char *cbtx_hex = json_string_value(json_object_get(tmp, "data")); - cbtx_size = cbtx_hex ? (int) strlen(cbtx_hex) / 2 : 0; - cbtx = (uchar*) malloc(cbtx_size + 100); - if (cbtx_size < 60 || !hex2bin(cbtx, cbtx_hex, cbtx_size)) { - applog(LOG_ERR, "JSON invalid coinbasetxn"); - goto out; - } - } else { - int64_t cbvalue; - if (!pk_script_size) { - if (allow_getwork) { - applog(LOG_INFO, "No payout address provided, switching to getwork"); - have_gbt = false; - } else - applog(LOG_ERR, "No payout address provided"); - goto out; - } - tmp = json_object_get(val, "coinbasevalue"); - if (!tmp || !json_is_number(tmp)) { - applog(LOG_ERR, "JSON invalid coinbasevalue"); - goto out; - } - cbvalue = (int64_t) (json_is_integer(tmp) ? json_integer_value(tmp) : json_number_value(tmp)); - cbtx = (uchar*) malloc(256); - le32enc((uint32_t *)cbtx, 1); /* version */ - cbtx[4] = 1; /* in-counter */ - memset(cbtx+5, 0x00, 32); /* prev txout hash */ - le32enc((uint32_t *)(cbtx+37), 0xffffffff); /* prev txout index */ - cbtx_size = 43; - /* BIP 34: height in coinbase */ - for (n = work->height; n; n >>= 8) - cbtx[cbtx_size++] = n & 0xff; - cbtx[42] = cbtx_size - 43; - cbtx[41] = cbtx_size - 42; /* scriptsig length */ - le32enc((uint32_t *)(cbtx+cbtx_size), 0xffffffff); /* sequence */ - cbtx_size += 4; - cbtx[cbtx_size++] = 1; /* out-counter */ - le32enc((uint32_t *)(cbtx+cbtx_size), (uint32_t)cbvalue); /* value */ - le32enc((uint32_t *)(cbtx+cbtx_size+4), cbvalue >> 32); - cbtx_size += 8; - cbtx[cbtx_size++] = (uint8_t) pk_script_size; /* txout-script length */ - memcpy(cbtx+cbtx_size, pk_script, pk_script_size); - cbtx_size += (int) pk_script_size; - le32enc((uint32_t *)(cbtx+cbtx_size), 0); /* lock time */ - cbtx_size += 4; - coinbase_append = true; - } - if (coinbase_append) - { - unsigned char xsig[100]; - int xsig_len = 0; - if (*coinbase_sig) { - n = (int) strlen(coinbase_sig); - if (cbtx[41] + xsig_len + n <= 100) { - memcpy(xsig+xsig_len, coinbase_sig, n); - xsig_len += n; - } else { - applog(LOG_WARNING, "Signature does not fit in coinbase, skipping"); - } - } - tmp = json_object_get(val, "coinbaseaux"); - if (tmp && json_is_object(tmp)) - { - void *iter = json_object_iter(tmp); - while (iter) - { - unsigned char buf[100]; - const char *s = json_string_value(json_object_iter_value(iter)); - n = s ? (int) (strlen(s) / 2) : 0; - if (!s || n > 100 || !hex2bin(buf, s, n)) { - applog(LOG_ERR, "JSON invalid coinbaseaux"); - break; - } - if (cbtx[41] + xsig_len + n <= 100) { - memcpy(xsig+xsig_len, buf, n); - xsig_len += n; - } - iter = json_object_iter_next(tmp, iter); - } - } - if (xsig_len) - { - unsigned char *ssig_end = cbtx + 42 + cbtx[41]; - int push_len = cbtx[41] + xsig_len < 76 ? 1 : + /* build coinbase transaction */ + tmp = json_object_get( val, "coinbasetxn" ); + if ( tmp ) + { + const char *cbtx_hex = json_string_value( json_object_get( tmp, "data" )); + cbtx_size = cbtx_hex ? (int) strlen( cbtx_hex ) / 2 : 0; + cbtx = (uchar*) malloc( cbtx_size + 100 ); + if ( cbtx_size < 60 || !hex2bin( cbtx, cbtx_hex, cbtx_size ) ) + { + applog( LOG_ERR, "JSON invalid coinbasetxn" ); + goto out; + } + } + else + { + int64_t cbvalue; + if ( !pk_script_size ) + { + if ( allow_getwork ) + { + applog( LOG_INFO, "No payout address provided, switching to getwork"); + have_gbt = false; + } + else + applog( LOG_ERR, "No payout address provided" ); + goto out; + } + tmp = json_object_get( val, "coinbasevalue" ); + if ( !tmp || !json_is_number( tmp ) ) + { + applog( LOG_ERR, "JSON invalid coinbasevalue" ); + goto out; + } + cbvalue = (int64_t) ( json_is_integer( tmp ) ? json_integer_value( tmp ) + : json_number_value( tmp ) ); + cbtx = (uchar*) malloc(256); + le32enc( (uint32_t *)cbtx, 1 ); /* version */ + cbtx[4] = 1; /* in-counter */ + memset( cbtx+5, 0x00, 32 ); /* prev txout hash */ + le32enc( (uint32_t *)(cbtx+37), 0xffffffff ); /* prev txout index */ + cbtx_size = 43; + /* BIP 34: height in coinbase */ + for ( n = work->height; n; n >>= 8 ) + cbtx[cbtx_size++] = n & 0xff; + cbtx[42] = cbtx_size - 43; + cbtx[41] = cbtx_size - 42; /* scriptsig length */ + le32enc( (uint32_t *)( cbtx+cbtx_size ), 0xffffffff ); /* sequence */ + cbtx_size += 4; + cbtx[ cbtx_size++ ] = 1; /* out-counter */ + le32enc( (uint32_t *)( cbtx+cbtx_size) , (uint32_t)cbvalue ); /* value */ + le32enc( (uint32_t *)( cbtx+cbtx_size+4 ), cbvalue >> 32 ); + cbtx_size += 8; + cbtx[ cbtx_size++ ] = (uint8_t) pk_script_size; /* txout-script length */ + memcpy( cbtx+cbtx_size, pk_script, pk_script_size ); + cbtx_size += (int) pk_script_size; + le32enc( (uint32_t *)( cbtx+cbtx_size ), 0 ); /* lock time */ + cbtx_size += 4; + coinbase_append = true; + } + if ( coinbase_append ) + { + unsigned char xsig[100]; + int xsig_len = 0; + if ( *coinbase_sig ) + { + n = (int) strlen( coinbase_sig ); + if ( cbtx[41] + xsig_len + n <= 100 ) + { + memcpy( xsig+xsig_len, coinbase_sig, n ); + xsig_len += n; + } + else + { + applog( LOG_WARNING, + "Signature does not fit in coinbase, skipping" ); + } + } + tmp = json_object_get( val, "coinbaseaux" ); + if ( tmp && json_is_object( tmp ) ) + { + void *iter = json_object_iter( tmp ); + while ( iter ) + { + unsigned char buf[100]; + const char *s = json_string_value( json_object_iter_value( iter ) ); + n = s ? (int) ( strlen(s) / 2 ) : 0; + if ( !s || n > 100 || !hex2bin( buf, s, n ) ) + { + applog(LOG_ERR, "JSON invalid coinbaseaux"); + break; + } + if ( cbtx[41] + xsig_len + n <= 100 ) + { + memcpy( xsig+xsig_len, buf, n ); + xsig_len += n; + } + iter = json_object_iter_next( tmp, iter ); + } + } + if ( xsig_len ) + { + unsigned char *ssig_end = cbtx + 42 + cbtx[41]; + int push_len = cbtx[41] + xsig_len < 76 ? 1 : cbtx[41] + 2 + xsig_len > 100 ? 0 : 2; - n = xsig_len + push_len; - memmove(ssig_end + n, ssig_end, cbtx_size - 42 - cbtx[41]); - cbtx[41] += n; - if (push_len == 2) - *(ssig_end++) = 0x4c; /* OP_PUSHDATA1 */ - if (push_len) - *(ssig_end++) = xsig_len; - memcpy(ssig_end, xsig, xsig_len); - cbtx_size += n; - } - } + n = xsig_len + push_len; + memmove( ssig_end + n, ssig_end, cbtx_size - 42 - cbtx[41] ); + cbtx[41] += n; + if ( push_len == 2 ) + *(ssig_end++) = 0x4c; /* OP_PUSHDATA1 */ + if ( push_len ) + *(ssig_end++) = xsig_len; + memcpy( ssig_end, xsig, xsig_len ); + cbtx_size += n; + } + } - n = varint_encode(txc_vi, 1 + tx_count); - work->txs = (char*) malloc(2 * (n + cbtx_size + tx_size) + 1); - bin2hex(work->txs, txc_vi, n); - bin2hex(work->txs + 2*n, cbtx, cbtx_size); + n = varint_encode( txc_vi, 1 + tx_count ); + work->txs = (char*) malloc( 2 * ( n + cbtx_size + tx_size ) + 1 ); + bin2hex( work->txs, txc_vi, n ); + bin2hex( work->txs + 2*n, cbtx, cbtx_size ); - /* generate merkle root */ - merkle_tree = (uchar(*)[32]) calloc(((1 + tx_count + 1) & ~1), 32); - sha256d(merkle_tree[0], cbtx, cbtx_size); - for (i = 0; i < tx_count; i++) - { - tmp = json_array_get(txa, i); - const char *tx_hex = json_string_value(json_object_get(tmp, "data")); - const int tx_size = tx_hex ? (int) (strlen(tx_hex) / 2) : 0; - unsigned char *tx = (uchar*) malloc(tx_size); - if (!tx_hex || !hex2bin(tx, tx_hex, tx_size)) - { - applog(LOG_ERR, "JSON invalid transactions"); - free(tx); - goto out; - } - sha256d(merkle_tree[1 + i], tx, tx_size); - if (!submit_coinbase) - strcat(work->txs, tx_hex); - } - n = 1 + tx_count; - while (n > 1) - { - if (n % 2) - { - memcpy(merkle_tree[n], merkle_tree[n-1], 32); - ++n; - } - n /= 2; - for (i = 0; i < n; i++) - sha256d(merkle_tree[i], merkle_tree[2*i], 64); - } + /* generate merkle root */ + merkle_tree = (uchar(*)[32]) calloc(((1 + tx_count + 1) & ~1), 32); + sha256d(merkle_tree[0], cbtx, cbtx_size); + for ( i = 0; i < tx_count; i++ ) + { + tmp = json_array_get( txa, i ); + const char *tx_hex = json_string_value( json_object_get( tmp, "data" ) ); + const int tx_size = tx_hex ? (int) ( strlen( tx_hex ) / 2 ) : 0; + unsigned char *tx = (uchar*) malloc( tx_size ); + if ( !tx_hex || !hex2bin( tx, tx_hex, tx_size ) ) + { + applog( LOG_ERR, "JSON invalid transactions" ); + free( tx ); + goto out; + } + sha256d( merkle_tree[1 + i], tx, tx_size ); + if ( !submit_coinbase ) + strcat( work->txs, tx_hex ); + } + n = 1 + tx_count; + while ( n > 1 ) + { + if ( n % 2 ) + { + memcpy( merkle_tree[n], merkle_tree[n-1], 32 ); + ++n; + } + n /= 2; + for ( i = 0; i < n; i++ ) + sha256d( merkle_tree[i], merkle_tree[2*i], 64 ); + } - /* assemble block header */ - work->data[0] = swab32(version); - for (i = 0; i < 8; i++) - work->data[8 - i] = le32dec(prevhash + i); - for (i = 0; i < 8; i++) - work->data[9 + i] = be32dec((uint32_t *)merkle_tree[0] + i); - work->data[17] = swab32(curtime); - work->data[18] = le32dec(&bits); - memset(work->data + 19, 0x00, 52); - work->data[20] = 0x80000000; - work->data[31] = 0x00000280; - - if ( unlikely( !jobj_binary(val, "target", target, sizeof(target)) ) ) - { - applog(LOG_ERR, "JSON invalid target"); - goto out; - } - for (i = 0; i < ARRAY_SIZE(work->target); i++) - work->target[7 - i] = be32dec(target + i); + /* assemble block header */ + algo_gate.build_block_header( work, swab32( version ), + (uint32_t*) prevhash, (uint32_t*) merkle_tree, + swab32( curtime ), le32dec( &bits ) ); - tmp = json_object_get(val, "workid"); - if (tmp) - { - if (!json_is_string(tmp)) { - applog(LOG_ERR, "JSON invalid workid"); - goto out; - } - work->workid = strdup(json_string_value(tmp)); - } + if ( unlikely( !jobj_binary(val, "target", target, sizeof(target)) ) ) + { + applog( LOG_ERR, "JSON invalid target" ); + goto out; + } + for ( i = 0; i < ARRAY_SIZE( work->target ); i++ ) + work->target[7 - i] = be32dec( target + i ); - rc = true; + tmp = json_object_get( val, "workid" ); + if ( tmp ) + { + if ( !json_is_string( tmp ) ) + { + applog( LOG_ERR, "JSON invalid workid" ); + goto out; + } + work->workid = strdup( json_string_value( tmp ) ); + } + + rc = true; out: - /* Long polling */ - tmp = json_object_get(val, "longpollid"); - if (want_longpoll && json_is_string(tmp)) - { - free(lp_id); - lp_id = strdup(json_string_value(tmp)); - if (!have_longpoll) - { - char *lp_uri; - tmp = json_object_get(val, "longpolluri"); - lp_uri = json_is_string(tmp) ? strdup(json_string_value(tmp)) : rpc_url; - have_longpoll = true; - tq_push(thr_info[longpoll_thr_id].q, lp_uri); - } - } + /* Long polling */ + tmp = json_object_get( val, "longpollid" ); + if ( want_longpoll && json_is_string( tmp ) ) + { + free( lp_id ); + lp_id = strdup( json_string_value( tmp ) ); + if ( !have_longpoll ) + { + char *lp_uri; + tmp = json_object_get( val, "longpolluri" ); + lp_uri = json_is_string( tmp ) ? strdup( json_string_value( tmp ) ) + : rpc_url; + have_longpoll = true; + tq_push(thr_info[longpoll_thr_id].q, lp_uri); + } + } - free(merkle_tree); - free(cbtx); - return rc; + free( merkle_tree ); + free( cbtx ); + return rc; } void scale_hash_for_display ( double* hashrate, char* units ) @@ -1050,12 +1072,42 @@ bool jr2_submit_getwork_result( CURL *curl, struct work *work ) return true; } -static bool submit_upstream_work( CURL *curl, struct work *work ) +char* std_malloc_txs_request( struct work *work ) { - json_t *val, *res; - char req[JSON_BUF_LEN]; - int i; + char *req; + json_t *val; + char data_str[2 * sizeof(work->data) + 1]; + int i; + for ( i = 0; i < ARRAY_SIZE(work->data); i++ ) + be32enc( work->data + i, work->data[i] ); + bin2hex( data_str, (unsigned char *)work->data, 80 ); + if ( work->workid ) + { + char *params; + val = json_object(); + json_object_set_new( val, "workid", json_string( work->workid ) ); + params = json_dumps( val, 0 ); + json_decref( val ); + req = (char*) malloc( 128 + 2 * 80 + strlen( work->txs ) + + strlen( params ) ); + sprintf( req, + "{\"method\": \"submitblock\", \"params\": [\"%s%s\", %s], \"id\":4}\r\n", + data_str, work->txs, params ); + free( params ); + } + else + { + req = (char*) malloc( 128 + 2 * 80 + strlen( work->txs ) ); + sprintf( req, + "{\"method\": \"submitblock\", \"params\": [\"%s%s\"], \"id\":4}\r\n", + data_str, work->txs); + } + return req; +} + +static bool submit_upstream_work( CURL *curl, struct work *work ) +{ /* pass if the previous hash is not the current previous hash */ if ( !submit_old && memcmp( &work->data[1], &g_work.data[1], 32 ) ) { @@ -1063,6 +1115,7 @@ static bool submit_upstream_work( CURL *curl, struct work *work ) applog(LOG_DEBUG, "DEBUG: stale work detected, discarding"); return true; } + if ( !have_stratum && allow_mininginfo ) { struct work wheight; @@ -1074,8 +1127,10 @@ static bool submit_upstream_work( CURL *curl, struct work *work ) return true; } } + if ( have_stratum ) { + char req[JSON_BUF_LEN]; stratum.sharediff = work->sharediff; algo_gate.build_stratum_request( req, work, &stratum ); if ( unlikely( !stratum_send_line( &stratum, req ) ) ) @@ -1085,71 +1140,49 @@ static bool submit_upstream_work( CURL *curl, struct work *work ) } return true; } - else if (work->txs) + else if ( work->txs ) { - char data_str[2 * sizeof(work->data) + 1]; - char *req; + char *req = NULL; + json_t *val, *res; - for (i = 0; i < ARRAY_SIZE(work->data); i++) - be32enc(work->data + i, work->data[i]); - bin2hex(data_str, (unsigned char *)work->data, 80); - if (work->workid) - { - char *params; - val = json_object(); - json_object_set_new(val, "workid", json_string(work->workid)); - params = json_dumps(val, 0); - json_decref(val); - req = (char*) malloc(128 + 2 * 80 + strlen(work->txs) + strlen(params)); - sprintf( req, - "{\"method\": \"submitblock\", \"params\": [\"%s%s\", %s], \"id\":4}\r\n", - data_str, work->txs, params); - free(params); - } - else - { - req = (char*) malloc(128 + 2 * 80 + strlen(work->txs)); - sprintf(req, - "{\"method\": \"submitblock\", \"params\": [\"%s%s\"], \"id\":4}\r\n", - data_str, work->txs); - } + req = algo_gate.malloc_txs_request( work ); + val = json_rpc_call( curl, rpc_url, rpc_userpass, req, NULL, 0 ); + free( req ); - val = json_rpc_call(curl, rpc_url, rpc_userpass, req, NULL, 0); - free(req); - if (unlikely(!val)) - { - applog(LOG_ERR, "submit_upstream_work json_rpc_call failed"); - return false; - } - res = json_object_get(val, "result"); - if (json_is_object(res)) - { - char *res_str; - bool sumres = false; - void *iter = json_object_iter(res); - while (iter) - { - if (json_is_null(json_object_iter_value(iter))) - { - sumres = true; - break; - } - iter = json_object_iter_next(res, iter); - } - res_str = json_dumps(res, 0); - share_result(sumres, work, res_str); - free(res_str); - } - else - share_result(json_is_null(res), work, json_string_value(res)); - json_decref(val); - return true; + if ( unlikely( !val ) ) + { + applog( LOG_ERR, "submit_upstream_work json_rpc_call failed" ); + return false; + } + res = json_object_get( val, "result" ); + if ( json_is_object( res ) ) + { + char *res_str; + bool sumres = false; + void *iter = json_object_iter( res ); + while ( iter ) + { + if ( json_is_null( json_object_iter_value( iter ) ) ) + { + sumres = true; + break; + } + iter = json_object_iter_next( res, iter ); + } + res_str = json_dumps( res, 0 ); + share_result( sumres, work, res_str ); + free( res_str ); + } + else + share_result( json_is_null( res ), work, json_string_value( res ) ); + json_decref( val ); + return true; } else return algo_gate.submit_getwork_result( curl, work ); } -static const char *getwork_req = +const char *getwork_req = "{\"method\": \"getwork\", \"params\": [], \"id\":0}\r\n"; #define GBT_CAPABILITIES "[\"coinbasetxn\", \"coinbasevalue\", \"longpoll\", \"workid\"]" @@ -1157,83 +1190,83 @@ static const char *getwork_req = static const char *gbt_req = "{\"method\": \"getblocktemplate\", \"params\": [{\"capabilities\": " GBT_CAPABILITIES "}], \"id\":0}\r\n"; -static const char *gbt_lp_req = +const char *gbt_lp_req = "{\"method\": \"getblocktemplate\", \"params\": [{\"capabilities\": " GBT_CAPABILITIES ", \"longpollid\": \"%s\"}], \"id\":0}\r\n"; -static bool get_upstream_work(CURL *curl, struct work *work) +static bool get_upstream_work( CURL *curl, struct work *work ) { - json_t *val; - int err; - bool rc; - struct timeval tv_start, tv_end, diff; + json_t *val; + int err; + bool rc; + struct timeval tv_start, tv_end, diff; start: - gettimeofday(&tv_start, NULL); + gettimeofday( &tv_start, NULL ); - if (jsonrpc_2) - { - char s[128]; - snprintf(s, 128, "{\"method\": \"getjob\", \"params\": {\"id\": \"%s\"}, \"id\":1}\r\n", rpc2_id); - val = json_rpc2_call(curl, rpc_url, rpc_userpass, s, NULL, 0); - } - else - { - val = json_rpc_call(curl, rpc_url, rpc_userpass, - have_gbt ? gbt_req : getwork_req, - &err, have_gbt ? JSON_RPC_QUIET_404 : 0); - } - gettimeofday(&tv_end, NULL); + if ( jsonrpc_2 ) + { + char s[128]; + snprintf( s, 128, "{\"method\": \"getjob\", \"params\": {\"id\": \"%s\"}, \"id\":1}\r\n", rpc2_id ); + val = json_rpc2_call( curl, rpc_url, rpc_userpass, s, NULL, 0 ); + } + else + { + val = json_rpc_call( curl, rpc_url, rpc_userpass, + have_gbt ? gbt_req : getwork_req, &err, + have_gbt ? JSON_RPC_QUIET_404 : 0); + } + gettimeofday( &tv_end, NULL ); - if (have_stratum) - { - if (val) - json_decref(val); + if ( have_stratum ) + { + if ( val ) + json_decref(val); - return true; - } + return true; + } - if (!have_gbt && !allow_getwork) - { - applog(LOG_ERR, "No usable protocol"); - if (val) - json_decref(val); - return false; - } + if ( !have_gbt && !allow_getwork ) + { + applog( LOG_ERR, "No usable protocol" ); + if ( val ) + json_decref( val ); + return false; + } - if (have_gbt && allow_getwork && !val && err == CURLE_OK) - { - applog(LOG_NOTICE, "getblocktemplate failed, falling back to getwork"); - have_gbt = false; - goto start; - } + if ( have_gbt && allow_getwork && !val && err == CURLE_OK ) + { + applog( LOG_NOTICE, "getblocktemplate failed, falling back to getwork" ); + have_gbt = false; + goto start; + } - if (!val) - return false; + if ( !val ) + return false; - if (have_gbt) - { - rc = gbt_work_decode(json_object_get(val, "result"), work); - if (!have_gbt) - { - json_decref(val); - goto start; - } - } - else - rc = work_decode(json_object_get(val, "result"), work); + if ( have_gbt ) + { + rc = gbt_work_decode( json_object_get( val, "result" ), work ); + if ( !have_gbt ) + { + json_decref( val ); + goto start; + } + } + else + rc = work_decode( json_object_get( val, "result" ), work ); - if (opt_protocol && rc) - { - timeval_subtract(&diff, &tv_end, &tv_start); - applog(LOG_DEBUG, "got new work in %.2f ms", - (1000.0 * diff.tv_sec) + (0.001 * diff.tv_usec)); - } + if ( opt_protocol && rc ) + { + timeval_subtract( &diff, &tv_end, &tv_start ); + applog( LOG_DEBUG, "got new work in %.2f ms", + ( 1000.0 * diff.tv_sec ) + ( 0.001 * diff.tv_usec ) ); + } - json_decref(val); - // store work height in solo - get_mininginfo(curl, work); - return rc; + json_decref( val ); + // store work height in solo + get_mininginfo(curl, work); + return rc; } static void workio_cmd_free(struct workio_cmd *wc) @@ -1881,65 +1914,59 @@ static void *miner_thread( void *userdata ) gettimeofday( (struct timeval *) &tv_start, NULL ); // Scan for nonce - nonce_found = (bool) algo_gate.scanhash( thr_id, &work, max_nonce, - &hashes_done ); + nonce_found = algo_gate.scanhash( thr_id, &work, max_nonce, + &hashes_done ); // record scanhash elapsed time - gettimeofday(&tv_end, NULL); - timeval_subtract(&diff, &tv_end, &tv_start); - if (diff.tv_usec || diff.tv_sec) + gettimeofday( &tv_end, NULL ); + timeval_subtract( &diff, &tv_end, &tv_start ); + if ( diff.tv_usec || diff.tv_sec ) { - pthread_mutex_lock(&stats_lock); + pthread_mutex_lock( &stats_lock ); thr_hashcount[thr_id] = hashes_done; thr_hashrates[thr_id] = - hashes_done / (diff.tv_sec + diff.tv_usec * 1e-6); - pthread_mutex_unlock(&stats_lock); + hashes_done / ( diff.tv_sec + diff.tv_usec * 1e-6 ); + pthread_mutex_unlock( &stats_lock ); } - // if nonce(s) submit work + // if nonce(s) found submit work if ( nonce_found && !opt_benchmark ) - { -/* - int num_submitted = 0; - + { // 4 way with multiple nonces, copy individually to work and submit. + if ( nonce_found > 1 ) for ( int n = 0; n < nonce_found; n++ ) { *algo_gate.get_nonceptr( work.data ) = work.nonces[n]; if ( submit_work( mythr, &work ) ) - { applog( LOG_NOTICE, "Share submitted." ); - num_submitted++; - } else { applog( LOG_WARNING, "Failed to submit share." ); break; } } - // must be a one way algo, nonce is already in work data - if ( !num_submitted ) - { -*/ + else + { // only 1 nonce, in work ready to submit. + if ( !submit_work( mythr, &work ) ) { applog( LOG_WARNING, "Failed to submit share." ); break; } applog( LOG_NOTICE, "Share submitted." ); -// } + } // prevent stale work in solo // we can't submit twice a block! - if (!have_stratum && !have_longpoll) + if ( !have_stratum && !have_longpoll ) { - pthread_mutex_lock(&g_work_lock); + pthread_mutex_lock( &g_work_lock ); // will force getwork g_work_time = 0; - pthread_mutex_unlock(&g_work_lock); + pthread_mutex_unlock( &g_work_lock ); } } // display hashrate - if (!opt_quiet) + if ( !opt_quiet ) { char hc[16]; char hr[16]; @@ -2236,29 +2263,47 @@ static bool stratum_handle_response( char *buf ) return ret; } -void std_build_extraheader( struct work* g_work, struct stratum_ctx* sctx ) +// used by stratum and gbt +void std_build_block_header( struct work* g_work, uint32_t version, + uint32_t *prevhash, uint32_t *merkle_tree, + uint32_t ntime, uint32_t nbits ) { - uchar merkle_root[64] = { 0 }; - size_t t; int i; - algo_gate.gen_merkle_root( merkle_root, sctx ); - // Increment extranonce2 - for ( t = 0; t < sctx->xnonce2_size && !( ++sctx->job.xnonce2[t] ); t++ ); - // Assemble block header memset( g_work->data, 0, sizeof(g_work->data) ); - g_work->data[0] = le32dec( sctx->job.version ); - for ( i = 0; i < 8; i++ ) - g_work->data[1 + i] = le32dec( (uint32_t *) sctx->job.prevhash + i ); + g_work->data[0] = version; + + if ( have_stratum ) + for ( i = 0; i < 8; i++ ) + g_work->data[ 1+i ] = le32dec( prevhash + i ); + else + for (i = 0; i < 8; i++) + g_work->data[ 8-i ] = le32dec( prevhash + i ); + for ( i = 0; i < 8; i++ ) - g_work->data[9 + i] = be32dec( (uint32_t *) merkle_root + i ); + g_work->data[ 9+i ] = be32dec( merkle_tree + i ); - g_work->data[ algo_gate.ntime_index ] = le32dec(sctx->job.ntime); - g_work->data[ algo_gate.nbits_index ] = le32dec(sctx->job.nbits); + g_work->data[ algo_gate.ntime_index ] = ntime; + g_work->data[ algo_gate.nbits_index ] = nbits; g_work->data[20] = 0x80000000; g_work->data[31] = 0x00000280; } +void std_build_extraheader( struct work* g_work, struct stratum_ctx* sctx ) +{ + uchar merkle_tree[64] = { 0 }; + size_t t; + + algo_gate.gen_merkle_root( merkle_tree, sctx ); + // Increment extranonce2 + for ( t = 0; t < sctx->xnonce2_size && !( ++sctx->job.xnonce2[t] ); t++ ); + // Assemble block header + + algo_gate.build_block_header( g_work, le32dec( sctx->job.version ), + (uint32_t*) sctx->job.prevhash, (uint32_t*) merkle_tree, + le32dec( sctx->job.ntime ), le32dec(sctx->job.nbits) ); +} + void std_stratum_gen_work( struct stratum_ctx *sctx, struct work *g_work ) { pthread_mutex_lock( &sctx->work_lock ); diff --git a/miner.h b/miner.h index d7ed22a0..01a797c8 100644 --- a/miner.h +++ b/miner.h @@ -648,6 +648,10 @@ extern int opt_timeout; extern bool want_longpoll; extern bool have_longpoll; extern bool have_gbt; +extern char* lp_id; +extern char *rpc_userpass; +extern const char *gbt_lp_req; +extern const char *getwork_req; extern bool allow_getwork; extern bool want_stratum; extern bool have_stratum;