Merge pull request #2115 from forrestv/getblocktemplate_allfees

Provide fee data for all txs in RPC getblocktemplate response
This commit is contained in:
Pieter Wuille 2013-01-10 13:09:51 -08:00
commit 45a1ec51b1
4 changed files with 70 additions and 55 deletions

View File

@ -3732,12 +3732,13 @@ public:
}
};
CBlock* CreateNewBlock(CReserveKey& reservekey)
CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
{
// Create new block
auto_ptr<CBlock> pblock(new CBlock());
if (!pblock.get())
auto_ptr<CBlockTemplate> 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<CBlock> pblock(CreateNewBlock(reservekey));
if (!pblock.get())
auto_ptr<CBlockTemplate> 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;
}

View File

@ -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<int64_t> vTxFees;
std::vector<int64_t> vTxSigOps;
};
#endif

View File

@ -103,7 +103,7 @@ Value getwork(const Array& params, bool fHelp)
typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
static mapNewBlock_t mapNewBlock; // FIXME: thread safety
static vector<CBlock*> vNewBlock;
static vector<CBlockTemplate*> 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);
@ -281,7 +283,6 @@ Value getblocktemplate(const Array& params, bool fHelp)
Array transactions;
map<uint256, int64_t> setTxIndex;
int i = 0;
CCoinsViewCache &view = *pcoinsTip;
BOOST_FOREACH (CTransaction& tx, pblock->vtx)
{
uint256 txHash = tx.GetHash();
@ -306,13 +307,9 @@ 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));
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);
}

View File

@ -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::vector<CTransaction*>txFirst;
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;
}