|
|
|
@ -24,36 +24,6 @@
|
|
|
|
|
using namespace json_spirit;
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_WALLET
|
|
|
|
|
// Key used by getwork miners.
|
|
|
|
|
// Allocated in InitRPCMining, free'd in ShutdownRPCMining
|
|
|
|
|
static CReserveKey* pMiningKey = NULL;
|
|
|
|
|
|
|
|
|
|
void InitRPCMining()
|
|
|
|
|
{
|
|
|
|
|
if (!pwalletMain)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// getwork/getblocktemplate mining rewards paid here:
|
|
|
|
|
pMiningKey = new CReserveKey(pwalletMain);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ShutdownRPCMining()
|
|
|
|
|
{
|
|
|
|
|
if (!pMiningKey)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
delete pMiningKey; pMiningKey = NULL;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
void InitRPCMining()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
void ShutdownRPCMining()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Return average network hashes per second based on the last 'lookup' blocks,
|
|
|
|
|
// or from the last difficulty change if 'lookup' is nonpositive.
|
|
|
|
|
// If 'height' is nonnegative, compute the estimate at the time when a given block was found.
|
|
|
|
@ -131,9 +101,6 @@ Value getgenerate(const Array& params, bool fHelp)
|
|
|
|
|
+ HelpExampleRpc("getgenerate", "")
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (!pMiningKey)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return GetBoolArg("-gen", false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -279,132 +246,6 @@ Value getmininginfo(const Array& params, bool fHelp)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_WALLET
|
|
|
|
|
Value getwork(const Array& params, bool fHelp)
|
|
|
|
|
{
|
|
|
|
|
if (fHelp || params.size() > 1)
|
|
|
|
|
throw runtime_error(
|
|
|
|
|
"getwork ( \"data\" )\n"
|
|
|
|
|
"\nIf 'data' is not specified, it returns the formatted hash data to work on.\n"
|
|
|
|
|
"If 'data' is specified, tries to solve the block and returns true if it was successful.\n"
|
|
|
|
|
"\nArguments:\n"
|
|
|
|
|
"1. \"data\" (string, optional) The hex encoded data to solve\n"
|
|
|
|
|
"\nResult (when 'data' is not specified):\n"
|
|
|
|
|
"{\n"
|
|
|
|
|
" \"midstate\" : \"xxxx\", (string) The precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
|
|
|
|
|
" \"data\" : \"xxxxx\", (string) The block data\n"
|
|
|
|
|
" \"hash1\" : \"xxxxx\", (string) The formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
|
|
|
|
|
" \"target\" : \"xxxx\" (string) The little endian hash target\n"
|
|
|
|
|
"}\n"
|
|
|
|
|
"\nResult (when 'data' is specified):\n"
|
|
|
|
|
"true|false (boolean) If solving the block specified in the 'data' was successfull\n"
|
|
|
|
|
"\nExamples:\n"
|
|
|
|
|
+ HelpExampleCli("getwork", "")
|
|
|
|
|
+ HelpExampleRpc("getwork", "")
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (vNodes.empty())
|
|
|
|
|
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Bitcoin is not connected!");
|
|
|
|
|
|
|
|
|
|
if (IsInitialBlockDownload())
|
|
|
|
|
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Bitcoin is downloading blocks...");
|
|
|
|
|
|
|
|
|
|
typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
|
|
|
|
|
static mapNewBlock_t mapNewBlock; // FIXME: thread safety
|
|
|
|
|
static vector<CBlockTemplate*> vNewBlockTemplate;
|
|
|
|
|
|
|
|
|
|
if (params.size() == 0)
|
|
|
|
|
{
|
|
|
|
|
// Update block
|
|
|
|
|
static unsigned int nTransactionsUpdatedLast;
|
|
|
|
|
static CBlockIndex* pindexPrev;
|
|
|
|
|
static int64_t nStart;
|
|
|
|
|
static CBlockTemplate* pblocktemplate;
|
|
|
|
|
if (pindexPrev != chainActive.Tip() ||
|
|
|
|
|
(mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60))
|
|
|
|
|
{
|
|
|
|
|
if (pindexPrev != chainActive.Tip())
|
|
|
|
|
{
|
|
|
|
|
// Deallocate old blocks since they're obsolete now
|
|
|
|
|
mapNewBlock.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
|
|
|
|
|
pindexPrev = NULL;
|
|
|
|
|
|
|
|
|
|
// Store the pindexBest used before CreateNewBlock, to avoid races
|
|
|
|
|
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
|
|
|
|
|
CBlockIndex* pindexPrevNew = chainActive.Tip();
|
|
|
|
|
nStart = GetTime();
|
|
|
|
|
|
|
|
|
|
// Create new block
|
|
|
|
|
pblocktemplate = CreateNewBlockWithKey(*pMiningKey);
|
|
|
|
|
if (!pblocktemplate)
|
|
|
|
|
throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
|
|
|
|
|
vNewBlockTemplate.push_back(pblocktemplate);
|
|
|
|
|
|
|
|
|
|
// Need to update only after we know CreateNewBlock succeeded
|
|
|
|
|
pindexPrev = pindexPrevNew;
|
|
|
|
|
}
|
|
|
|
|
CBlock* pblock = &pblocktemplate->block; // pointer for convenience
|
|
|
|
|
|
|
|
|
|
// Update nTime
|
|
|
|
|
UpdateTime(*pblock, pindexPrev);
|
|
|
|
|
pblock->nNonce = 0;
|
|
|
|
|
|
|
|
|
|
// Update nExtraNonce
|
|
|
|
|
static unsigned int nExtraNonce = 0;
|
|
|
|
|
IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
|
|
|
|
|
|
|
|
|
|
// Save
|
|
|
|
|
mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
|
|
|
|
|
|
|
|
|
|
// Pre-build hash buffers
|
|
|
|
|
char pmidstate[32];
|
|
|
|
|
char pdata[128];
|
|
|
|
|
char phash1[64];
|
|
|
|
|
FormatHashBuffers(pblock, pmidstate, pdata, phash1);
|
|
|
|
|
|
|
|
|
|
uint256 hashTarget = uint256().SetCompact(pblock->nBits);
|
|
|
|
|
|
|
|
|
|
Object result;
|
|
|
|
|
result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
|
|
|
|
|
result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
|
|
|
|
|
result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
|
|
|
|
|
result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Parse parameters
|
|
|
|
|
vector<unsigned char> vchData = ParseHex(params[0].get_str());
|
|
|
|
|
if (vchData.size() != 128)
|
|
|
|
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
|
|
|
|
|
CBlock* pdata = (CBlock*)&vchData[0];
|
|
|
|
|
|
|
|
|
|
// Byte reverse
|
|
|
|
|
for (int i = 0; i < 128/4; i++)
|
|
|
|
|
((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
|
|
|
|
|
|
|
|
|
|
// Get saved block
|
|
|
|
|
if (!mapNewBlock.count(pdata->hashMerkleRoot))
|
|
|
|
|
return false;
|
|
|
|
|
CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
|
|
|
|
|
|
|
|
|
|
pblock->nTime = pdata->nTime;
|
|
|
|
|
pblock->nNonce = pdata->nNonce;
|
|
|
|
|
pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
|
|
|
|
|
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
|
|
|
|
|
|
|
|
|
|
assert(pwalletMain != NULL);
|
|
|
|
|
return CheckWork(pblock, *pwalletMain, *pMiningKey);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
Value getblocktemplate(const Array& params, bool fHelp)
|
|
|
|
|
{
|
|
|
|
|
if (fHelp || params.size() > 1)
|
|
|
|
|