From 03cac0bb8e9cab02c456cbe71a0519aec92a6150 Mon Sep 17 00:00:00 2001 From: Forrest Voight Date: Wed, 19 Dec 2012 15:21:21 -0500 Subject: [PATCH 1/3] changed CreateNewBlock to return a CBlockTemplate object, which includes per-tx fee and sigop count data --- src/main.cpp | 28 ++++++++++++++++--------- src/main.h | 11 +++++++++- src/rpcmining.cpp | 30 ++++++++++++++------------- src/test/miner_tests.cpp | 45 ++++++++++++++++++++-------------------- 4 files changed, 67 insertions(+), 47 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 96bdabd58..20480f029 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3732,12 +3732,13 @@ public: } }; -CBlock* CreateNewBlock(CReserveKey& reservekey) +CBlockTemplate* CreateNewBlock(CReserveKey& reservekey) { // Create new block - auto_ptr pblock(new CBlock()); - if (!pblock.get()) + auto_ptr pblocktemplate(new CBlockTemplate()); + if(!pblocktemplate.get()) return NULL; + CBlock *pblock = &pblocktemplate->block; // pointer for convenience // Create coinbase tx CTransaction txNew; @@ -3748,6 +3749,8 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) // Add our coinbase tx as first transaction pblock->vtx.push_back(txNew); + pblocktemplate->vTxFees.push_back(-1); // updated at end + pblocktemplate->vTxSigOps.push_back(-1); // updated at end // Largest block you're willing to create: unsigned int nBlockMaxSize = GetArg("-blockmaxsize", MAX_BLOCK_SIZE_GEN/2); @@ -3925,6 +3928,8 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) // Added pblock->vtx.push_back(tx); + pblocktemplate->vTxFees.push_back(nTxFees); + pblocktemplate->vTxSigOps.push_back(nTxSigOps); nBlockSize += nTxSize; ++nBlockTx; nBlockSigOps += nTxSigOps; @@ -3959,13 +3964,15 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) printf("CreateNewBlock(): total size %"PRI64u"\n", nBlockSize); pblock->vtx[0].vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees); + pblocktemplate->vTxFees[0] = -nFees; // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); pblock->UpdateTime(pindexPrev); - pblock->nBits = GetNextWorkRequired(pindexPrev, pblock.get()); + pblock->nBits = GetNextWorkRequired(pindexPrev, pblock); pblock->nNonce = 0; pblock->vtx[0].vin[0].scriptSig = CScript() << OP_0 << OP_0; + pblocktemplate->vTxSigOps[0] = pblock->vtx[0].GetLegacySigOpCount(); CBlockIndex indexDummy(*pblock); indexDummy.pprev = pindexPrev; @@ -3975,7 +3982,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) throw std::runtime_error("CreateNewBlock() : ConnectBlock failed"); } - return pblock.release(); + return pblocktemplate.release(); } @@ -4118,10 +4125,11 @@ void static BitcoinMiner(CWallet *pwallet) unsigned int nTransactionsUpdatedLast = nTransactionsUpdated; CBlockIndex* pindexPrev = pindexBest; - auto_ptr pblock(CreateNewBlock(reservekey)); - if (!pblock.get()) + auto_ptr pblocktemplate(CreateNewBlock(reservekey)); + if (!pblocktemplate.get()) return; - IncrementExtraNonce(pblock.get(), pindexPrev, nExtraNonce); + CBlock *pblock = &pblocktemplate->block; + IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); printf("Running BitcoinMiner with %"PRIszu" transactions in block (%u bytes)\n", pblock->vtx.size(), ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); @@ -4134,7 +4142,7 @@ void static BitcoinMiner(CWallet *pwallet) char pdatabuf[128+16]; char* pdata = alignup<16>(pdatabuf); char phash1buf[64+16]; char* phash1 = alignup<16>(phash1buf); - FormatHashBuffers(pblock.get(), pmidstate, pdata, phash1); + FormatHashBuffers(pblock, pmidstate, pdata, phash1); unsigned int& nBlockTime = *(unsigned int*)(pdata + 64 + 4); unsigned int& nBlockBits = *(unsigned int*)(pdata + 64 + 8); @@ -4170,7 +4178,7 @@ void static BitcoinMiner(CWallet *pwallet) assert(hash == pblock->GetHash()); SetThreadPriority(THREAD_PRIORITY_NORMAL); - CheckWork(pblock.get(), *pwalletMain, reservekey); + CheckWork(pblock, *pwalletMain, reservekey); SetThreadPriority(THREAD_PRIORITY_LOWEST); break; } diff --git a/src/main.h b/src/main.h index 8bceffbaf..d34778d12 100644 --- a/src/main.h +++ b/src/main.h @@ -108,6 +108,8 @@ class CTxUndo; class CCoinsView; class CCoinsViewCache; +struct CBlockTemplate; + /** Register a wallet to receive updates from core */ void RegisterWallet(CWallet* pwalletIn); /** Unregister a wallet from core */ @@ -139,7 +141,7 @@ void ThreadImport(void *parg); /** Run the miner threads */ void GenerateBitcoins(bool fGenerate, CWallet* pwallet); /** Generate a new block, without valid proof-of-work */ -CBlock* CreateNewBlock(CReserveKey& reservekey); +CBlockTemplate* CreateNewBlock(CReserveKey& reservekey); /** Modify the extranonce in a block */ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce); /** Do mining precalculation */ @@ -1975,4 +1977,11 @@ extern CCoinsViewCache *pcoinsTip; /** Global variable that points to the active block tree (protected by cs_main) */ extern CBlockTreeDB *pblocktree; +struct CBlockTemplate +{ + CBlock block; + std::vector vTxFees; + std::vector vTxSigOps; +}; + #endif diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 0591f3539..e4b487aea 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -103,7 +103,7 @@ Value getwork(const Array& params, bool fHelp) typedef map > mapNewBlock_t; static mapNewBlock_t mapNewBlock; // FIXME: thread safety - static vector vNewBlock; + static vector vNewBlockTemplate; static CReserveKey reservekey(pwalletMain); if (params.size() == 0) @@ -112,7 +112,7 @@ Value getwork(const Array& params, bool fHelp) static unsigned int nTransactionsUpdatedLast; static CBlockIndex* pindexPrev; static int64 nStart; - static CBlock* pblock; + static CBlockTemplate* pblocktemplate; if (pindexPrev != pindexBest || (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60)) { @@ -120,9 +120,9 @@ Value getwork(const Array& params, bool fHelp) { // Deallocate old blocks since they're obsolete now mapNewBlock.clear(); - BOOST_FOREACH(CBlock* pblock, vNewBlock) - delete pblock; - vNewBlock.clear(); + BOOST_FOREACH(CBlockTemplate* pblocktemplate, vNewBlockTemplate) + delete pblocktemplate; + vNewBlockTemplate.clear(); } // Clear pindexPrev so future getworks make a new block, despite any failures from here on @@ -134,14 +134,15 @@ Value getwork(const Array& params, bool fHelp) nStart = GetTime(); // Create new block - pblock = CreateNewBlock(reservekey); - if (!pblock) + pblocktemplate = CreateNewBlock(reservekey); + if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); - vNewBlock.push_back(pblock); + vNewBlockTemplate.push_back(pblocktemplate); // Need to update only after we know CreateNewBlock succeeded pindexPrev = pindexPrevNew; } + CBlock* pblock = &pblocktemplate->block; // pointer for convenience // Update nTime pblock->UpdateTime(pindexPrev); @@ -248,7 +249,7 @@ Value getblocktemplate(const Array& params, bool fHelp) static unsigned int nTransactionsUpdatedLast; static CBlockIndex* pindexPrev; static int64 nStart; - static CBlock* pblock; + static CBlockTemplate* pblocktemplate; if (pindexPrev != pindexBest || (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5)) { @@ -261,18 +262,19 @@ Value getblocktemplate(const Array& params, bool fHelp) nStart = GetTime(); // Create new block - if(pblock) + if(pblocktemplate) { - delete pblock; - pblock = NULL; + delete pblocktemplate; + pblocktemplate = NULL; } - pblock = CreateNewBlock(reservekey); - if (!pblock) + pblocktemplate = CreateNewBlock(reservekey); + if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); // Need to update only after we know CreateNewBlock succeeded pindexPrev = pindexPrevNew; } + CBlock* pblock = &pblocktemplate->block; // pointer for convenience // Update nTime pblock->UpdateTime(pindexPrev); diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 4558a76a2..bc2a05a6b 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -49,19 +49,20 @@ struct { BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { CReserveKey reservekey(pwalletMain); - CBlock *pblock; + CBlockTemplate *pblocktemplate; CTransaction tx; CScript script; uint256 hash; // Simple block creation, nothing special yet: - BOOST_CHECK(pblock = CreateNewBlock(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(reservekey)); // We can't make transactions until we have inputs // Therefore, load 100 blocks :) std::vectortxFirst; for (unsigned int i = 0; i < sizeof(blockinfo)/sizeof(*blockinfo); ++i) { + CBlock *pblock = &pblocktemplate->block; // pointer for convenience pblock->nVersion = 1; pblock->nTime = pindexBest->GetMedianTimePast()+1; pblock->vtx[0].vin[0].scriptSig = CScript(); @@ -75,10 +76,10 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) assert(ProcessBlock(NULL, pblock)); pblock->hashPrevBlock = pblock->GetHash(); } - delete pblock; + delete pblocktemplate; // Just to make sure we can still make simple blocks - BOOST_CHECK(pblock = CreateNewBlock(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(reservekey)); // block sigops > limit: 1000 CHECKMULTISIG + 1 tx.vin.resize(1); @@ -95,8 +96,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) mempool.addUnchecked(hash, tx); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(pblock = CreateNewBlock(reservekey)); - delete pblock; + BOOST_CHECK(pblocktemplate = CreateNewBlock(reservekey)); + delete pblocktemplate; mempool.clear(); // block size > limit @@ -115,15 +116,15 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) mempool.addUnchecked(hash, tx); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(pblock = CreateNewBlock(reservekey)); - delete pblock; + BOOST_CHECK(pblocktemplate = CreateNewBlock(reservekey)); + delete pblocktemplate; mempool.clear(); // orphan in mempool hash = tx.GetHash(); mempool.addUnchecked(hash, tx); - BOOST_CHECK(pblock = CreateNewBlock(reservekey)); - delete pblock; + BOOST_CHECK(pblocktemplate = CreateNewBlock(reservekey)); + delete pblocktemplate; mempool.clear(); // child with higher priority than parent @@ -140,8 +141,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue = 5900000000LL; hash = tx.GetHash(); mempool.addUnchecked(hash, tx); - BOOST_CHECK(pblock = CreateNewBlock(reservekey)); - delete pblock; + BOOST_CHECK(pblocktemplate = CreateNewBlock(reservekey)); + delete pblocktemplate; mempool.clear(); // coinbase in mempool @@ -151,8 +152,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue = 0; hash = tx.GetHash(); mempool.addUnchecked(hash, tx); - BOOST_CHECK(pblock = CreateNewBlock(reservekey)); - delete pblock; + BOOST_CHECK(pblocktemplate = CreateNewBlock(reservekey)); + delete pblocktemplate; mempool.clear(); // invalid (pre-p2sh) txn in mempool @@ -169,8 +170,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue -= 1000000; hash = tx.GetHash(); mempool.addUnchecked(hash,tx); - BOOST_CHECK(pblock = CreateNewBlock(reservekey)); - delete pblock; + BOOST_CHECK(pblocktemplate = CreateNewBlock(reservekey)); + delete pblocktemplate; mempool.clear(); // double spend txn pair in mempool @@ -183,18 +184,18 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].scriptPubKey = CScript() << OP_2; hash = tx.GetHash(); mempool.addUnchecked(hash, tx); - BOOST_CHECK(pblock = CreateNewBlock(reservekey)); - delete pblock; + BOOST_CHECK(pblocktemplate = CreateNewBlock(reservekey)); + delete pblocktemplate; mempool.clear(); // subsidy changing int nHeight = pindexBest->nHeight; pindexBest->nHeight = 209999; - BOOST_CHECK(pblock = CreateNewBlock(reservekey)); - delete pblock; + BOOST_CHECK(pblocktemplate = CreateNewBlock(reservekey)); + delete pblocktemplate; pindexBest->nHeight = 210000; - BOOST_CHECK(pblock = CreateNewBlock(reservekey)); - delete pblock; + BOOST_CHECK(pblocktemplate = CreateNewBlock(reservekey)); + delete pblocktemplate; pindexBest->nHeight = nHeight; } From 0f927ceb5b90ec02be36ddb20b2f4cff82589265 Mon Sep 17 00:00:00 2001 From: Forrest Voight Date: Wed, 19 Dec 2012 15:44:25 -0500 Subject: [PATCH 2/3] use fee/sigop data in BlockTemplate struct instead of (not always correctly) calculating it ourselves --- src/rpcmining.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index e4b487aea..47ca13528 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -283,7 +283,6 @@ Value getblocktemplate(const Array& params, bool fHelp) Array transactions; map setTxIndex; int i = 0; - CCoinsViewCache &view = *pcoinsTip; BOOST_FOREACH (CTransaction& tx, pblock->vtx) { uint256 txHash = tx.GetHash(); @@ -308,13 +307,8 @@ Value getblocktemplate(const Array& params, bool fHelp) } entry.push_back(Pair("depends", deps)); - int64_t nSigOps = tx.GetLegacySigOpCount(); - if (tx.HaveInputs(view)) - { - entry.push_back(Pair("fee", (int64_t)(tx.GetValueIn(view) - tx.GetValueOut()))); - nSigOps += tx.GetP2SHSigOpCount(view); - } - entry.push_back(Pair("sigops", nSigOps)); + entry.push_back(Pair("fee", pblocktemplate->vTxFees[&tx - pblock->vtx.data()])); + entry.push_back(Pair("sigops", pblocktemplate->vTxSigOps[&tx - pblock->vtx.data()])); transactions.push_back(entry); } From f3d872d1eabeb5c999162f709626ee20c8789c42 Mon Sep 17 00:00:00 2001 From: Forrest Voight Date: Thu, 3 Jan 2013 23:58:36 -0500 Subject: [PATCH 3/3] moved "index_in_template" to a separate variable to clarify what it is --- src/rpcmining.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 47ca13528..778e0acbd 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -307,8 +307,9 @@ Value getblocktemplate(const Array& params, bool fHelp) } entry.push_back(Pair("depends", deps)); - entry.push_back(Pair("fee", pblocktemplate->vTxFees[&tx - pblock->vtx.data()])); - entry.push_back(Pair("sigops", pblocktemplate->vTxSigOps[&tx - pblock->vtx.data()])); + int index_in_template = &tx - pblock->vtx.data(); + entry.push_back(Pair("fee", pblocktemplate->vTxFees[index_in_template])); + entry.push_back(Pair("sigops", pblocktemplate->vTxSigOps[index_in_template])); transactions.push_back(entry); }