|
|
@ -1959,123 +1959,121 @@ Value getblocktemplate(const Array& params, bool fHelp) |
|
|
|
if (strMode != "template") |
|
|
|
if (strMode != "template") |
|
|
|
throw JSONRPCError(-8, "Invalid mode"); |
|
|
|
throw JSONRPCError(-8, "Invalid mode"); |
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
if (vNodes.empty()) |
|
|
|
if (vNodes.empty()) |
|
|
|
throw JSONRPCError(-9, "Bitcoin is not connected!"); |
|
|
|
throw JSONRPCError(-9, "Bitcoin is not connected!"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (IsInitialBlockDownload()) |
|
|
|
|
|
|
|
throw JSONRPCError(-10, "Bitcoin is downloading blocks..."); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static CReserveKey reservekey(pwalletMain); |
|
|
|
if (IsInitialBlockDownload()) |
|
|
|
|
|
|
|
throw JSONRPCError(-10, "Bitcoin is downloading blocks..."); |
|
|
|
|
|
|
|
|
|
|
|
// Update block
|
|
|
|
static CReserveKey reservekey(pwalletMain); |
|
|
|
static unsigned int nTransactionsUpdatedLast; |
|
|
|
|
|
|
|
static CBlockIndex* pindexPrev; |
|
|
|
|
|
|
|
static int64 nStart; |
|
|
|
|
|
|
|
static CBlock* pblock; |
|
|
|
|
|
|
|
if (pindexPrev != pindexBest || |
|
|
|
|
|
|
|
(nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// Clear pindexPrev so future calls make a new block, despite any failures from here on
|
|
|
|
|
|
|
|
pindexPrev = NULL; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Store the pindexBest used before CreateNewBlock, to avoid races
|
|
|
|
// Update block
|
|
|
|
nTransactionsUpdatedLast = nTransactionsUpdated; |
|
|
|
static unsigned int nTransactionsUpdatedLast; |
|
|
|
CBlockIndex* pindexPrevNew = pindexBest; |
|
|
|
static CBlockIndex* pindexPrev; |
|
|
|
nStart = GetTime(); |
|
|
|
static int64 nStart; |
|
|
|
|
|
|
|
static CBlock* pblock; |
|
|
|
|
|
|
|
if (pindexPrev != pindexBest || |
|
|
|
|
|
|
|
(nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// Clear pindexPrev so future calls make a new block, despite any failures from here on
|
|
|
|
|
|
|
|
pindexPrev = NULL; |
|
|
|
|
|
|
|
|
|
|
|
// Create new block
|
|
|
|
// Store the pindexBest used before CreateNewBlock, to avoid races
|
|
|
|
if(pblock) |
|
|
|
nTransactionsUpdatedLast = nTransactionsUpdated; |
|
|
|
{ |
|
|
|
CBlockIndex* pindexPrevNew = pindexBest; |
|
|
|
delete pblock; |
|
|
|
nStart = GetTime(); |
|
|
|
pblock = NULL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
pblock = CreateNewBlock(reservekey); |
|
|
|
|
|
|
|
if (!pblock) |
|
|
|
|
|
|
|
throw JSONRPCError(-7, "Out of memory"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Need to update only after we know CreateNewBlock succeeded
|
|
|
|
// Create new block
|
|
|
|
pindexPrev = pindexPrevNew; |
|
|
|
if(pblock) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
delete pblock; |
|
|
|
|
|
|
|
pblock = NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
pblock = CreateNewBlock(reservekey); |
|
|
|
|
|
|
|
if (!pblock) |
|
|
|
|
|
|
|
throw JSONRPCError(-7, "Out of memory"); |
|
|
|
|
|
|
|
|
|
|
|
// Update nTime
|
|
|
|
// Need to update only after we know CreateNewBlock succeeded
|
|
|
|
pblock->UpdateTime(pindexPrev); |
|
|
|
pindexPrev = pindexPrevNew; |
|
|
|
pblock->nNonce = 0; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Array transactions; |
|
|
|
// Update nTime
|
|
|
|
map<uint256, int64_t> setTxIndex; |
|
|
|
pblock->UpdateTime(pindexPrev); |
|
|
|
int i = 0; |
|
|
|
pblock->nNonce = 0; |
|
|
|
CTxDB txdb("r"); |
|
|
|
|
|
|
|
BOOST_FOREACH (CTransaction& tx, pblock->vtx) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
uint256 txHash = tx.GetHash(); |
|
|
|
|
|
|
|
setTxIndex[txHash] = i++; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (tx.IsCoinBase()) |
|
|
|
Array transactions; |
|
|
|
continue; |
|
|
|
map<uint256, int64_t> setTxIndex; |
|
|
|
|
|
|
|
int i = 0; |
|
|
|
|
|
|
|
CTxDB txdb("r"); |
|
|
|
|
|
|
|
BOOST_FOREACH (CTransaction& tx, pblock->vtx) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
uint256 txHash = tx.GetHash(); |
|
|
|
|
|
|
|
setTxIndex[txHash] = i++; |
|
|
|
|
|
|
|
|
|
|
|
Object entry; |
|
|
|
if (tx.IsCoinBase()) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); |
|
|
|
Object entry; |
|
|
|
ssTx << tx; |
|
|
|
|
|
|
|
entry.push_back(Pair("data", HexStr(ssTx.begin(), ssTx.end()))); |
|
|
|
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); |
|
|
|
|
|
|
|
ssTx << tx; |
|
|
|
|
|
|
|
entry.push_back(Pair("data", HexStr(ssTx.begin(), ssTx.end()))); |
|
|
|
|
|
|
|
|
|
|
|
entry.push_back(Pair("hash", txHash.GetHex())); |
|
|
|
entry.push_back(Pair("hash", txHash.GetHex())); |
|
|
|
|
|
|
|
|
|
|
|
MapPrevTx mapInputs; |
|
|
|
MapPrevTx mapInputs; |
|
|
|
map<uint256, CTxIndex> mapUnused; |
|
|
|
map<uint256, CTxIndex> mapUnused; |
|
|
|
bool fInvalid = false; |
|
|
|
bool fInvalid = false; |
|
|
|
if (tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid)) |
|
|
|
if (tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
entry.push_back(Pair("fee", (int64_t)(tx.GetValueIn(mapInputs) - tx.GetValueOut()))); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Array deps; |
|
|
|
|
|
|
|
BOOST_FOREACH (MapPrevTx::value_type& inp, mapInputs) |
|
|
|
{ |
|
|
|
{ |
|
|
|
entry.push_back(Pair("fee", (int64_t)(tx.GetValueIn(mapInputs) - tx.GetValueOut()))); |
|
|
|
if (setTxIndex.count(inp.first)) |
|
|
|
|
|
|
|
deps.push_back(setTxIndex[inp.first]); |
|
|
|
Array deps; |
|
|
|
|
|
|
|
BOOST_FOREACH (MapPrevTx::value_type& inp, mapInputs) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (setTxIndex.count(inp.first)) |
|
|
|
|
|
|
|
deps.push_back(setTxIndex[inp.first]); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
entry.push_back(Pair("depends", deps)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int64_t nSigOps = tx.GetLegacySigOpCount(); |
|
|
|
|
|
|
|
nSigOps += tx.GetP2SHSigOpCount(mapInputs); |
|
|
|
|
|
|
|
entry.push_back(Pair("sigops", nSigOps)); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
entry.push_back(Pair("depends", deps)); |
|
|
|
|
|
|
|
|
|
|
|
transactions.push_back(entry); |
|
|
|
int64_t nSigOps = tx.GetLegacySigOpCount(); |
|
|
|
|
|
|
|
nSigOps += tx.GetP2SHSigOpCount(mapInputs); |
|
|
|
|
|
|
|
entry.push_back(Pair("sigops", nSigOps)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Object aux; |
|
|
|
transactions.push_back(entry); |
|
|
|
aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()))); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); |
|
|
|
Object aux; |
|
|
|
|
|
|
|
aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()))); |
|
|
|
|
|
|
|
|
|
|
|
static Array aMutable; |
|
|
|
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); |
|
|
|
if (aMutable.empty()) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
aMutable.push_back("time"); |
|
|
|
|
|
|
|
aMutable.push_back("transactions"); |
|
|
|
|
|
|
|
aMutable.push_back("prevblock"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Object result; |
|
|
|
|
|
|
|
result.push_back(Pair("version", pblock->nVersion)); |
|
|
|
|
|
|
|
result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); |
|
|
|
|
|
|
|
result.push_back(Pair("transactions", transactions)); |
|
|
|
|
|
|
|
result.push_back(Pair("coinbaseaux", aux)); |
|
|
|
|
|
|
|
result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue)); |
|
|
|
|
|
|
|
result.push_back(Pair("target", hashTarget.GetHex())); |
|
|
|
|
|
|
|
result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); |
|
|
|
|
|
|
|
result.push_back(Pair("mutable", aMutable)); |
|
|
|
|
|
|
|
result.push_back(Pair("noncerange", "00000000ffffffff")); |
|
|
|
|
|
|
|
result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS)); |
|
|
|
|
|
|
|
result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE)); |
|
|
|
|
|
|
|
result.push_back(Pair("curtime", (int64_t)pblock->nTime)); |
|
|
|
|
|
|
|
result.push_back(Pair("bits", HexBits(pblock->nBits))); |
|
|
|
|
|
|
|
result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1))); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return result; |
|
|
|
static Array aMutable; |
|
|
|
|
|
|
|
if (aMutable.empty()) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
aMutable.push_back("time"); |
|
|
|
|
|
|
|
aMutable.push_back("transactions"); |
|
|
|
|
|
|
|
aMutable.push_back("prevblock"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Object result; |
|
|
|
|
|
|
|
result.push_back(Pair("version", pblock->nVersion)); |
|
|
|
|
|
|
|
result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); |
|
|
|
|
|
|
|
result.push_back(Pair("transactions", transactions)); |
|
|
|
|
|
|
|
result.push_back(Pair("coinbaseaux", aux)); |
|
|
|
|
|
|
|
result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue)); |
|
|
|
|
|
|
|
result.push_back(Pair("target", hashTarget.GetHex())); |
|
|
|
|
|
|
|
result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); |
|
|
|
|
|
|
|
result.push_back(Pair("mutable", aMutable)); |
|
|
|
|
|
|
|
result.push_back(Pair("noncerange", "00000000ffffffff")); |
|
|
|
|
|
|
|
result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS)); |
|
|
|
|
|
|
|
result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE)); |
|
|
|
|
|
|
|
result.push_back(Pair("curtime", (int64_t)pblock->nTime)); |
|
|
|
|
|
|
|
result.push_back(Pair("bits", HexBits(pblock->nBits))); |
|
|
|
|
|
|
|
result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1))); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Value submitblock(const Array& params, bool fHelp) |
|
|
|
Value submitblock(const Array& params, bool fHelp) |
|
|
|