mirror of
https://github.com/LBRYFoundation/pool.git
synced 2025-08-23 09:27:25 +00:00
commit c59abe5d203fabdabcca81ff5f9c6ff133cfae3b Author: Tanguy Pruvot <tanguy.pruvot@gmail.com> Date: Tue Nov 28 11:13:52 2017 +0100 segwit: show a segwit icon on blocks history + remove some inline styles... commit b4a8639370e6837ebc5a2047e7c334e9f931abfc Author: Tanguy Pruvot <tanguy.pruvot@gmail.com> Date: Tue Nov 28 09:55:40 2017 +0100 segwit: cleanup + masternode case tested ok with BSD (block 400996), and with real BTX segwit txs (block 90958) also ok on VTC and GRS commit 926dbd11757ebff7f7d4930266de9b9061c8ab16 Author: Tanguy Pruvot <tanguy.pruvot@gmail.com> Date: Sat Nov 25 18:41:01 2017 +0100 sql: add segwit fields, and ui config and fill block segwit field if it contains segwit txs, an icon is added in the dashboard "last blocks" for these blocks commit 0b13bf55e9dd1d2229d188f0f8382b27642b20da Author: Tanguy Pruvot <tanguy.pruvot@gmail.com> Date: Sat Nov 25 13:47:20 2017 +0100 segwit: include commitment in coinbase + .conf toggle tested ok on BTX, GRS and VTC with normal txs, but the commitment merkle hash maybe need some more love... so, to prevent useless bigger blocks, only generate segwit commitment if a segwit tx is present in mempool to check with real segwit txs... not seen any yet.. commit b508bc87943d9e426cda994c2f53c16c11e8d4c3 Author: Tanguy Pruvot <tanguy.pruvot@gmail.com> Date: Thu Mar 2 11:18:34 2017 +0100 segwit: prepare the witness data, but disabled need more test, may affect the coinbase merkle and the miners... commit 19bd3a83b9ddddd8b5ed4b7a1bdf8cf8c233e346 Author: Tanguy Pruvot <tanguy.pruvot@gmail.com> Date: Thu Mar 2 10:30:29 2017 +0100 stratum: handle and auto toggle segwit if supported
448 lines
16 KiB
C++
448 lines
16 KiB
C++
|
|
// http://www.righto.com/2014/02/bitcoin-mining-hard-way-algorithms.html
|
|
|
|
// https://en.bitcoin.it/wiki/Merged_mining_specification#Merged_mining_coinbase
|
|
|
|
#include "stratum.h"
|
|
|
|
#define TX_VALUE(v, s) ((unsigned int)(v>>s)&0xff)
|
|
|
|
static void encode_tx_value(char *encoded, json_int_t value)
|
|
{
|
|
sprintf(encoded, "%02x%02x%02x%02x%02x%02x%02x%02x",
|
|
TX_VALUE(value, 0), TX_VALUE(value, 8), TX_VALUE(value, 16), TX_VALUE(value, 24),
|
|
TX_VALUE(value, 32), TX_VALUE(value, 40), TX_VALUE(value, 48), TX_VALUE(value, 56));
|
|
}
|
|
|
|
static void job_pack_tx(YAAMP_COIND *coind, char *data, json_int_t amount, char *key)
|
|
{
|
|
int ol = strlen(data);
|
|
char evalue[32];
|
|
encode_tx_value(evalue, amount);
|
|
|
|
sprintf(data+strlen(data), "%s", evalue);
|
|
|
|
if(coind->pos && !key)
|
|
sprintf(data+strlen(data), "2321%sac", coind->pubkey);
|
|
|
|
else
|
|
sprintf(data+strlen(data), "1976a914%s88ac", key? key: coind->script_pubkey);
|
|
|
|
// debuglog("pack tx %s\n", data+ol);
|
|
// debuglog("pack tx %lld\n", amount);
|
|
}
|
|
|
|
void coinbase_aux(YAAMP_JOB_TEMPLATE *templ, char *aux_script)
|
|
{
|
|
vector<string> hashlist = coind_aux_hashlist(templ->auxs, templ->auxs_size);
|
|
while(hashlist.size() > 1)
|
|
{
|
|
vector<string> l;
|
|
for(int i = 0; i < hashlist.size()/2; i++)
|
|
{
|
|
string s = hashlist[i*2] + hashlist[i*2+1];
|
|
|
|
char bin[YAAMP_HASHLEN_BIN*2];
|
|
char out[YAAMP_HASHLEN_STR];
|
|
|
|
binlify((unsigned char *)bin, s.c_str());
|
|
sha256_double_hash_hex(bin, out, YAAMP_HASHLEN_BIN*2);
|
|
|
|
l.push_back(out);
|
|
}
|
|
|
|
hashlist = l;
|
|
}
|
|
|
|
char merkle_hash[4*1024];
|
|
memset(merkle_hash, 0, 4*1024);
|
|
string_be(hashlist[0].c_str(), merkle_hash);
|
|
|
|
sprintf(aux_script+strlen(aux_script), "fabe6d6d%s%02x00000000000000", merkle_hash, templ->auxs_size);
|
|
// debuglog("aux_script is %s\n", aux_script);
|
|
}
|
|
|
|
void coinbase_create(YAAMP_COIND *coind, YAAMP_JOB_TEMPLATE *templ, json_value *json_result)
|
|
{
|
|
char eheight[32], etime[32];
|
|
char entime[32] = { 0 };
|
|
char commitment[128] = { 0 };
|
|
|
|
ser_number(templ->height, eheight);
|
|
ser_number(time(NULL), etime);
|
|
if(coind->pos) ser_string_be(templ->ntime, entime, 1);
|
|
|
|
char eversion1[32] = "01000000";
|
|
if(coind->txmessage)
|
|
strcpy(eversion1, "02000000");
|
|
|
|
char script1[4*1024];
|
|
sprintf(script1, "%s%s%s08", eheight, templ->flags, etime);
|
|
|
|
char script2[32] = "7969696d7000"; // "yiimp\0" in hex ascii
|
|
|
|
if(!coind->pos && !coind->isaux && templ->auxs_size)
|
|
coinbase_aux(templ, script2);
|
|
|
|
int script_len = strlen(script1)/2 + strlen(script2)/2 + 8;
|
|
sprintf(templ->coinb1, "%s%s01"
|
|
"0000000000000000000000000000000000000000000000000000000000000000"
|
|
"ffffffff%02x%s", eversion1, entime, script_len, script1);
|
|
|
|
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
|
|
if(strcmp(coind->symbol, "EGC") == 0) {
|
|
if (coind->charity_percent <= 0)
|
|
coind->charity_percent = 2;
|
|
if (strlen(coind->charity_address) == 0)
|
|
sprintf(coind->charity_address, "EdFwYw4Mo2Zq6CFM2yNJgXvE2DTJxgdBRX");
|
|
}
|
|
else if(strcmp(coind->symbol, "LTCR") == 0) {
|
|
if (coind->charity_percent <= 0)
|
|
coind->charity_percent = 10;
|
|
if (strlen(coind->charity_address) == 0)
|
|
sprintf(coind->charity_address, "BCDrF1hWdKTmrjXXVFTezPjKBmGigmaXg5");
|
|
}
|
|
else if(strcmp(coind->symbol, "XZC") == 0) {
|
|
char script_payee[1024];
|
|
if (coind->charity_percent <= 0)
|
|
coind->charity_percent = 25; // wrong coinbase 40 instead of 40 + 10 = 50
|
|
|
|
json_int_t charity_amount = (available * coind->charity_percent) / 100;
|
|
|
|
if (strlen(coind->charity_address) == 0)
|
|
sprintf(coind->charity_address, "aHu897ivzmeFuLNB6956X6gyGeVNHUBRgD");
|
|
|
|
strcat(templ->coinb2, "06");
|
|
job_pack_tx(coind, templ->coinb2, available, NULL);
|
|
base58_decode("aCAgTPgtYcA4EysU4UKC86EQd5cTtHtCcr", script_payee);
|
|
job_pack_tx(coind, templ->coinb2, charity_amount/5, script_payee);
|
|
base58_decode(coind->charity_address, script_payee); // may change
|
|
job_pack_tx(coind, templ->coinb2, charity_amount/5, script_payee);
|
|
base58_decode("aQ18FBVFtnueucZKeVg4srhmzbpAeb1KoN", script_payee);
|
|
job_pack_tx(coind, templ->coinb2, charity_amount/5, script_payee);
|
|
base58_decode("a1HwTdCmQV3NspP2QqCGpehoFpi8NY4Zg3", script_payee);
|
|
job_pack_tx(coind, templ->coinb2, charity_amount/5, script_payee);
|
|
base58_decode("a1kCCGddf5pMXSipLVD9hBG2MGGVNaJ15U", script_payee);
|
|
job_pack_tx(coind, templ->coinb2, charity_amount/5, script_payee);
|
|
strcat(templ->coinb2, "00000000"); // locktime
|
|
|
|
coind->reward = (double)available/100000000*coind->reward_mul;
|
|
return;
|
|
}
|
|
else if(strcmp("DCR", coind->rpcencoding) == 0) {
|
|
coind->reward_mul = 6; // coinbase value is wrong, reward_mul should be 6
|
|
coind->charity_percent = 0;
|
|
coind->charity_amount = available;
|
|
available *= coind->reward_mul;
|
|
if (strlen(coind->charity_address) == 0 && !strcmp(coind->symbol, "DCR"))
|
|
sprintf(coind->charity_address, "Dcur2mcGjmENx4DhNqDctW5wJCVyT3Qeqkx");
|
|
}
|
|
|
|
// 2 txs are required on these coins, one for foundation (dev fees)
|
|
if(coind->charity_percent)
|
|
{
|
|
char script_payee[1024];
|
|
char charity_payee[256] = { 0 };
|
|
const char *payee = json_get_string(json_result, "payee");
|
|
if (payee) snprintf(charity_payee, 255, "%s", payee);
|
|
else sprintf(charity_payee, "%s", coind->charity_address);
|
|
if (strlen(charity_payee) == 0)
|
|
stratumlog("ERROR %s has no charity_address set!\n", coind->name);
|
|
|
|
base58_decode(charity_payee, script_payee);
|
|
|
|
json_int_t charity_amount = (available * coind->charity_percent) / 100;
|
|
available -= charity_amount;
|
|
coind->charity_amount = charity_amount;
|
|
|
|
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
|
|
|
|
coind->reward = (double)available/100000000*coind->reward_mul;
|
|
return;
|
|
}
|
|
|
|
else if(coind->charity_amount && !strcmp("DCR", coind->rpcencoding))
|
|
{
|
|
stratumlog("ERROR %s should not use coinbase (getwork only)!\n", coind->symbol);
|
|
coind->reward = (double)available/100000000;
|
|
return;
|
|
}
|
|
|
|
if(strcmp(coind->symbol, "XVC") == 0)
|
|
{
|
|
char charity_payee[256];
|
|
json_value* incentive = json_get_object(json_result, "incentive");
|
|
if (incentive) {
|
|
const char* payee = json_get_string(incentive, "address");
|
|
if (payee) snprintf(charity_payee, 255, "%s", payee);
|
|
else sprintf(charity_payee, "%s", coind->charity_address);
|
|
|
|
bool enforced = json_get_bool(incentive, "enforced");
|
|
json_int_t charity_amount = json_get_int(incentive, "amount");
|
|
if (enforced && charity_amount && strlen(charity_payee)) {
|
|
char script_payee[1024];
|
|
base58_decode(charity_payee, script_payee);
|
|
|
|
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
|
|
|
|
coind->charity_amount = charity_amount;
|
|
coind->reward = (double)available/100000000*coind->reward_mul;
|
|
//debuglog("XVC coinbase %ld (+%ld incentive to %s)\n",
|
|
// (long) available, (long) charity_amount, charity_payee);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(strcmp(coind->symbol, "SIB") == 0 ||
|
|
strcmp(coind->symbol, "MUE") == 0 || // MUEcore-x11
|
|
strcmp(coind->symbol, "VIVO") == 0 || // VIVO coin
|
|
strcmp(coind->symbol, "INN") == 0 || // Innova coin
|
|
strcmp(coind->symbol, "DSR") == 0 || // Desire coin
|
|
strcmp(coind->symbol, "ONEX") == 0 || // ONEX Cash
|
|
strcmp(coind->symbol, "GBX") == 0 || // GoByte
|
|
strcmp(coind->symbol, "KZC") == 0 || // KZ Cash
|
|
strcmp(coind->symbol, "DASH") == 0 || strcmp(coind->symbol, "DASH-TESTNET") == 0) // Dash 12.1
|
|
{
|
|
char script_dests[2048] = { 0 };
|
|
char script_payee[128] = { 0 };
|
|
char payees[4]; // addresses count
|
|
int npayees = 1;
|
|
bool masternode_enabled = json_get_bool(json_result, "masternode_payments_enforced");
|
|
bool superblocks_enabled = json_get_bool(json_result, "superblocks_enabled");
|
|
json_value* superblock = json_get_array(json_result, "superblock");
|
|
json_value* masternode = json_get_object(json_result, "masternode");
|
|
if(superblocks_enabled && superblock) {
|
|
for(int i = 0; i < superblock->u.array.length; i++) {
|
|
const char *payee = json_get_string(superblock->u.array.values[i], "payee");
|
|
json_int_t amount = json_get_int(superblock->u.array.values[i], "amount");
|
|
if (payee && amount) {
|
|
npayees++;
|
|
available -= amount;
|
|
base58_decode(payee, script_payee);
|
|
job_pack_tx(coind, script_dests, amount, script_payee);
|
|
//debuglog("%s superblock %s %u\n", coind->symbol, payee, amount);
|
|
}
|
|
}
|
|
}
|
|
if (masternode_enabled && masternode) {
|
|
const char *payee = json_get_string(masternode, "payee");
|
|
json_int_t amount = json_get_int(masternode, "amount");
|
|
if (payee && amount) {
|
|
npayees++;
|
|
available -= amount;
|
|
base58_decode(payee, script_payee);
|
|
job_pack_tx(coind, script_dests, amount, script_payee);
|
|
}
|
|
}
|
|
sprintf(payees, "%02x", npayees);
|
|
strcat(templ->coinb2, payees);
|
|
strcat(templ->coinb2, script_dests);
|
|
job_pack_tx(coind, templ->coinb2, available, NULL);
|
|
strcat(templ->coinb2, "00000000"); // locktime
|
|
coind->reward = (double)available/100000000*coind->reward_mul;
|
|
//debuglog("%s %d dests %s\n", coind->symbol, npayees, script_dests);
|
|
return;
|
|
}
|
|
|
|
else if(strcmp(coind->symbol, "ARC") == 0)
|
|
{
|
|
char script_dests[2048] = { 0 };
|
|
char script_payee[128] = { 0 };
|
|
char payees[4];
|
|
int npayees = 1;
|
|
bool masternode_enabled = json_get_bool(json_result, "goldminenode_payments_enforced");
|
|
bool superblocks_enabled = json_get_bool(json_result, "superblocks_enabled");
|
|
json_value* superblock = json_get_array(json_result, "superblock");
|
|
json_value* masternode = json_get_object(json_result, "goldminenode");
|
|
if(superblocks_enabled && superblock) {
|
|
for(int i = 0; i < superblock->u.array.length; i++) {
|
|
const char *payee = json_get_string(superblock->u.array.values[i], "payee");
|
|
json_int_t amount = json_get_int(superblock->u.array.values[i], "amount");
|
|
if (payee && amount) {
|
|
npayees++;
|
|
available -= amount;
|
|
base58_decode(payee, script_payee);
|
|
job_pack_tx(coind, script_dests, amount, script_payee);
|
|
//debuglog("%s superblock %s %u\n", coind->symbol, payee, amount);
|
|
}
|
|
}
|
|
}
|
|
if (masternode_enabled && masternode) {
|
|
const char *payee = json_get_string(masternode, "payee");
|
|
json_int_t amount = json_get_int(masternode, "amount");
|
|
if (payee && amount) {
|
|
npayees++;
|
|
available -= amount;
|
|
base58_decode(payee, script_payee);
|
|
job_pack_tx(coind, script_dests, amount, script_payee);
|
|
}
|
|
}
|
|
sprintf(payees, "%02x", npayees);
|
|
strcat(templ->coinb2, payees);
|
|
strcat(templ->coinb2, script_dests);
|
|
job_pack_tx(coind, templ->coinb2, available, NULL);
|
|
strcat(templ->coinb2, "00000000"); // locktime
|
|
coind->reward = (double)available/100000000*coind->reward_mul;
|
|
//debuglog("%s %d dests %s\n", coind->symbol, npayees, script_dests);
|
|
return;
|
|
}
|
|
|
|
else if(strcmp(coind->symbol, "ENT") == 0)
|
|
{
|
|
char script_dests[2048] = { 0 };
|
|
char script_payee[128] = { 0 };
|
|
char payees[4];
|
|
int npayees = 1;
|
|
bool masternode_enabled = json_get_bool(json_result, "eternitynode_payments_enforced");
|
|
bool superblocks_enabled = json_get_bool(json_result, "superblocks_enabled");
|
|
json_value* superblock = json_get_array(json_result, "superblock");
|
|
json_value* masternode = json_get_object(json_result, "eternitynode");
|
|
if(superblocks_enabled && superblock) {
|
|
for(int i = 0; i < superblock->u.array.length; i++) {
|
|
const char *payee = json_get_string(superblock->u.array.values[i], "payee");
|
|
json_int_t amount = json_get_int(superblock->u.array.values[i], "amount");
|
|
if (payee && amount) {
|
|
npayees++;
|
|
available -= amount;
|
|
base58_decode(payee, script_payee);
|
|
job_pack_tx(coind, script_dests, amount, script_payee);
|
|
//debuglog("%s superblock %s %u\n", coind->symbol, payee, amount);
|
|
}
|
|
}
|
|
}
|
|
if (masternode_enabled && masternode) {
|
|
const char *payee = json_get_string(masternode, "payee");
|
|
json_int_t amount = json_get_int(masternode, "amount");
|
|
if (payee && amount) {
|
|
npayees++;
|
|
available -= amount;
|
|
base58_decode(payee, script_payee);
|
|
job_pack_tx(coind, script_dests, amount, script_payee);
|
|
}
|
|
}
|
|
sprintf(payees, "%02x", npayees);
|
|
strcat(templ->coinb2, payees);
|
|
strcat(templ->coinb2, script_dests);
|
|
job_pack_tx(coind, templ->coinb2, available, NULL);
|
|
strcat(templ->coinb2, "00000000"); // locktime
|
|
coind->reward = (double)available/100000000*coind->reward_mul;
|
|
//debuglog("%s %d dests %s\n", coind->symbol, npayees, script_dests);
|
|
return;
|
|
}
|
|
|
|
|
|
else if(coind->hasmasternodes) /* OLD DASH style */
|
|
{
|
|
char charity_payee[256] = { 0 };
|
|
const char *payee = json_get_string(json_result, "payee");
|
|
if (payee) snprintf(charity_payee, 255, "%s", payee);
|
|
|
|
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 };
|
|
char script_payee[128] = { 0 };
|
|
char payees[4];
|
|
int npayees = 1;
|
|
bool masternodes_enabled = json_get_bool(json_result, "enforce_masternode_payments");
|
|
bool systemnodes_enabled = json_get_bool(json_result, "enforce_systemnode_payments");
|
|
bool systemnodes = json_get_bool(json_result, "systemnodes");
|
|
bool masternodes = json_get_bool(json_result, "masternodes");
|
|
if(systemnodes_enabled && systemnodes) {
|
|
const char *payeeSN = json_get_string(json_result, "payeeSN");
|
|
json_int_t payeeSN_amount = json_get_int(json_result, "payeeSN_amount");
|
|
if (payeeSN && payeeSN_amount) {
|
|
npayees++;
|
|
available -= payeeSN_amount;
|
|
base58_decode(payeeSN, script_payee);
|
|
job_pack_tx(coind, script_dests, payeeSN_amount, script_payee);
|
|
//debuglog("%s systemnode %s %u\n", coind->symbol, payeeSN, payeeSN_amount);
|
|
}
|
|
}
|
|
if (masternodes_enabled && masternodes) {
|
|
const char *payee = json_get_string(json_result, "payee");
|
|
json_int_t amount = json_get_int(json_result, "amount");
|
|
if (payee && amount) {
|
|
npayees++;
|
|
available -= amount;
|
|
base58_decode(payee, script_payee);
|
|
job_pack_tx(coind, script_dests, amount, script_payee);
|
|
}
|
|
}
|
|
sprintf(payees, "%02x", npayees);
|
|
strcat(templ->coinb2, payees);
|
|
strcat(templ->coinb2, script_dests);
|
|
job_pack_tx(coind, templ->coinb2, available, NULL);
|
|
strcat(templ->coinb2, "00000000"); // locktime
|
|
coind->reward = (double)available/100000000*coind->reward_mul;
|
|
//debuglog("%s %d dests %s\n", coind->symbol, npayees, script_dests);
|
|
return;
|
|
}
|
|
|
|
if(charity_payments && charity_enforce)
|
|
{
|
|
char script_payee[256] = { 0 };
|
|
base58_decode(charity_payee, script_payee);
|
|
|
|
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);
|
|
available -= charity_amount;
|
|
|
|
} else {
|
|
strcat(templ->coinb2, "01");
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
//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);
|
|
|
|
// debuglog("coinbase %s: version %s, nbits %s, time %s\n", coind->symbol, templ->version, templ->nbits, templ->ntime);
|
|
// debuglog("coinb1 %s\n", templ->coinb1);
|
|
// debuglog("coinb2 %s\n", templ->coinb2);
|
|
}
|
|
|
|
|
|
|