Make 0.12.1.x minable again (#963)

* Changes for getblocktemplate, CreateNewBlock, FillBlockPayee, CreateSuperblock:
- Add support for superblocks in getblocktemplate (+fix miner reward - it was missing)
- Refactor the way masternode payments are passed around, change getblocktemplate format for them too.
This commit is contained in:
UdjinM6 2016-08-28 14:11:36 +04:00 committed by GitHub
parent 180a81eada
commit 02b86cf467
7 changed files with 95 additions and 59 deletions

View File

@ -396,7 +396,7 @@ bool CSuperblockManager::GetBestSuperblock(CSuperblock_sptr& pBlock, int nBlockH
* - Create the correct payment structure for a given superblock
*/
void CSuperblockManager::CreateSuperblock(CMutableTransaction& txNew, int nBlockHeight)
void CSuperblockManager::CreateSuperblock(CMutableTransaction& txNewRet, int nBlockHeight, std::vector<CTxOut>& voutSuperblockRet)
{
DBG( cout << "CSuperblockManager::CreateSuperblock Start" << endl; );
@ -411,10 +411,12 @@ void CSuperblockManager::CreateSuperblock(CMutableTransaction& txNew, int nBlock
return;
}
// CONFIGURE SUPERBLOCK OUTPUTS
// make sure it's empty, just in case
voutSuperblockRet.clear();
// CONFIGURE SUPERBLOCK OUTPUTS
// Superblock payments are appended to the end of the coinbase vout vector
DBG( cout << "CSuperblockManager::CreateSuperblock Number payments: " << pBlock->CountPayments() << endl; );
// TODO: How many payments can we add before things blow up?
@ -428,7 +430,9 @@ void CSuperblockManager::CreateSuperblock(CMutableTransaction& txNew, int nBlock
DBG( cout << "CSuperblockManager::CreateSuperblock Payment found " << endl; );
// SET COINBASE OUTPUT TO SUPERBLOCK SETTING
txNew.vout.push_back(CTxOut(payment.nAmount, payment.script));
CTxOut txout = CTxOut(payment.nAmount, payment.script);
txNewRet.vout.push_back(txout);
voutSuperblockRet.push_back(txout);
// PRINT NICE LOG OUTPUT FOR SUPERBLOCK PAYMENT

View File

@ -90,7 +90,7 @@ public:
static bool IsSuperblockTriggered(int nBlockHeight);
static void CreateSuperblock(CMutableTransaction& txNew, int nBlockHeight);
static void CreateSuperblock(CMutableTransaction& txNewRet, int nBlockHeight, std::vector<CTxOut>& voutSuperblockRet);
static std::string GetRequiredPaymentsString(int nBlockHeight);
static bool IsValid(const CTransaction& txNew, int nBlockHeight, CAmount blockReward);

View File

@ -183,19 +183,21 @@ bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight, CAmount bloc
return true;
}
void FillBlockPayee(CMutableTransaction& txNew, CAmount blockReward, int nBlockHeight)
void FillBlockPayments(CMutableTransaction& txNew, int nBlockHeight, CAmount blockReward, CTxOut& txoutMasternodeRet, std::vector<CTxOut>& voutSuperblockRet)
{
// only create superblocks if spork is enabled AND if superblock is actually triggered
// (height should be validated inside)
if(sporkManager.IsSporkActive(SPORK_9_MASTERNODE_SUPERBLOCK_ENFORCEMENT) &&
CSuperblockManager::IsSuperblockTriggered(nBlockHeight)) {
LogPrint("gobject", "FillBlockPayee -- triggered superblock creation at height %d\n", nBlockHeight);
CSuperblockManager::CreateSuperblock(txNew, nBlockHeight);
LogPrint("gobject", "FillBlockPayments -- triggered superblock creation at height %d\n", nBlockHeight);
CSuperblockManager::CreateSuperblock(txNew, nBlockHeight, voutSuperblockRet);
return;
}
// FILL BLOCK PAYEE WITH MASTERNODE PAYMENT OTHERWISE
mnpayments.FillBlockPayee(txNew, blockReward, nBlockHeight);
mnpayments.FillBlockPayee(txNew, nBlockHeight, blockReward, txoutMasternodeRet);
LogPrint("mnpayments", "FillBlockPayments -- nBlockHeight %d blockReward %lld txoutMasternodeRet %s txNew %s",
nBlockHeight, blockReward, txoutMasternodeRet.ToString(), txNew.ToString());
}
std::string GetRequiredPaymentsString(int nBlockHeight)
@ -215,40 +217,39 @@ std::string GetRequiredPaymentsString(int nBlockHeight)
* Fill Masternode ONLY payment block
*/
void CMasternodePayments::FillBlockPayee(CMutableTransaction& txNew, CAmount blockReward, int nBlockHeight)
void CMasternodePayments::FillBlockPayee(CMutableTransaction& txNew, int nBlockHeight, CAmount blockReward, CTxOut& txoutMasternodeRet)
{
bool hasPayment = true;
// make sure it's not filled yet
txoutMasternodeRet = CTxOut();
CScript payee;
if(!mnpayments.GetBlockPayee(nBlockHeight, payee)) {
//no masternode detected
// no masternode detected...
CMasternode* winningNode = mnodeman.GetCurrentMasterNode();
if(winningNode) {
payee = GetScriptForDestination(winningNode->pubkey.GetID());
} else {
if(!winningNode) {
// ...and we can't calculate it on our own
LogPrintf("CMasternodePayments::FillBlockPayee -- Failed to detect masternode to pay\n");
hasPayment = false;
return;
}
// fill payee with locally calculated winner and hope for the best
payee = GetScriptForDestination(winningNode->pubkey.GetID());
}
// GET MASTERNODE PAYMENT VARIABLES SETUP
CAmount masternodePayment = GetMasternodePayment(nBlockHeight, blockReward);
txNew.vout[0].nValue = blockReward;
// split reward between miner ...
txNew.vout[0].nValue -= masternodePayment;
// ... and masternode
txoutMasternodeRet = CTxOut(masternodePayment, payee);
txNew.vout.push_back(txoutMasternodeRet);
if(hasPayment) {
// split reward between miner ...
txNew.vout[0].nValue -= masternodePayment;
// ... and masternode
txNew.vout.push_back(CTxOut(masternodePayment, payee));
CTxDestination address1;
ExtractDestination(payee, address1);
CBitcoinAddress address2(address1);
CTxDestination address1;
ExtractDestination(payee, address1);
CBitcoinAddress address2(address1);
LogPrintf("Masternode payment %d to %s\n", masternodePayment, address2.ToString());
}
LogPrintf("CMasternodePayments::FillBlockPayee -- Masternode payment %lld to %s\n", masternodePayment, address2.ToString());
}
int CMasternodePayments::GetMinMasternodePaymentsProto() {

View File

@ -35,7 +35,7 @@ bool IsReferenceNode(CTxIn& vin);
/// TODO: all 4 functions do not belong here really, they should be refactored/moved somewhere (main.cpp ?)
bool IsBlockValueValid(const CBlock& block, int nBlockHeight, CAmount blockReward);
bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight, CAmount blockReward);
void FillBlockPayee(CMutableTransaction& txNew, CAmount blockReward, int nBlockHeight);
void FillBlockPayments(CMutableTransaction& txNew, int nBlockHeight, CAmount blockReward, CTxOut& txoutMasternodeRet, std::vector<CTxOut>& voutSuperblockRet);
std::string GetRequiredPaymentsString(int nBlockHeight);
class CMasternodePayee
@ -249,7 +249,7 @@ public:
int GetMinMasternodePaymentsProto();
void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
std::string GetRequiredPaymentsString(int nBlockHeight);
void FillBlockPayee(CMutableTransaction& txNew, CAmount blockReward, int nBlockHeight);
void FillBlockPayee(CMutableTransaction& txNew, int nBlockHeight, CAmount blockReward, CTxOut& txoutMasternodeRet);
std::string ToString() const;
int GetOldestBlock();

View File

@ -274,24 +274,25 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s
}
}
}
CAmount blockReward = nFees + GetBlockSubsidy(pindexPrev->nBits, pindexPrev->nHeight, Params().GetConsensus());
// Masternode and governace payments
FillBlockPayee(txNew, blockReward, nHeight);
// Make payee
// TODO: does not make sense for superblocks and it is not enough anymore
if(txNew.vout.size() > 1){
pblock->payee = txNew.vout[1].scriptPubKey;
}
// NOTE: unlike in bitcoin, we need to pass PREVIOUS block height here
CAmount blockReward = nFees + GetBlockSubsidy(pindexPrev->nBits, pindexPrev->nHeight, Params().GetConsensus());
// Compute regular coinbase transaction.
txNew.vout[0].nValue = blockReward;
txNew.vin[0].scriptSig = CScript() << nHeight << OP_0;
// Update coinbase transaction with additional info about masternode and governace payments,
// get some info back to pass to getblocktemplate
FillBlockPayments(txNew, nHeight, blockReward, pblock->txoutMasternode, pblock->voutSuperblock);
// LogPrintf("CreateNewBlock -- nBlockHeight %d blockReward %lld txoutMasternode %s txNew %s",
// nHeight, blockReward, pblock->txoutMasternode.ToString(), txNew.ToString());
nLastBlockTx = nBlockTx;
nLastBlockSize = nBlockSize;
LogPrintf("CreateNewBlock(): total size %u txs: %u fees: %ld sigops %d\n", nBlockSize, nBlockTx, nFees, nBlockSigOps);
// Compute final coinbase transaction.
// Should already be calculated in FillBlockPayee
// txNew.vout[0].nValue = nFees + GetBlockSubsidy(pindexPrev->nBits, nHeight, chainparams.GetConsensus());
txNew.vin[0].scriptSig = CScript() << nHeight << OP_0;
// Update block coinbase
pblock->vtx[0] = txNew;
pblocktemplate->vTxFees[0] = -nFees;

View File

@ -77,7 +77,8 @@ public:
std::vector<CTransaction> vtx;
// memory only
mutable CScript payee;
mutable CTxOut txoutMasternode; // masternode payment
mutable std::vector<CTxOut> voutSuperblock; // superblock payment
mutable bool fChecked;
CBlock()
@ -103,7 +104,8 @@ public:
{
CBlockHeader::SetNull();
vtx.clear();
payee = CScript();
txoutMasternode = CTxOut();
voutSuperblock.clear();
fChecked = false;
}

View File

@ -381,10 +381,23 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
" \"curtime\" : ttt, (numeric) current timestamp in seconds since epoch (Jan 1 1970 GMT)\n"
" \"bits\" : \"xxx\", (string) compressed target of next block\n"
" \"height\" : n (numeric) The height of the next block\n"
" \"payee\" : \"xxx\", (string) required payee for the next block\n"
" \"payee_amount\" : n, (numeric) required amount to pay\n"
" \"masternode_payments\" : true|false, (boolean) true, if masternode payments are enabled\n"
" \"enforce_masternode_payments\" : true|false (boolean) true, if masternode payments are enforced\n"
" \"masternode\" : { (json object) required masternode payee that must be included in the next block\n"
" \"payee\" : \"xxxx\", (string) payee address\n"
" \"script\" : \"xxxx\", (string) payee scriptPubKey\n"
" \"amount\": n (numeric) required amount to pay\n"
" },\n"
" \"masternode_payments_started\" : true|false, (boolean) true, if masternode payments started\n"
" \"masternode_payments_enforced\" : true|false, (boolean) true, if masternode payments are enforced\n"
" \"superblock\" : [ (array) required superblock payees that must be included in the next block\n"
" {\n"
" \"payee\" : \"xxxx\", (string) payee address\n"
" \"script\" : \"xxxx\", (string) payee scriptPubKey\n"
" \"amount\": n (numeric) required amount to pay\n"
" }\n"
" ,...\n"
" ],\n"
" \"superblocks_started\" : true|false, (boolean) true, if superblock payments started\n"
" \"superblocks_enabled\" : true|false (boolean) true, if superblock payments are enabled\n"
"}\n"
"\nExamples:\n"
@ -597,20 +610,35 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
result.push_back(Pair("bits", strprintf("%08x", pblock->nBits)));
result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
if(pblock->payee != CScript()){
UniValue masternodeObj(UniValue::VOBJ);
if(pblock->txoutMasternode != CTxOut()) {
CTxDestination address1;
ExtractDestination(pblock->payee, address1);
ExtractDestination(pblock->txoutMasternode.scriptPubKey, address1);
CBitcoinAddress address2(address1);
result.push_back(Pair("payee", address2.ToString().c_str()));
result.push_back(Pair("payee_amount", (int64_t)pblock->vtx[0].vout[1].nValue));
} else {
result.push_back(Pair("payee", ""));
result.push_back(Pair("payee_amount", ""));
masternodeObj.push_back(Pair("payee", address2.ToString().c_str()));
masternodeObj.push_back(Pair("script", HexStr(pblock->txoutMasternode.scriptPubKey.begin(), pblock->txoutMasternode.scriptPubKey.end())));
masternodeObj.push_back(Pair("amount", pblock->txoutMasternode.nValue));
}
result.push_back(Pair("masternode", masternodeObj));
result.push_back(Pair("masternode_payments_started", pindexPrev->nHeight + 1 > Params().GetConsensus().nMasternodePaymentsStartBlock));
result.push_back(Pair("masternode_payments_enforced", sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)));
result.push_back(Pair("masternode_payments", (int64_t)(pindexPrev->nHeight+1) > Params().GetConsensus().nMasternodePaymentsStartBlock));
result.push_back(Pair("enforce_masternode_payments", sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)));
UniValue superblockObjArray(UniValue::VARR);
if(pblock->voutSuperblock.size()) {
BOOST_FOREACH (const CTxOut& txout, pblock->voutSuperblock) {
UniValue entry(UniValue::VOBJ);
CTxDestination address1;
ExtractDestination(txout.scriptPubKey, address1);
CBitcoinAddress address2(address1);
entry.push_back(Pair("payee", address2.ToString().c_str()));
entry.push_back(Pair("script", HexStr(txout.scriptPubKey.begin(), txout.scriptPubKey.end())));
entry.push_back(Pair("amount", txout.nValue));
superblockObjArray.push_back(entry);
}
}
result.push_back(Pair("superblock", superblockObjArray));
result.push_back(Pair("superblocks_started", pindexPrev->nHeight + 1 > Params().GetConsensus().nSuperblockStartBlock));
result.push_back(Pair("superblocks_enabled", sporkManager.IsSporkActive(SPORK_9_MASTERNODE_SUPERBLOCK_ENFORCEMENT)));
return result;
}