diff --git a/sql/2017-11-segwit.sql b/sql/2017-11-segwit.sql new file mode 100644 index 0000000..3399cfa --- /dev/null +++ b/sql/2017-11-segwit.sql @@ -0,0 +1,7 @@ +-- Recent additions to add after db init (.gz) +-- mysql yaamp -p < file.sql + +ALTER TABLE `blocks` ADD `segwit` tinyint(1) UNSIGNED NOT NULL DEFAULT '0' AFTER `txhash`; + +ALTER TABLE `coins` ADD `usesegwit` tinyint(1) UNSIGNED NOT NULL DEFAULT '0' AFTER `usememorypool`; + diff --git a/stratum/client_submit.cpp b/stratum/client_submit.cpp index b3a04fa..993b726 100644 --- a/stratum/client_submit.cpp +++ b/stratum/client_submit.cpp @@ -205,7 +205,7 @@ static void client_do_submit(YAAMP_CLIENT *client, YAAMP_JOB *job, YAAMP_JOB_VAL debuglog("*** ACCEPTED %s %d (+1)\n", coind_aux->name, coind_aux->height); block_add(client->userid, client->workerid, coind_aux->id, coind_aux->height, target_to_diff(coin_target_aux), - target_to_diff(hash_int), coind_aux->aux.hash, ""); + target_to_diff(hash_int), coind_aux->aux.hash, "", 0); } else @@ -270,7 +270,7 @@ static void client_do_submit(YAAMP_CLIENT *client, YAAMP_JOB *job, YAAMP_JOB_VAL block_add(client->userid, client->workerid, coind->id, templ->height, target_to_diff(coin_target), target_to_diff(hash_int), - hash1, submitvalues->hash_be); + hash1, submitvalues->hash_be, templ->has_segwit_txs); if(coind->noblocknotify) { // DCR go wallet doesnt handle blocknotify= config (yet) diff --git a/stratum/coinbase.cpp b/stratum/coinbase.cpp index 4226fc9..b37bca8 100644 --- a/stratum/coinbase.cpp +++ b/stratum/coinbase.cpp @@ -66,6 +66,7 @@ void coinbase_create(YAAMP_COIND *coind, YAAMP_JOB_TEMPLATE *templ, json_value * { char eheight[32], etime[32]; char entime[32] = { 0 }; + char commitment[128] = { 0 }; ser_number(templ->height, eheight); ser_number(time(NULL), etime); @@ -90,6 +91,10 @@ void coinbase_create(YAAMP_COIND *coind, YAAMP_JOB_TEMPLATE *templ, json_value * sprintf(templ->coinb2, "%s00000000", script2); + // segwit commitment, if needed + if (templ->has_segwit_txs) + sprintf(commitment, "0000000000000000%02x%s", (int) (strlen(coind->commitment)/2), coind->commitment); + json_int_t available = templ->value; // sample coins using mandatory dev/foundation fees @@ -158,7 +163,12 @@ void coinbase_create(YAAMP_COIND *coind, YAAMP_JOB_TEMPLATE *templ, json_value * available -= charity_amount; coind->charity_amount = charity_amount; - strcat(templ->coinb2, "02"); + if (templ->has_segwit_txs) { + strcat(templ->coinb2, "03"); // 3 outputs (nulldata + fees + miner) + strcat(templ->coinb2, commitment); + } else { + strcat(templ->coinb2, "02"); + } job_pack_tx(coind, templ->coinb2, available, NULL); job_pack_tx(coind, templ->coinb2, charity_amount, script_payee); strcat(templ->coinb2, "00000000"); // locktime @@ -253,7 +263,7 @@ void coinbase_create(YAAMP_COIND *coind, YAAMP_JOB_TEMPLATE *templ, json_value * //debuglog("%s %d dests %s\n", coind->symbol, npayees, script_dests); return; } - + else if(strcmp(coind->symbol, "ARC") == 0) { char script_dests[2048] = { 0 }; @@ -296,7 +306,7 @@ void coinbase_create(YAAMP_COIND *coind, YAAMP_JOB_TEMPLATE *templ, json_value * //debuglog("%s %d dests %s\n", coind->symbol, npayees, script_dests); return; } - + else if(strcmp(coind->symbol, "ENT") == 0) { char script_dests[2048] = { 0 }; @@ -350,6 +360,7 @@ void coinbase_create(YAAMP_COIND *coind, YAAMP_JOB_TEMPLATE *templ, json_value * json_int_t charity_amount = json_get_int(json_result, "payee_amount"); bool charity_payments = json_get_bool(json_result, "masternode_payments"); bool charity_enforce = json_get_bool(json_result, "enforce_masternode_payments"); + if(strcmp(coind->symbol, "CRW") == 0) { char script_dests[2048] = { 0 }; @@ -390,29 +401,41 @@ void coinbase_create(YAAMP_COIND *coind, YAAMP_JOB_TEMPLATE *templ, json_value * //debuglog("%s %d dests %s\n", coind->symbol, npayees, script_dests); return; } + if(charity_payments && charity_enforce) { - available -= charity_amount; - - char script_payee[1024]; + char script_payee[256] = { 0 }; base58_decode(charity_payee, script_payee); - strcat(templ->coinb2, "02"); + if (templ->has_segwit_txs) { + strcat(templ->coinb2, "03"); // 3 outputs (nulldata + node + miner) + strcat(templ->coinb2, commitment); + } else { + strcat(templ->coinb2, "02"); // 2 outputs + } + job_pack_tx(coind, templ->coinb2, charity_amount, script_payee); - } - else + available -= charity_amount; + + } else { strcat(templ->coinb2, "01"); + } } - else + else if (templ->has_segwit_txs) { + strcat(templ->coinb2, "02"); + strcat(templ->coinb2, commitment); + } else { strcat(templ->coinb2, "01"); + } job_pack_tx(coind, templ->coinb2, available, NULL); - strcat(templ->coinb2, "00000000"); // locktime //if(coind->txmessage) // strcat(templ->coinb2, "00"); + strcat(templ->coinb2, "00000000"); // locktime + coind->reward = (double)available/100000000*coind->reward_mul; // debuglog("coinbase %f\n", coind->reward); diff --git a/stratum/coind.h b/stratum/coind.h index 166a0aa..aae8eb3 100644 --- a/stratum/coind.h +++ b/stratum/coind.h @@ -68,6 +68,10 @@ public: bool noblocknotify; bool multialgos; // pow_hash field (or mined_hash) + bool usesegwit; + char commitment[128]; + char witness_magic[16]; + YAAMP_JOB *job; // YAAMP_JOB_TEMPLATE *templ; }; diff --git a/stratum/coind_template.cpp b/stratum/coind_template.cpp index fea6d7f..82bd4f6 100644 --- a/stratum/coind_template.cpp +++ b/stratum/coind_template.cpp @@ -233,8 +233,9 @@ YAAMP_JOB_TEMPLATE *coind_create_template(YAAMP_COIND *coind) if(coind->usememorypool) return coind_create_template_memorypool(coind); - char params[4*1024] = "[{}]"; + char params[512] = "[{}]"; if(!strcmp(coind->symbol, "PPC")) strcpy(params, "[]"); + else if(g_stratum_segwit) strcpy(params, "[{\"rules\":[\"segwit\"]}]"); json_value *json = rpc_call(&coind->rpc, "getblocktemplate", params); if(!json || json_is_null(json)) @@ -255,6 +256,26 @@ YAAMP_JOB_TEMPLATE *coind_create_template(YAAMP_COIND *coind) return NULL; } + // segwit rule + json_value *json_rules = json_get_array(json_result, "rules"); + if(json_rules && !strlen(coind->witness_magic) && json_rules->u.array.length) { + for (int i=0; iu.array.length; i++) { + json_value *val = json_rules->u.array.values[i]; + if(!strcmp(val->u.string.ptr, "segwit")) { + const char *commitment = json_get_string(json_result, "default_witness_commitment"); + strcpy(coind->witness_magic, "aa21a9ed"); + if (commitment && strlen(commitment) > 12) { + strncpy(coind->witness_magic, &commitment[4], 8); + coind->witness_magic[8] = '\0'; + } + coind->usesegwit |= g_stratum_segwit; + if (coind->usesegwit) + debuglog("%s segwit enabled, magic %s\n", coind->symbol, coind->witness_magic); + break; + } + } + } + json_value *json_tx = json_get_array(json_result, "transactions"); if(!json_tx) { @@ -355,26 +376,78 @@ YAAMP_JOB_TEMPLATE *coind_create_template(YAAMP_COIND *coind) ////////////////////////////////////////////////////////////////////////////////////////// vector txhashes; + vector txids; txhashes.push_back(""); + txids.push_back(""); + templ->has_segwit_txs = false; + // to force/test + // templ->has_segwit_txs = coind->usesegwit = (coind->usesegwit || g_stratum_segwit); for(int i = 0; i < json_tx->u.array.length; i++) { const char *p = json_get_string(json_tx->u.array.values[i], "hash"); - - char hash_be[1024]; - memset(hash_be, 0, 1024); + char hash_be[256] = { 0 }; string_be(p, hash_be); - txhashes.push_back(hash_be); + const char *txid = json_get_string(json_tx->u.array.values[i], "txid"); + if(txid && strlen(txid)) { + char txid_be[256] = { 0 }; + string_be(txid, txid_be); + txids.push_back(txid_be); + if (strcmp(hash_be, txid_be)) { + //debuglog("%s segwit tx found, height %d\n", coind->symbol, templ->height); + templ->has_segwit_txs = true; // if not, its useless to generate a segwit block, bigger + } + } else { + templ->has_segwit_txs = false; // force disable if not supported (no txid fields) + } + const char *d = json_get_string(json_tx->u.array.values[i], "data"); templ->txdata.push_back(d); } - templ->txmerkles[0] = 0; - templ->txcount = txhashes.size(); - templ->txsteps = merkle_steps(txhashes); + templ->txmerkles[0] = '\0'; + if(templ->has_segwit_txs) { + templ->txcount = txids.size(); + templ->txsteps = merkle_steps(txids); + } else { + templ->txcount = txhashes.size(); + templ->txsteps = merkle_steps(txhashes); + } + + if(templ->has_segwit_txs) { + // * We compute the witness hash (which is the hash including witnesses) of all the block's transactions, except the + // coinbase (where 0x0000....0000 is used instead). + // * The coinbase scriptWitness is a stack of a single 32-byte vector, containing a witness nonce (unconstrained). + // * We build a merkle tree with all those witness hashes as leaves (similar to the hashMerkleRoot in the block header). + // * There must be at least one output whose scriptPubKey is a single 36-byte push, the first 4 bytes (magic) of which are + // {0xaa, 0x21, 0xa9, 0xed}, and the following 32 bytes are SHA256^2(witness root, witness nonce). In case there are + /* + char bin[YAAMP_HASHLEN_BIN*2]; + char witness[128] = { 0 }; + vector mt_verify = merkle_steps(txhashes); + string witness_mt = merkle_with_first(mt_verify, "0000000000000000000000000000000000000000000000000000000000000000"); + mt_verify.clear(); + witness_mt = witness_mt + "0000000000000000000000000000000000000000000000000000000000000000"; + + binlify((unsigned char *)bin, witness_mt.c_str()); + sha256_double_hash_hex(bin, witness, YAAMP_HASHLEN_BIN*2); + + int clen = (int) (strlen(coind->witness_magic) + strlen(witness)); // 4 + 32 = 36 = 0x24 + sprintf(coind->commitment, "6a%02x%s%s", clen/2, coind->witness_magic, witness); + */ + // default commitment is already computed correctly + const char *commitment = json_get_string(json_result, "default_witness_commitment"); + if (commitment) { + sprintf(coind->commitment, "%s", commitment); + } else { + templ->has_segwit_txs = false; + } + } + txhashes.clear(); + txids.clear(); vector::const_iterator i; for(i = templ->txsteps.begin(); i != templ->txsteps.end(); ++i) diff --git a/stratum/db.cpp b/stratum/db.cpp index 8be7e6b..1737ed7 100644 --- a/stratum/db.cpp +++ b/stratum/db.cpp @@ -158,7 +158,7 @@ void db_update_coinds(YAAMP_DB *db) db_query(db, "SELECT id, name, rpchost, rpcport, rpcuser, rpcpasswd, rpcencoding, master_wallet, reward, price, " "hassubmitblock, txmessage, enable, auto_ready, algo, pool_ttf, charity_address, charity_amount, charity_percent, " "reward_mul, symbol, auxpow, actual_ttf, network_ttf, usememorypool, hasmasternodes, algo, symbol2, " - "rpccurl, rpcssl, rpccert, account, multialgos, max_miners, max_shares " + "rpccurl, rpcssl, rpccert, account, multialgos, max_miners, max_shares, usesegwit " "FROM coins WHERE enable AND auto_ready AND algo='%s' ORDER BY index_avg", g_stratum_algo); MYSQL_RES *result = mysql_store_result(&db->mysql); @@ -258,6 +258,9 @@ void db_update_coinds(YAAMP_DB *db) if(row[32]) coind->multialgos = atoi(row[32]); if(row[33] && atoi(row[33]) > 0) g_stratum_max_cons = atoi(row[33]); if(row[34] && atol(row[34]) > 0) g_max_shares = atol(row[34]); + if(row[35]) coind->usesegwit = atoi(row[35]) > 0; + + if(coind->usesegwit) g_stratum_segwit = true; // force the right rpcencoding for DCR if(!strcmp(coind->symbol, "DCR") && strcmp(coind->rpcencoding, "DCR")) diff --git a/stratum/job.h b/stratum/job.h index 00d97a2..f876fd7 100644 --- a/stratum/job.h +++ b/stratum/job.h @@ -50,6 +50,8 @@ struct YAAMP_JOB_TEMPLATE char header[256]; + bool has_segwit_txs; + int auxs_size; YAAMP_COIND_AUX *auxs[MAX_AUXS]; }; diff --git a/stratum/share.cpp b/stratum/share.cpp index 07164b7..c7106da 100644 --- a/stratum/share.cpp +++ b/stratum/share.cpp @@ -180,7 +180,7 @@ void share_prune(YAAMP_DB *db) void block_prune(YAAMP_DB *db) { int count = 0; - char buffer[128*1024] = "insert into blocks (height, blockhash, coin_id, userid, workerid, category, difficulty, difficulty_user, time, algo) values "; + char buffer[128*1024] = "insert into blocks (height, blockhash, coin_id, userid, workerid, category, difficulty, difficulty_user, time, algo, segwit) values "; g_list_block.Enter(); for(CLI li = g_list_block.first; li; li = li->next) @@ -199,9 +199,9 @@ void block_prune(YAAMP_DB *db) } if(count) strcat(buffer, ","); - sprintf(buffer+strlen(buffer), "(%d, '%s', %d, %d, %d, 'new', %f, %f, %d, '%s')", + sprintf(buffer+strlen(buffer), "(%d, '%s', %d, %d, %d, 'new', %f, %f, %d, '%s', %d)", block->height, block->hash, block->coinid, block->userid, block->workerid, - block->difficulty, block->difficulty_user, (int)block->created, g_stratum_algo); + block->difficulty, block->difficulty_user, (int)block->created, g_stratum_algo, block->segwit?1:0); object_delete(block); count++; @@ -211,7 +211,7 @@ void block_prune(YAAMP_DB *db) if(count) db_query(db, buffer); } -void block_add(int userid, int workerid, int coinid, int height, double difficulty, double difficulty_user, const char *hash1, const char *hash2) +void block_add(int userid, int workerid, int coinid, int height, double diff, double diff_user, const char *h1, const char *h2, int segwit) { YAAMP_BLOCK *block = new YAAMP_BLOCK; memset(block, 0, sizeof(YAAMP_BLOCK)); @@ -221,11 +221,12 @@ void block_add(int userid, int workerid, int coinid, int height, double difficul block->workerid = workerid; block->coinid = coinid; block->height = height; - block->difficulty = difficulty; - block->difficulty_user = difficulty_user; + block->difficulty = diff; + block->difficulty_user = diff_user; + block->segwit = segwit; - strcpy(block->hash1, hash1); - strcpy(block->hash2, hash2); + strcpy(block->hash1, h1); + strcpy(block->hash2, h2); g_list_block.AddTail(block); } diff --git a/stratum/share.h b/stratum/share.h index 184448d..1decef9 100644 --- a/stratum/share.h +++ b/stratum/share.h @@ -9,7 +9,7 @@ public: bool valid; bool extranonce1; - int error_number; + int32_t error_number; uint32_t ntime; double difficulty; @@ -56,8 +56,9 @@ void share_prune(YAAMP_DB *db); class YAAMP_BLOCK: public YAAMP_OBJECT { public: - int created; + time_t created; bool confirmed; + bool segwit; int userid; int workerid; @@ -83,7 +84,7 @@ inline void block_delete(YAAMP_OBJECT *object) class YAAMP_SUBMIT: public YAAMP_OBJECT { public: - int created; + time_t created; bool valid; int remoteid; @@ -98,7 +99,7 @@ inline void submit_delete(YAAMP_OBJECT *object) void block_prune(YAAMP_DB *db); -void block_add(int userid, int workerid, int coinid, int height, double difficulty, double difficulty_user, const char *hash1, const char *hash2); +void block_add(int userid, int workerid, int coinid, int height, double diff, double diff_user, const char *hash1, const char *h2, int segwit); void block_confirm(int coinid, const char *hash); YAAMP_SUBMIT *submit_add(int remoteid, double difficulty); diff --git a/stratum/stratum.cpp b/stratum/stratum.cpp index 77afcbc..e8330f0 100644 --- a/stratum/stratum.cpp +++ b/stratum/stratum.cpp @@ -31,6 +31,7 @@ int g_stratum_max_ttf; int g_stratum_max_cons = 5000; bool g_stratum_reconnect; bool g_stratum_renting; +bool g_stratum_segwit; bool g_autoexchange = true; uint64_t g_max_shares = 0; @@ -221,6 +222,7 @@ int main(int argc, char **argv) g_stratum_max_ttf = iniparser_getint(ini, "STRATUM:max_ttf", 0x70000000); g_stratum_reconnect = iniparser_getint(ini, "STRATUM:reconnect", true); g_stratum_renting = iniparser_getint(ini, "STRATUM:renting", true); + g_stratum_segwit = iniparser_getint(ini, "STRATUM:segwit", 0); iniparser_freedict(ini); diff --git a/stratum/stratum.h b/stratum/stratum.h index aacec49..e02dbc8 100644 --- a/stratum/stratum.h +++ b/stratum/stratum.h @@ -82,6 +82,7 @@ extern int g_stratum_max_cons; extern int g_stratum_max_ttf; extern bool g_stratum_reconnect; extern bool g_stratum_renting; +extern bool g_stratum_segwit; extern uint64_t g_max_shares; extern uint64_t g_shares_counter; diff --git a/web/images/ui/segwit.png b/web/images/ui/segwit.png new file mode 100644 index 0000000..5ec7f28 Binary files /dev/null and b/web/images/ui/segwit.png differ diff --git a/web/yaamp/models/db_coinsModel.php b/web/yaamp/models/db_coinsModel.php index 5be9037..3446eb1 100644 --- a/web/yaamp/models/db_coinsModel.php +++ b/web/yaamp/models/db_coinsModel.php @@ -49,6 +49,7 @@ class db_coins extends CActiveRecord 'serveruser' => 'Server user', 'hassubmitblock'=> 'Has submitblock', 'hasmasternodes'=> 'Masternodes', + 'usesegwit' => 'Use segwit', 'market' => 'Preferred market', 'rpcencoding' => 'RPC Type', 'specifications'=> 'Notes' diff --git a/web/yaamp/modules/site/block_results.php b/web/yaamp/modules/site/block_results.php index 5dd5f94..fe21454 100644 --- a/web/yaamp/modules/site/block_results.php +++ b/web/yaamp/modules/site/block_results.php @@ -3,11 +3,9 @@ JavascriptFile("/yaamp/ui/js/jquery.metadata.js"); JavascriptFile("/yaamp/ui/js/jquery.tablesorter.widgets.js"); -$id = getiparam('id'); -if($id) - $db_blocks = getdbolist('db_blocks', "coin_id=:id order by time desc limit 250", array(':id'=>$id)); -else - $db_blocks = getdbolist('db_blocks', "1 order by time desc limit 250"); +$id = (int) getiparam('id'); +$db_blocks = getdbolist('db_blocks', "coin_id=:id order by time desc limit 250", array(':id'=>$id)); +$coin = getdbo('db_coins', $id); showTableSorter('maintable', "{ tableClass: 'dataGrid', @@ -54,7 +52,6 @@ foreach($db_blocks as $db_block) { if(!$db_block->coin_id) continue; - $coin = getdbo('db_coins', $db_block->coin_id); if(!$coin) continue; if($db_block->category == 'stake' && !$this->admin) continue; @@ -74,12 +71,14 @@ foreach($db_blocks as $db_block) echo ''; + $flags = $db_block->segwit ? ' ' : ''; + echo ''; if ($this->admin) echo ''.$coin->name.''; else echo ''.$coin->name.''; - echo ' ('.$coin->symbol.')'; + echo ' ('.$coin->symbol.')'.$flags.''; // $db_block->confirmations = $blockext['confirmations']; // $db_block->save(); @@ -133,11 +132,3 @@ foreach($db_blocks as $db_block) echo ""; - - - - - - - - diff --git a/web/yaamp/modules/site/coin_form.php b/web/yaamp/modules/site/coin_form.php index 92be012..af67481 100644 --- a/web/yaamp/modules/site/coin_form.php +++ b/web/yaamp/modules/site/coin_form.php @@ -219,6 +219,12 @@ echo CUFHtml::activeCheckBox($coin, 'hasmasternodes'); echo '

Require "payee" and "payee_amount" fields in getblocktemplate (DASH)

'; echo CUFHtml::closeCtrlHolder(); +echo CUFHtml::openActiveCtrlHolder($coin, 'usesegwit'); +echo CUFHtml::activeLabelEx($coin, 'usesegwit'); +echo CUFHtml::activeCheckBox($coin, 'usesegwit'); +echo '

'; +echo CUFHtml::closeCtrlHolder(); + echo ""; ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/web/yaamp/modules/site/common_results.php b/web/yaamp/modules/site/common_results.php index b9311ec..056f4a6 100644 --- a/web/yaamp/modules/site/common_results.php +++ b/web/yaamp/modules/site/common_results.php @@ -615,7 +615,8 @@ foreach($db_blocks as $db_block) $algo_color = getAlgoColors($coin->algo); echo ''; echo ''; - echo ''.$coin->name.''; + $flags = $db_block->segwit ? ' ' : ''; + echo ''.$coin->name.''.$flags.''; echo ''.$db_block->amount.' '.$coin->symbol.''; echo ''.$diff.''; diff --git a/web/yaamp/modules/site/results/found_results.php b/web/yaamp/modules/site/results/found_results.php index ed2741b..c181093 100644 --- a/web/yaamp/modules/site/results/found_results.php +++ b/web/yaamp/modules/site/results/found_results.php @@ -35,6 +35,9 @@ span.block.new { color: white; background-color: #ad4ef0; } span.block.orphan { color: white; background-color: #d9534f; } span.block.immature { color: white; background-color: #f0ad4e; } span.block.confirmed { color: white; background-color: #5cb85c; } +b.row a { font-size: 10pt; } +.ssrow td.row { font-size: .8em; } +td.right { text-align: right; } @@ -61,17 +64,17 @@ foreach($db_blocks as $db_block) $reward = bitcoinvaluetoa($db_block->amount); - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; continue; } @@ -83,14 +86,16 @@ foreach($db_blocks as $db_block) $link = $coin->createExplorerLink($coin->name, array('hash'=>$db_block->blockhash)); + $flags = $db_block->segwit ? ' ' : ''; + echo ''; - echo ''; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo "'; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo '
Rental ($db_block->algo)$reward BTC$d ago"; - echo "Confirmed"; - echo "
Rental ('.$db_block->algo.')'.$reward.' BTC'.$d.' ago'; + echo 'Confirmed'; + echo '
$link ($coin->algo)$reward $coin->symbol_show$difficulty$height$d ago"; + echo ''.$link.' ('.$coin->algo.')'.$flags.''.$reward.' '.$coin->symbol_show.''.$difficulty.''.$height.''.$d.' ago'; if($db_block->category == 'orphan') echo 'Orphan';