This commit is contained in:
Jay D Dee
2018-02-25 14:15:07 -05:00
parent c24a4bdbc2
commit 157508bd07
10 changed files with 653 additions and 457 deletions

View File

@@ -142,11 +142,11 @@ Donations
cpuminer-opt has no fees of any kind but donations are accepted. cpuminer-opt has no fees of any kind but donations are accepted.
BTC: 12tdvfF7KmAsihBXQXynT6E6th2c2pByTT BTC: 12tdvfF7KmAsihBXQXynT6E6th2c2pByTT
ETH: 0x72122edabcae9d3f57eab0729305a425f6fef6d0 ETH: 0x72122edabcae9d3f57eab0729305a425f6fef6d0
LTC: LdUwoHJnux9r9EKqFWNvAi45kQompHk6e8 LTC: LdUwoHJnux9r9EKqFWNvAi45kQompHk6e8
BCH: 1QKYkB6atn4P7RFozyziAXLEnurwnUM1cQ BCH: 1QKYkB6atn4P7RFozyziAXLEnurwnUM1cQ
BTG: GVUyECtRHeC5D58z9F3nGGfVQndwnsPnHQ BTG: GVUyECtRHeC5D58z9F3nGGfVQndwnsPnHQ
Happy mining! Happy mining!

View File

@@ -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 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 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. Start mining.
@@ -159,6 +160,12 @@ Support for even older x86_64 without AES_NI or SSE2 is not availble.
Change Log 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 v3.8.3.2
Reverted gbt changes from v3.8.0 that broke getwork. Reverted gbt changes from v3.8.0 that broke getwork.

View File

@@ -119,9 +119,11 @@ void init_algo_gate( algo_gate_t* gate )
gate->gen_merkle_root = (void*)&sha256d_gen_merkle_root; gate->gen_merkle_root = (void*)&sha256d_gen_merkle_root;
gate->stratum_gen_work = (void*)&std_stratum_gen_work; gate->stratum_gen_work = (void*)&std_stratum_gen_work;
gate->build_stratum_request = (void*)&std_le_build_stratum_request; 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->set_target = (void*)&std_set_target;
gate->work_decode = (void*)&std_le_work_decode; gate->work_decode = (void*)&std_le_work_decode;
gate->submit_getwork_result = (void*)&std_le_submit_getwork_result; 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->build_extraheader = (void*)&std_build_extraheader;
gate->set_work_data_endian = (void*)&do_nothing; gate->set_work_data_endian = (void*)&do_nothing;
gate->calc_network_diff = (void*)&std_calc_network_diff; gate->calc_network_diff = (void*)&std_calc_network_diff;

View File

@@ -127,7 +127,10 @@ void ( *set_target) ( struct work*, double );
bool ( *submit_getwork_result ) ( CURL*, struct work* ); bool ( *submit_getwork_result ) ( CURL*, struct work* );
void ( *gen_merkle_root ) ( char*, struct stratum_ctx* ); void ( *gen_merkle_root ) ( char*, struct stratum_ctx* );
void ( *build_extraheader ) ( struct work*, 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* ); void ( *build_stratum_request ) ( char*, struct work*, struct stratum_ctx* );
char* ( *malloc_txs_request ) ( struct work* );
void ( *set_work_data_endian ) ( struct work* ); void ( *set_work_data_endian ) ( struct work* );
double ( *calc_network_diff ) ( struct work* ); double ( *calc_network_diff ) ( struct work* );
bool ( *ready_to_mine ) ( struct work*, struct stratum_ctx*, int ); 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 std_be_build_stratum_request( char *req, struct work *work );
void jr2_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) // Default is do_nothing (assumed LE)
void set_work_data_big_endian( struct work *work ); void set_work_data_big_endian( struct work *work );
double std_calc_network_diff( 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 ); void std_build_extraheader( struct work *work, struct stratum_ctx *sctx );
json_t* std_longpoll_rpc_call( CURL *curl, int *err, char *lp_url ); json_t* std_longpoll_rpc_call( CURL *curl, int *err, char *lp_url );

View File

@@ -42,15 +42,83 @@ void hodl_le_build_stratum_request( char* req, struct work* work,
free( xnonce2str ); free( xnonce2str );
} }
void hodl_build_extraheader( struct work* g_work, struct stratum_ctx *sctx ) char* hodl_malloc_txs_request( struct work *work )
{ {
uchar merkle_root[64] = { 0 }; char* req;
size_t t; json_t *val;
char data_str[2 * sizeof(work->data) + 1];
int i; int i;
algo_gate.gen_merkle_root( merkle_root, sctx ); 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_tree[64] = { 0 };
size_t t;
// int i;
algo_gate.gen_merkle_root( merkle_tree, sctx );
// Increment extranonce2 // Increment extranonce2
for ( t = 0; t < sctx->xnonce2_size && !( ++sctx->job.xnonce2[t] ); t++ ); 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 // Assemble block header
memset( g_work->data, 0, sizeof(g_work->data) ); memset( g_work->data, 0, sizeof(g_work->data) );
g_work->data[0] = le32dec( sctx->job.version ); 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[ algo_gate.nbits_index ] = le32dec( sctx->job.nbits );
g_work->data[22] = 0x80000000; g_work->data[22] = 0x80000000;
g_work->data[31] = 0x00000280; g_work->data[31] = 0x00000280;
*/
} }
#endif
// called only by thread 0, saves a backup of g_work // called only by thread 0, saves a backup of g_work
void hodl_get_new_work( struct work* work, struct work* 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; 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. // called by every thread, copies the backup to each thread's work.
void hodl_resync_threads( struct work* 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->optimizations = SSE2_OPT | AES_OPT | AVX_OPT | AVX2_OPT;
gate->scanhash = (void*)&hodl_scanhash; gate->scanhash = (void*)&hodl_scanhash;
gate->get_new_work = (void*)&hodl_get_new_work; 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->set_target = (void*)&hodl_set_target;
gate->build_stratum_request = (void*)&hodl_le_build_stratum_request; 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->resync_threads = (void*)&hodl_resync_threads;
gate->do_this_thread = (void*)&hodl_do_this_thread; gate->do_this_thread = (void*)&hodl_do_this_thread;
gate->work_cmp_size = 76; gate->work_cmp_size = 76;
hodl_scratchbuf = (unsigned char*)malloc( 1 << 30 ); hodl_scratchbuf = (unsigned char*)malloc( 1 << 30 );
allow_getwork = false;
return ( hodl_scratchbuf != NULL ); return ( hodl_scratchbuf != NULL );
} }

View File

@@ -40,6 +40,35 @@ void lbry_le_build_stratum_request( char *req, struct work *work,
rpc_user, work->job_id, xnonce2str, ntimestr, noncestr ); rpc_user, work->job_id, xnonce2str, ntimestr, noncestr );
free(xnonce2str); 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 ) void lbry_build_extraheader( struct work* g_work, struct stratum_ctx* sctx )
{ {
unsigned char merkle_root[64] = { 0 }; unsigned char merkle_root[64] = { 0 };
@@ -50,14 +79,23 @@ void lbry_build_extraheader( struct work* g_work, struct stratum_ctx* sctx )
// Increment extranonce2 // Increment extranonce2
for ( t = 0; t < sctx->xnonce2_size && !( ++sctx->job.xnonce2[t] ); t++ ); for ( t = 0; t < sctx->xnonce2_size && !( ++sctx->job.xnonce2[t] ); t++ );
// Assemble block header // 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) ); memset( g_work->data, 0, sizeof(g_work->data) );
g_work->data[0] = le32dec( sctx->job.version ); g_work->data[0] = le32dec( sctx->job.version );
for ( i = 0; i < 8; i++ ) for ( i = 0; i < 8; i++ )
g_work->data[1 + i] = le32dec( (uint32_t *) sctx->job.prevhash + i ); g_work->data[1 + i] = le32dec( (uint32_t *) sctx->job.prevhash + i );
for ( i = 0; i < 8; i++ ) for ( i = 0; i < 8; i++ )
g_work->data[9 + i] = be32dec( (uint32_t *) merkle_root + i ); g_work->data[9 + i] = be32dec( (uint32_t *) merkle_root + i );
for ( int i = 0; i < 8; i++ ) for ( int i = 0; i < 8; i++ )
g_work->data[17 + i] = ((uint32_t*)sctx->job.claim)[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_NTIME_INDEX ] = le32dec(sctx->job.ntime);
g_work->data[ LBRY_NBITS_INDEX ] = le32dec(sctx->job.nbits); g_work->data[ LBRY_NBITS_INDEX ] = le32dec(sctx->job.nbits);
g_work->data[28] = 0x80000000; 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->calc_network_diff = (void*)&lbry_calc_network_diff;
gate->get_max64 = (void*)&lbry_get_max64; gate->get_max64 = (void*)&lbry_get_max64;
gate->build_stratum_request = (void*)&lbry_le_build_stratum_request; 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->build_extraheader = (void*)&lbry_build_extraheader;
gate->set_target = (void*)&lbry_set_target; gate->set_target = (void*)&lbry_set_target;
gate->ntime_index = LBRY_NTIME_INDEX; gate->ntime_index = LBRY_NTIME_INDEX;

20
configure vendored
View File

@@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # 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. # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -577,8 +577,8 @@ MAKEFLAGS=
# Identity of this package. # Identity of this package.
PACKAGE_NAME='cpuminer-opt' PACKAGE_NAME='cpuminer-opt'
PACKAGE_TARNAME='cpuminer-opt' PACKAGE_TARNAME='cpuminer-opt'
PACKAGE_VERSION='3.8.3.2' PACKAGE_VERSION='3.8.3.3'
PACKAGE_STRING='cpuminer-opt 3.8.3.2' PACKAGE_STRING='cpuminer-opt 3.8.3.3'
PACKAGE_BUGREPORT='' PACKAGE_BUGREPORT=''
PACKAGE_URL='' 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. # 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. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF 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]... Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1392,7 +1392,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in 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 esac
cat <<\_ACEOF cat <<\_ACEOF
@@ -1497,7 +1497,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
cpuminer-opt configure 3.8.3.2 cpuminer-opt configure 3.8.3.3
generated by GNU Autoconf 2.69 generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc. Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2000,7 +2000,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. 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 generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@ $ $0 $@
@@ -2981,7 +2981,7 @@ fi
# Define the identity of the package. # Define the identity of the package.
PACKAGE='cpuminer-opt' PACKAGE='cpuminer-opt'
VERSION='3.8.3.2' VERSION='3.8.3.3'
cat >>confdefs.h <<_ACEOF 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 # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" 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 generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@@ -6743,7 +6743,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\ 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, configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"

View File

@@ -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_PREREQ([2.59c])
AC_CANONICAL_SYSTEM AC_CANONICAL_SYSTEM

View File

@@ -177,7 +177,7 @@ static struct work g_work = {{ 0 }};
time_t g_work_time = 0; time_t g_work_time = 0;
static pthread_mutex_t g_work_lock; static pthread_mutex_t g_work_lock;
static bool submit_old = false; static bool submit_old = false;
static char* lp_id; char* lp_id;
static void workio_cmd_free(struct workio_cmd *wc); static void workio_cmd_free(struct workio_cmd *wc);
@@ -434,9 +434,10 @@ static bool get_mininginfo(CURL *curl, struct work *work)
} }
// hodl needs 4 but leave it at 3 until gbt better understood // hodl needs 4 but leave it at 3 until gbt better understood
#define BLOCK_VERSION_CURRENT 3 //#define BLOCK_VERSION_CURRENT 3
#define BLOCK_VERSION_CURRENT 4
static bool gbt_work_decode(const json_t *val, struct work *work) static bool gbt_work_decode( const json_t *val, struct work *work )
{ {
int i, n; int i, n;
uint32_t version, curtime, bits; uint32_t version, curtime, bits;
@@ -454,47 +455,52 @@ static bool gbt_work_decode(const json_t *val, struct work *work)
json_t *tmp, *txa; json_t *tmp, *txa;
bool rc = false; bool rc = false;
tmp = json_object_get(val, "mutable"); tmp = json_object_get( val, "mutable" );
if (tmp && json_is_array(tmp)) { if ( tmp && json_is_array( tmp ) )
n = (int) json_array_size(tmp); {
for (i = 0; i < n; i++) { n = (int) json_array_size( tmp );
const char *s = json_string_value(json_array_get(tmp, i)); for ( i = 0; i < n; i++ )
if (!s) {
const char *s = json_string_value( json_array_get( tmp, i ) );
if ( !s )
continue; continue;
if (!strcmp(s, "coinbase/append")) if ( !strcmp( s, "coinbase/append" ) ) coinbase_append = true;
coinbase_append = true; else if ( !strcmp( s, "submit/coinbase" ) ) submit_coinbase = true;
else if (!strcmp(s, "submit/coinbase")) else if ( !strcmp( s, "version/force" ) ) version_force = true;
submit_coinbase = true; else if ( !strcmp( s, "version/reduce" ) ) version_reduce = 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"); tmp = json_object_get( val, "height" );
if (!tmp || !json_is_integer(tmp)) { if ( !tmp || !json_is_integer( tmp ) )
applog(LOG_ERR, "JSON invalid height"); {
applog( LOG_ERR, "JSON invalid height" );
goto out; goto out;
} }
work->height = (int) json_integer_value(tmp); work->height = (int) json_integer_value( tmp );
applog(LOG_BLUE, "Current block is %d", work->height); applog( LOG_BLUE, "Current block is %d", work->height );
tmp = json_object_get(val, "version"); tmp = json_object_get(val, "version");
if (!tmp || !json_is_integer(tmp)) { if ( !tmp || !json_is_integer( tmp ) )
applog(LOG_ERR, "JSON invalid version"); {
applog( LOG_ERR, "JSON invalid version" );
goto out; goto out;
} }
version = (uint32_t) json_integer_value(tmp); version = (uint32_t) json_integer_value( tmp );
if ((version & 0xffU) > BLOCK_VERSION_CURRENT) { if ( (version & 0xffU) > BLOCK_VERSION_CURRENT )
if (version_reduce) { {
version = (version & ~0xffU) | BLOCK_VERSION_CURRENT; if ( version_reduce )
} else if (have_gbt && allow_getwork && !version_force) { {
applog(LOG_DEBUG, "Switching to getwork, gbt version %d", version = ( version & ~0xffU ) | BLOCK_VERSION_CURRENT;
version); }
else if ( have_gbt && allow_getwork && !version_force )
{
applog( LOG_DEBUG, "Switching to getwork, gbt version %d", version );
have_gbt = false; have_gbt = false;
goto out; goto out;
} else if (!version_force) { }
else if ( !version_force )
{
applog(LOG_ERR, "Unrecognized block version: %u", version); applog(LOG_ERR, "Unrecognized block version: %u", version);
goto out; goto out;
} }
@@ -503,227 +509,243 @@ static bool gbt_work_decode(const json_t *val, struct work *work)
if ( unlikely( !jobj_binary(val, "previousblockhash", prevhash, if ( unlikely( !jobj_binary(val, "previousblockhash", prevhash,
sizeof(prevhash)) ) ) sizeof(prevhash)) ) )
{ {
applog(LOG_ERR, "JSON invalid previousblockhash"); applog( LOG_ERR, "JSON invalid previousblockhash" );
goto out; goto out;
} }
tmp = json_object_get(val, "curtime"); tmp = json_object_get( val, "curtime" );
if (!tmp || !json_is_integer(tmp)) { if ( !tmp || !json_is_integer( tmp ) )
applog(LOG_ERR, "JSON invalid curtime"); {
applog( LOG_ERR, "JSON invalid curtime" );
goto out; goto out;
} }
curtime = (uint32_t) json_integer_value(tmp); curtime = (uint32_t) json_integer_value(tmp);
if (unlikely(!jobj_binary(val, "bits", &bits, sizeof(bits)))) { if ( unlikely( !jobj_binary( val, "bits", &bits, sizeof(bits) ) ) )
{
applog(LOG_ERR, "JSON invalid bits"); applog(LOG_ERR, "JSON invalid bits");
goto out; goto out;
} }
/* find count and size of transactions */ /* find count and size of transactions */
txa = json_object_get(val, "transactions"); txa = json_object_get(val, "transactions" );
if (!txa || !json_is_array(txa)) { if ( !txa || !json_is_array( txa ) )
applog(LOG_ERR, "JSON invalid transactions"); {
applog( LOG_ERR, "JSON invalid transactions" );
goto out; goto out;
} }
tx_count = (int) json_array_size(txa); tx_count = (int) json_array_size( txa );
tx_size = 0; tx_size = 0;
for (i = 0; i < tx_count; i++) { 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")); const json_t *tx = json_array_get( txa, i );
if (!tx_hex) { const char *tx_hex = json_string_value( json_object_get( tx, "data" ) );
applog(LOG_ERR, "JSON invalid transactions"); if ( !tx_hex )
{
applog( LOG_ERR, "JSON invalid transactions" );
goto out; goto out;
} }
tx_size += (int) (strlen(tx_hex) / 2); tx_size += (int) ( strlen( tx_hex ) / 2 );
} }
/* build coinbase transaction */ /* build coinbase transaction */
tmp = json_object_get(val, "coinbasetxn"); tmp = json_object_get( val, "coinbasetxn" );
if (tmp) { if ( tmp )
const char *cbtx_hex = json_string_value(json_object_get(tmp, "data")); {
cbtx_size = cbtx_hex ? (int) strlen(cbtx_hex) / 2 : 0; const char *cbtx_hex = json_string_value( json_object_get( tmp, "data" ));
cbtx = (uchar*) malloc(cbtx_size + 100); cbtx_size = cbtx_hex ? (int) strlen( cbtx_hex ) / 2 : 0;
if (cbtx_size < 60 || !hex2bin(cbtx, cbtx_hex, cbtx_size)) { cbtx = (uchar*) malloc( cbtx_size + 100 );
applog(LOG_ERR, "JSON invalid coinbasetxn"); if ( cbtx_size < 60 || !hex2bin( cbtx, cbtx_hex, cbtx_size ) )
{
applog( LOG_ERR, "JSON invalid coinbasetxn" );
goto out; goto out;
} }
} else { }
else
{
int64_t cbvalue; int64_t cbvalue;
if (!pk_script_size) { if ( !pk_script_size )
if (allow_getwork) { {
applog(LOG_INFO, "No payout address provided, switching to getwork"); if ( allow_getwork )
{
applog( LOG_INFO, "No payout address provided, switching to getwork");
have_gbt = false; have_gbt = false;
} else }
applog(LOG_ERR, "No payout address provided"); else
applog( LOG_ERR, "No payout address provided" );
goto out; goto out;
} }
tmp = json_object_get(val, "coinbasevalue"); tmp = json_object_get( val, "coinbasevalue" );
if (!tmp || !json_is_number(tmp)) { if ( !tmp || !json_is_number( tmp ) )
applog(LOG_ERR, "JSON invalid coinbasevalue"); {
applog( LOG_ERR, "JSON invalid coinbasevalue" );
goto out; goto out;
} }
cbvalue = (int64_t) (json_is_integer(tmp) ? json_integer_value(tmp) : json_number_value(tmp)); cbvalue = (int64_t) ( json_is_integer( tmp ) ? json_integer_value( tmp )
: json_number_value( tmp ) );
cbtx = (uchar*) malloc(256); cbtx = (uchar*) malloc(256);
le32enc((uint32_t *)cbtx, 1); /* version */ le32enc( (uint32_t *)cbtx, 1 ); /* version */
cbtx[4] = 1; /* in-counter */ cbtx[4] = 1; /* in-counter */
memset(cbtx+5, 0x00, 32); /* prev txout hash */ memset( cbtx+5, 0x00, 32 ); /* prev txout hash */
le32enc((uint32_t *)(cbtx+37), 0xffffffff); /* prev txout index */ le32enc( (uint32_t *)(cbtx+37), 0xffffffff ); /* prev txout index */
cbtx_size = 43; cbtx_size = 43;
/* BIP 34: height in coinbase */ /* BIP 34: height in coinbase */
for (n = work->height; n; n >>= 8) for ( n = work->height; n; n >>= 8 )
cbtx[cbtx_size++] = n & 0xff; cbtx[cbtx_size++] = n & 0xff;
cbtx[42] = cbtx_size - 43; cbtx[42] = cbtx_size - 43;
cbtx[41] = cbtx_size - 42; /* scriptsig length */ cbtx[41] = cbtx_size - 42; /* scriptsig length */
le32enc((uint32_t *)(cbtx+cbtx_size), 0xffffffff); /* sequence */ le32enc( (uint32_t *)( cbtx+cbtx_size ), 0xffffffff ); /* sequence */
cbtx_size += 4; cbtx_size += 4;
cbtx[cbtx_size++] = 1; /* out-counter */ cbtx[ cbtx_size++ ] = 1; /* out-counter */
le32enc((uint32_t *)(cbtx+cbtx_size), (uint32_t)cbvalue); /* value */ le32enc( (uint32_t *)( cbtx+cbtx_size) , (uint32_t)cbvalue ); /* value */
le32enc((uint32_t *)(cbtx+cbtx_size+4), cbvalue >> 32); le32enc( (uint32_t *)( cbtx+cbtx_size+4 ), cbvalue >> 32 );
cbtx_size += 8; cbtx_size += 8;
cbtx[cbtx_size++] = (uint8_t) pk_script_size; /* txout-script length */ cbtx[ cbtx_size++ ] = (uint8_t) pk_script_size; /* txout-script length */
memcpy(cbtx+cbtx_size, pk_script, pk_script_size); memcpy( cbtx+cbtx_size, pk_script, pk_script_size );
cbtx_size += (int) pk_script_size; cbtx_size += (int) pk_script_size;
le32enc((uint32_t *)(cbtx+cbtx_size), 0); /* lock time */ le32enc( (uint32_t *)( cbtx+cbtx_size ), 0 ); /* lock time */
cbtx_size += 4; cbtx_size += 4;
coinbase_append = true; coinbase_append = true;
} }
if (coinbase_append) if ( coinbase_append )
{ {
unsigned char xsig[100]; unsigned char xsig[100];
int xsig_len = 0; int xsig_len = 0;
if (*coinbase_sig) { 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); n = (int) strlen( coinbase_sig );
while (iter) 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]; unsigned char buf[100];
const char *s = json_string_value(json_object_iter_value(iter)); const char *s = json_string_value( json_object_iter_value( iter ) );
n = s ? (int) (strlen(s) / 2) : 0; n = s ? (int) ( strlen(s) / 2 ) : 0;
if (!s || n > 100 || !hex2bin(buf, s, n)) { if ( !s || n > 100 || !hex2bin( buf, s, n ) )
{
applog(LOG_ERR, "JSON invalid coinbaseaux"); applog(LOG_ERR, "JSON invalid coinbaseaux");
break; break;
} }
if (cbtx[41] + xsig_len + n <= 100) { if ( cbtx[41] + xsig_len + n <= 100 )
memcpy(xsig+xsig_len, buf, n); {
memcpy( xsig+xsig_len, buf, n );
xsig_len += n; xsig_len += n;
} }
iter = json_object_iter_next(tmp, iter); iter = json_object_iter_next( tmp, iter );
} }
} }
if (xsig_len) if ( xsig_len )
{ {
unsigned char *ssig_end = cbtx + 42 + cbtx[41]; unsigned char *ssig_end = cbtx + 42 + cbtx[41];
int push_len = cbtx[41] + xsig_len < 76 ? 1 : int push_len = cbtx[41] + xsig_len < 76 ? 1 :
cbtx[41] + 2 + xsig_len > 100 ? 0 : 2; cbtx[41] + 2 + xsig_len > 100 ? 0 : 2;
n = xsig_len + push_len; n = xsig_len + push_len;
memmove(ssig_end + n, ssig_end, cbtx_size - 42 - cbtx[41]); memmove( ssig_end + n, ssig_end, cbtx_size - 42 - cbtx[41] );
cbtx[41] += n; cbtx[41] += n;
if (push_len == 2) if ( push_len == 2 )
*(ssig_end++) = 0x4c; /* OP_PUSHDATA1 */ *(ssig_end++) = 0x4c; /* OP_PUSHDATA1 */
if (push_len) if ( push_len )
*(ssig_end++) = xsig_len; *(ssig_end++) = xsig_len;
memcpy(ssig_end, xsig, xsig_len); memcpy( ssig_end, xsig, xsig_len );
cbtx_size += n; cbtx_size += n;
} }
} }
n = varint_encode(txc_vi, 1 + tx_count); n = varint_encode( txc_vi, 1 + tx_count );
work->txs = (char*) malloc(2 * (n + cbtx_size + tx_size) + 1); work->txs = (char*) malloc( 2 * ( n + cbtx_size + tx_size ) + 1 );
bin2hex(work->txs, txc_vi, n); bin2hex( work->txs, txc_vi, n );
bin2hex(work->txs + 2*n, cbtx, cbtx_size); bin2hex( work->txs + 2*n, cbtx, cbtx_size );
/* generate merkle root */ /* generate merkle root */
merkle_tree = (uchar(*)[32]) calloc(((1 + tx_count + 1) & ~1), 32); merkle_tree = (uchar(*)[32]) calloc(((1 + tx_count + 1) & ~1), 32);
sha256d(merkle_tree[0], cbtx, cbtx_size); sha256d(merkle_tree[0], cbtx, cbtx_size);
for (i = 0; i < tx_count; i++) for ( i = 0; i < tx_count; i++ )
{ {
tmp = json_array_get(txa, i); tmp = json_array_get( txa, i );
const char *tx_hex = json_string_value(json_object_get(tmp, "data")); const char *tx_hex = json_string_value( json_object_get( tmp, "data" ) );
const int tx_size = tx_hex ? (int) (strlen(tx_hex) / 2) : 0; const int tx_size = tx_hex ? (int) ( strlen( tx_hex ) / 2 ) : 0;
unsigned char *tx = (uchar*) malloc(tx_size); unsigned char *tx = (uchar*) malloc( tx_size );
if (!tx_hex || !hex2bin(tx, tx_hex, tx_size)) if ( !tx_hex || !hex2bin( tx, tx_hex, tx_size ) )
{ {
applog(LOG_ERR, "JSON invalid transactions"); applog( LOG_ERR, "JSON invalid transactions" );
free(tx); free( tx );
goto out; goto out;
} }
sha256d(merkle_tree[1 + i], tx, tx_size); sha256d( merkle_tree[1 + i], tx, tx_size );
if (!submit_coinbase) if ( !submit_coinbase )
strcat(work->txs, tx_hex); strcat( work->txs, tx_hex );
} }
n = 1 + tx_count; n = 1 + tx_count;
while (n > 1) while ( n > 1 )
{ {
if (n % 2) if ( n % 2 )
{ {
memcpy(merkle_tree[n], merkle_tree[n-1], 32); memcpy( merkle_tree[n], merkle_tree[n-1], 32 );
++n; ++n;
} }
n /= 2; n /= 2;
for (i = 0; i < n; i++) for ( i = 0; i < n; i++ )
sha256d(merkle_tree[i], merkle_tree[2*i], 64); sha256d( merkle_tree[i], merkle_tree[2*i], 64 );
} }
/* assemble block header */ /* assemble block header */
work->data[0] = swab32(version); algo_gate.build_block_header( work, swab32( version ),
for (i = 0; i < 8; i++) (uint32_t*) prevhash, (uint32_t*) merkle_tree,
work->data[8 - i] = le32dec(prevhash + i); swab32( curtime ), le32dec( &bits ) );
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)) ) ) if ( unlikely( !jobj_binary(val, "target", target, sizeof(target)) ) )
{ {
applog(LOG_ERR, "JSON invalid target"); applog( LOG_ERR, "JSON invalid target" );
goto out; goto out;
} }
for (i = 0; i < ARRAY_SIZE(work->target); i++) for ( i = 0; i < ARRAY_SIZE( work->target ); i++ )
work->target[7 - i] = be32dec(target + i); work->target[7 - i] = be32dec( target + i );
tmp = json_object_get(val, "workid"); tmp = json_object_get( val, "workid" );
if (tmp) if ( tmp )
{ {
if (!json_is_string(tmp)) { if ( !json_is_string( tmp ) )
applog(LOG_ERR, "JSON invalid workid"); {
applog( LOG_ERR, "JSON invalid workid" );
goto out; goto out;
} }
work->workid = strdup(json_string_value(tmp)); work->workid = strdup( json_string_value( tmp ) );
} }
rc = true; rc = true;
out: out:
/* Long polling */ /* Long polling */
tmp = json_object_get(val, "longpollid"); tmp = json_object_get( val, "longpollid" );
if (want_longpoll && json_is_string(tmp)) if ( want_longpoll && json_is_string( tmp ) )
{ {
free(lp_id); free( lp_id );
lp_id = strdup(json_string_value(tmp)); lp_id = strdup( json_string_value( tmp ) );
if (!have_longpoll) if ( !have_longpoll )
{ {
char *lp_uri; char *lp_uri;
tmp = json_object_get(val, "longpolluri"); tmp = json_object_get( val, "longpolluri" );
lp_uri = json_is_string(tmp) ? strdup(json_string_value(tmp)) : rpc_url; lp_uri = json_is_string( tmp ) ? strdup( json_string_value( tmp ) )
: rpc_url;
have_longpoll = true; have_longpoll = true;
tq_push(thr_info[longpoll_thr_id].q, lp_uri); tq_push(thr_info[longpoll_thr_id].q, lp_uri);
} }
} }
free(merkle_tree); free( merkle_tree );
free(cbtx); free( cbtx );
return rc; return rc;
} }
@@ -1050,12 +1072,42 @@ bool jr2_submit_getwork_result( CURL *curl, struct work *work )
return true; 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;
char req[JSON_BUF_LEN]; json_t *val;
char data_str[2 * sizeof(work->data) + 1];
int i; 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 */ /* pass if the previous hash is not the current previous hash */
if ( !submit_old && memcmp( &work->data[1], &g_work.data[1], 32 ) ) 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"); applog(LOG_DEBUG, "DEBUG: stale work detected, discarding");
return true; return true;
} }
if ( !have_stratum && allow_mininginfo ) if ( !have_stratum && allow_mininginfo )
{ {
struct work wheight; struct work wheight;
@@ -1074,8 +1127,10 @@ static bool submit_upstream_work( CURL *curl, struct work *work )
return true; return true;
} }
} }
if ( have_stratum ) if ( have_stratum )
{ {
char req[JSON_BUF_LEN];
stratum.sharediff = work->sharediff; stratum.sharediff = work->sharediff;
algo_gate.build_stratum_request( req, work, &stratum ); algo_gate.build_stratum_request( req, work, &stratum );
if ( unlikely( !stratum_send_line( &stratum, req ) ) ) if ( unlikely( !stratum_send_line( &stratum, req ) ) )
@@ -1085,71 +1140,49 @@ static bool submit_upstream_work( CURL *curl, struct work *work )
} }
return true; return true;
} }
else if (work->txs) else if ( work->txs )
{ {
char data_str[2 * sizeof(work->data) + 1]; char *req = NULL;
char *req; json_t *val, *res;
for (i = 0; i < ARRAY_SIZE(work->data); i++) req = algo_gate.malloc_txs_request( work );
be32enc(work->data + i, work->data[i]); val = json_rpc_call( curl, rpc_url, rpc_userpass, req, NULL, 0 );
bin2hex(data_str, (unsigned char *)work->data, 80); free( req );
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);
}
val = json_rpc_call(curl, rpc_url, rpc_userpass, req, NULL, 0); if ( unlikely( !val ) )
free(req);
if (unlikely(!val))
{ {
applog(LOG_ERR, "submit_upstream_work json_rpc_call failed"); applog( LOG_ERR, "submit_upstream_work json_rpc_call failed" );
return false; return false;
} }
res = json_object_get(val, "result"); res = json_object_get( val, "result" );
if (json_is_object(res)) if ( json_is_object( res ) )
{ {
char *res_str; char *res_str;
bool sumres = false; bool sumres = false;
void *iter = json_object_iter(res); void *iter = json_object_iter( res );
while (iter) while ( iter )
{ {
if (json_is_null(json_object_iter_value(iter))) if ( json_is_null( json_object_iter_value( iter ) ) )
{ {
sumres = true; sumres = true;
break; break;
} }
iter = json_object_iter_next(res, iter); iter = json_object_iter_next( res, iter );
} }
res_str = json_dumps(res, 0); res_str = json_dumps( res, 0 );
share_result(sumres, work, res_str); share_result( sumres, work, res_str );
free(res_str); free( res_str );
} }
else else
share_result(json_is_null(res), work, json_string_value(res)); share_result( json_is_null( res ), work, json_string_value( res ) );
json_decref(val); json_decref( val );
return true; return true;
} }
else else
return algo_gate.submit_getwork_result( curl, work ); return algo_gate.submit_getwork_result( curl, work );
} }
static const char *getwork_req = const char *getwork_req =
"{\"method\": \"getwork\", \"params\": [], \"id\":0}\r\n"; "{\"method\": \"getwork\", \"params\": [], \"id\":0}\r\n";
#define GBT_CAPABILITIES "[\"coinbasetxn\", \"coinbasevalue\", \"longpoll\", \"workid\"]" #define GBT_CAPABILITIES "[\"coinbasetxn\", \"coinbasevalue\", \"longpoll\", \"workid\"]"
@@ -1157,11 +1190,11 @@ static const char *getwork_req =
static const char *gbt_req = static const char *gbt_req =
"{\"method\": \"getblocktemplate\", \"params\": [{\"capabilities\": " "{\"method\": \"getblocktemplate\", \"params\": [{\"capabilities\": "
GBT_CAPABILITIES "}], \"id\":0}\r\n"; GBT_CAPABILITIES "}], \"id\":0}\r\n";
static const char *gbt_lp_req = const char *gbt_lp_req =
"{\"method\": \"getblocktemplate\", \"params\": [{\"capabilities\": " "{\"method\": \"getblocktemplate\", \"params\": [{\"capabilities\": "
GBT_CAPABILITIES ", \"longpollid\": \"%s\"}], \"id\":0}\r\n"; 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; json_t *val;
int err; int err;
@@ -1169,68 +1202,68 @@ static bool get_upstream_work(CURL *curl, struct work *work)
struct timeval tv_start, tv_end, diff; struct timeval tv_start, tv_end, diff;
start: start:
gettimeofday(&tv_start, NULL); gettimeofday( &tv_start, NULL );
if (jsonrpc_2) if ( jsonrpc_2 )
{ {
char s[128]; char s[128];
snprintf(s, 128, "{\"method\": \"getjob\", \"params\": {\"id\": \"%s\"}, \"id\":1}\r\n", rpc2_id); 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); val = json_rpc2_call( curl, rpc_url, rpc_userpass, s, NULL, 0 );
} }
else else
{ {
val = json_rpc_call(curl, rpc_url, rpc_userpass, val = json_rpc_call( curl, rpc_url, rpc_userpass,
have_gbt ? gbt_req : getwork_req, have_gbt ? gbt_req : getwork_req, &err,
&err, have_gbt ? JSON_RPC_QUIET_404 : 0); have_gbt ? JSON_RPC_QUIET_404 : 0);
} }
gettimeofday(&tv_end, NULL); gettimeofday( &tv_end, NULL );
if (have_stratum) if ( have_stratum )
{ {
if (val) if ( val )
json_decref(val); json_decref(val);
return true; return true;
} }
if (!have_gbt && !allow_getwork) if ( !have_gbt && !allow_getwork )
{ {
applog(LOG_ERR, "No usable protocol"); applog( LOG_ERR, "No usable protocol" );
if (val) if ( val )
json_decref(val); json_decref( val );
return false; return false;
} }
if (have_gbt && allow_getwork && !val && err == CURLE_OK) if ( have_gbt && allow_getwork && !val && err == CURLE_OK )
{ {
applog(LOG_NOTICE, "getblocktemplate failed, falling back to getwork"); applog( LOG_NOTICE, "getblocktemplate failed, falling back to getwork" );
have_gbt = false; have_gbt = false;
goto start; goto start;
} }
if (!val) if ( !val )
return false; return false;
if (have_gbt) if ( have_gbt )
{ {
rc = gbt_work_decode(json_object_get(val, "result"), work); rc = gbt_work_decode( json_object_get( val, "result" ), work );
if (!have_gbt) if ( !have_gbt )
{ {
json_decref(val); json_decref( val );
goto start; goto start;
} }
} }
else else
rc = work_decode(json_object_get(val, "result"), work); rc = work_decode( json_object_get( val, "result" ), work );
if (opt_protocol && rc) if ( opt_protocol && rc )
{ {
timeval_subtract(&diff, &tv_end, &tv_start); timeval_subtract( &diff, &tv_end, &tv_start );
applog(LOG_DEBUG, "got new work in %.2f ms", applog( LOG_DEBUG, "got new work in %.2f ms",
(1000.0 * diff.tv_sec) + (0.001 * diff.tv_usec)); ( 1000.0 * diff.tv_sec ) + ( 0.001 * diff.tv_usec ) );
} }
json_decref(val); json_decref( val );
// store work height in solo // store work height in solo
get_mininginfo(curl, work); get_mininginfo(curl, work);
return rc; return rc;
@@ -1881,65 +1914,59 @@ static void *miner_thread( void *userdata )
gettimeofday( (struct timeval *) &tv_start, NULL ); gettimeofday( (struct timeval *) &tv_start, NULL );
// Scan for nonce // Scan for nonce
nonce_found = (bool) algo_gate.scanhash( thr_id, &work, max_nonce, nonce_found = algo_gate.scanhash( thr_id, &work, max_nonce,
&hashes_done ); &hashes_done );
// record scanhash elapsed time // record scanhash elapsed time
gettimeofday(&tv_end, NULL); gettimeofday( &tv_end, NULL );
timeval_subtract(&diff, &tv_end, &tv_start); timeval_subtract( &diff, &tv_end, &tv_start );
if (diff.tv_usec || diff.tv_sec) if ( diff.tv_usec || diff.tv_sec )
{ {
pthread_mutex_lock(&stats_lock); pthread_mutex_lock( &stats_lock );
thr_hashcount[thr_id] = hashes_done; thr_hashcount[thr_id] = hashes_done;
thr_hashrates[thr_id] = thr_hashrates[thr_id] =
hashes_done / (diff.tv_sec + diff.tv_usec * 1e-6); hashes_done / ( diff.tv_sec + diff.tv_usec * 1e-6 );
pthread_mutex_unlock(&stats_lock); pthread_mutex_unlock( &stats_lock );
} }
// if nonce(s) submit work // if nonce(s) found submit work
if ( nonce_found && !opt_benchmark ) if ( nonce_found && !opt_benchmark )
{ { // 4 way with multiple nonces, copy individually to work and submit.
/* if ( nonce_found > 1 )
int num_submitted = 0;
for ( int n = 0; n < nonce_found; n++ ) for ( int n = 0; n < nonce_found; n++ )
{ {
*algo_gate.get_nonceptr( work.data ) = work.nonces[n]; *algo_gate.get_nonceptr( work.data ) = work.nonces[n];
if ( submit_work( mythr, &work ) ) if ( submit_work( mythr, &work ) )
{
applog( LOG_NOTICE, "Share submitted." ); applog( LOG_NOTICE, "Share submitted." );
num_submitted++;
}
else else
{ {
applog( LOG_WARNING, "Failed to submit share." ); applog( LOG_WARNING, "Failed to submit share." );
break; break;
} }
} }
// must be a one way algo, nonce is already in work data else
if ( !num_submitted ) { // only 1 nonce, in work ready to submit.
{
*/
if ( !submit_work( mythr, &work ) ) if ( !submit_work( mythr, &work ) )
{ {
applog( LOG_WARNING, "Failed to submit share." ); applog( LOG_WARNING, "Failed to submit share." );
break; break;
} }
applog( LOG_NOTICE, "Share submitted." ); applog( LOG_NOTICE, "Share submitted." );
// } }
// prevent stale work in solo // prevent stale work in solo
// we can't submit twice a block! // 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 // will force getwork
g_work_time = 0; g_work_time = 0;
pthread_mutex_unlock(&g_work_lock); pthread_mutex_unlock( &g_work_lock );
} }
} }
// display hashrate // display hashrate
if (!opt_quiet) if ( !opt_quiet )
{ {
char hc[16]; char hc[16];
char hr[16]; char hr[16];
@@ -2236,27 +2263,45 @@ out:
return ret; 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; int i;
algo_gate.gen_merkle_root( merkle_root, sctx ); 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[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 // Increment extranonce2
for ( t = 0; t < sctx->xnonce2_size && !( ++sctx->job.xnonce2[t] ); t++ ); for ( t = 0; t < sctx->xnonce2_size && !( ++sctx->job.xnonce2[t] ); t++ );
// Assemble block header // 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 );
for ( i = 0; i < 8; i++ )
g_work->data[9 + i] = be32dec( (uint32_t *) merkle_root + i );
g_work->data[ algo_gate.ntime_index ] = le32dec(sctx->job.ntime); algo_gate.build_block_header( g_work, le32dec( sctx->job.version ),
g_work->data[ algo_gate.nbits_index ] = le32dec(sctx->job.nbits); (uint32_t*) sctx->job.prevhash, (uint32_t*) merkle_tree,
g_work->data[20] = 0x80000000; le32dec( sctx->job.ntime ), le32dec(sctx->job.nbits) );
g_work->data[31] = 0x00000280;
} }
void std_stratum_gen_work( struct stratum_ctx *sctx, struct work *g_work ) void std_stratum_gen_work( struct stratum_ctx *sctx, struct work *g_work )

View File

@@ -648,6 +648,10 @@ extern int opt_timeout;
extern bool want_longpoll; extern bool want_longpoll;
extern bool have_longpoll; extern bool have_longpoll;
extern bool have_gbt; 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 allow_getwork;
extern bool want_stratum; extern bool want_stratum;
extern bool have_stratum; extern bool have_stratum;