Skip to content

Commit 0d8a229

Browse files
committed
getwork
1 parent b9450da commit 0d8a229

File tree

7 files changed

+220
-2
lines changed

7 files changed

+220
-2
lines changed

src/init.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ void Shutdown()
195195
StopHTTPRPC();
196196
StopREST();
197197
StopRPC();
198+
ShutdownRPCMining();
198199
StopHTTPServer();
199200
#ifdef ENABLE_WALLET
200201
if (pwalletMain)
@@ -1573,6 +1574,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
15731574
StartTorControl(threadGroup, scheduler);
15741575

15751576
StartNode(threadGroup, scheduler);
1577+
InitRPCMining();
15761578

15771579
// ********************************************************* Step 12: finished
15781580

src/miner.cpp

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,6 @@ CBlockTemplate* BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, bo
183183
coinbaseTx.vout[0].nValue = 0;
184184
*pStakeReward = nFees + GetProofOfStakeReward(nHeight, chainparams.GetConsensus());
185185
} else {
186-
187186
coinbaseTx.vout[0].scriptPubKey = scriptPubKeyIn;
188187
coinbaseTx.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus());
189188
}
@@ -622,6 +621,66 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned
622621
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
623622
}
624623

624+
/* Prepares a block header for transmission using RPC getwork */
625+
void FormatDataBuffer(CBlock *pblock, unsigned int *pdata) {
626+
unsigned int i;
627+
628+
struct {
629+
int nVersion;
630+
uint256 hashPrevBlock;
631+
uint256 hashMerkleRoot;
632+
unsigned int nTime;
633+
unsigned int nBits;
634+
unsigned int nNonce;
635+
} data;
636+
637+
data.nVersion = pblock->nVersion;
638+
data.hashPrevBlock = pblock->hashPrevBlock;
639+
data.hashMerkleRoot = pblock->hashMerkleRoot;
640+
data.nTime = pblock->nTime;
641+
data.nBits = pblock->nBits;
642+
data.nNonce = pblock->nNonce;
643+
644+
for (i = 0; i < 20; i++)
645+
pdata[i] = ((unsigned int *) &data)[i];
646+
}
647+
648+
bool CheckWork(const CChainParams& chainparams, CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) {
649+
uint256 hashBlock = pblock->GetHash();
650+
arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits);
651+
652+
if (!pblock->IsProofOfWork())
653+
return error("%s: %s height %d is not a proof-of-work block", __func__, hashBlock.GetHex());
654+
655+
uint256 hashProof = pblock->GetPoWHash();
656+
657+
if (UintToArith256(hashProof) > hashTarget)
658+
return error("%s: block %s height %d proof-of-work not meeting target", __func__, hashBlock.GetHex());
659+
660+
// Found a solution
661+
{
662+
LOCK(cs_main);
663+
if (pblock->hashPrevBlock != hashBestChain)
664+
return error("%s: generated block is stale", __func__);
665+
666+
// Remove key from key pool
667+
reservekey.KeepKey();
668+
669+
// Track how many getdata requests this block gets
670+
{
671+
LOCK(wallet.cs_wallet);
672+
wallet.mapRequestCount[hashBlock] = 0;
673+
}
674+
675+
// Process this block the same as if we had received it from another node
676+
CValidationState state;
677+
if (!ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL, false))
678+
return error("%s: ProcessBlock, block not accepted", __func__);
679+
}
680+
681+
return true;
682+
}
683+
625684
/**
626685
* Internal Staker
627686
*/

src/miner.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,13 @@ class BlockAssembler
209209

210210
/** Modify the extranonce in a block */
211211
void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
212+
213+
/** Prepares a block header for transmission using RPC getwork */
214+
void FormatDataBuffer(CBlock *pblock, unsigned int *pdata);
215+
216+
/** Check mined block */
217+
bool CheckWork(const CChainParams& chainparams, CBlock* pblock, CWallet& wallet, CReserveKey& reservekey);
218+
212219
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);
213220

214221
/** Sign proof-of-stake block */

src/rpc/client.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
7070
{ "listunspent", 0 },
7171
{ "listunspent", 1 },
7272
{ "listunspent", 2 },
73+
{ "getwork", 0 },
7374
{ "getblock", 1 },
7475
{ "getblockheader", 1 },
7576
{ "gettransaction", 1 },

src/rpc/mining.cpp

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
#include "util.h"
2222
#include "utilstrencodings.h"
2323
#include "validationinterface.h"
24+
#ifdef ENABLE_WALLET
25+
#include "wallet/wallet.h"
26+
#endif
2427

2528
#include <stdint.h>
2629

@@ -31,6 +34,36 @@
3134

3235
using namespace std;
3336

37+
#ifdef ENABLE_WALLET
38+
// Key used by getwork miners.
39+
// Allocated in InitRPCMining, free'd in ShutdownRPCMining
40+
static CReserveKey* pMiningKey = NULL;
41+
42+
void InitRPCMining()
43+
{
44+
if (!pwalletMain)
45+
return;
46+
47+
// getwork/getblocktemplate mining rewards paid here:
48+
pMiningKey = new CReserveKey(pwalletMain);
49+
}
50+
51+
void ShutdownRPCMining()
52+
{
53+
if (!pMiningKey)
54+
return;
55+
56+
delete pMiningKey; pMiningKey = NULL;
57+
}
58+
#else
59+
void InitRPCMining()
60+
{
61+
}
62+
void ShutdownRPCMining()
63+
{
64+
}
65+
#endif
66+
3467
/**
3568
* Return average network hashes per second based on the last 'lookup' blocks,
3669
* or from the last difficulty change if 'lookup' is nonpositive.
@@ -319,6 +352,118 @@ std::string gbt_vb_name(const Consensus::DeploymentPos pos) {
319352
return s;
320353
}
321354

355+
#ifdef ENABLE_WALLET
356+
UniValue getwork(const UniValue& params, bool fHelp)
357+
{
358+
if (fHelp || params.size() > 1)
359+
throw runtime_error(
360+
"getwork ( \"data\" )\n"
361+
"\nIf 'data' is not specified, it returns the formatted hash data to work on.\n"
362+
"If 'data' is specified, tries to solve the block and returns true if it was successful.\n"
363+
"\nArguments:\n"
364+
"1. \"data\" (string, optional) The hex encoded data to solve\n"
365+
"\nResult (when 'data' is not specified):\n"
366+
"{\n"
367+
" \"data\" : \"xxxxx\", (string) The block data\n"
368+
" \"target\" : \"xxxx\" (string) The little endian hash target\n"
369+
"}\n"
370+
"If [data] is specified, verifies the PoW hash against target and returns true if successful."
371+
"\nExamples:\n"
372+
+ HelpExampleCli("getwork", "")
373+
+ HelpExampleRpc("getwork", "")
374+
);
375+
376+
if (vNodes.empty())
377+
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Trezarcoin is not connected!");
378+
379+
if (IsInitialBlockDownload())
380+
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Trezarcoin is downloading blocks...");
381+
382+
typedef std::map<uint256, std::pair<CBlock*, CScript> > mapNewBlock_t;
383+
static mapNewBlock_t mapNewBlock; // FIXME: thread safety
384+
385+
static boost::shared_ptr<CReserveScript> coinbaseScript;
386+
387+
if (params.size() == 0)
388+
{
389+
// Update block
390+
static unsigned int nTransactionsUpdatedLast;
391+
static CBlockIndex* pindexPrev;
392+
static int64_t nStart;
393+
static CBlockTemplate* pblocktemplate;
394+
395+
if (pindexPrev != chainActive.Tip() ||
396+
(mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60))
397+
{
398+
if (pindexPrev != chainActive.Tip())
399+
mapNewBlock.clear();
400+
401+
// Clear pindexPrev so future getworks make a new block, despite any failures from here on
402+
pindexPrev = nullptr;
403+
404+
// Store the pindexBest used before CreateNewBlock, to avoid races
405+
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
406+
CBlockIndex* pindexPrevNew = chainActive.Tip();
407+
nStart = GetTime();
408+
409+
// Create new block
410+
GetMainSignals().ScriptForMining(coinbaseScript);
411+
pblocktemplate = BlockAssembler(Params()).CreateNewBlock(coinbaseScript->reserveScript);
412+
if (!pblocktemplate)
413+
throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
414+
415+
// Need to update only after we know CreateNewBlock succeeded
416+
pindexPrev = pindexPrevNew;
417+
}
418+
CBlock* pblock = &pblocktemplate->block; // pointer for convenience
419+
420+
// Update nTime
421+
UpdateTime(pblock, Params().GetConsensus(), pindexPrev);
422+
pblock->nNonce = 0;
423+
424+
// Update nExtraNonce
425+
static unsigned int nExtraNonce = 0;
426+
IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
427+
428+
// Save
429+
mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
430+
431+
// Pre-build hash buffers
432+
unsigned int pdata[32];
433+
FormatDataBuffer(pblock, pdata);
434+
435+
arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits);
436+
437+
UniValue result(UniValue::VOBJ);
438+
result.push_back(Pair("data", HexStr(BEGIN(pdata), (char *) &pdata[20])));
439+
result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
440+
441+
return result;
442+
}
443+
else
444+
{
445+
// Parse parameters
446+
vector<unsigned char> vchData = ParseHex(params[0].get_str());
447+
if (vchData.size() < 80)
448+
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
449+
CBlock* pdata = (CBlock*)&vchData[0];
450+
451+
// Get saved block
452+
if (!mapNewBlock.count(pdata->hashMerkleRoot))
453+
return false;
454+
CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
455+
456+
pblock->nTime = pdata->nTime;
457+
pblock->nNonce = pdata->nNonce;
458+
pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
459+
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
460+
461+
assert(pwalletMain != NULL);
462+
return CheckWork(Params(), pblock, *pwalletMain, *pMiningKey);
463+
}
464+
}
465+
#endif
466+
322467
UniValue getblocktemplate(const UniValue& params, bool fHelp)
323468
{
324469
if (fHelp || params.size() > 1)
@@ -942,6 +1087,7 @@ static const CRPCCommand commands[] =
9421087
{ "mining", "getmininginfo", &getmininginfo, true },
9431088
{ "mining", "prioritisetransaction", &prioritisetransaction, true },
9441089
{ "mining", "getblocktemplate", &getblocktemplate, true },
1090+
{ "mining", "getwork", &getwork, true },
9451091
{ "mining", "submitblock", &submitblock, true },
9461092

9471093
{ "generating", "staking", &staking, true },

src/rpc/server.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ void JSONRequest::parse(const UniValue& valRequest)
372372
if (!valMethod.isStr())
373373
throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
374374
strMethod = valMethod.get_str();
375-
if (strMethod != "getblocktemplate")
375+
if (strMethod != "getwork" && strMethod != "getblocktemplate")
376376
LogPrint("rpc", "ThreadRPCServer method=%s\n", SanitizeString(strMethod));
377377

378378
// Parse params

src/rpc/server.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,9 @@ extern uint256 ParseHashO(const UniValue& o, std::string strKey);
182182
extern std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName);
183183
extern std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey);
184184

185+
extern void InitRPCMining();
186+
extern void ShutdownRPCMining();
187+
185188
extern int64_t nWalletUnlockTime;
186189
extern CAmount AmountFromValue(const UniValue& value);
187190
extern UniValue ValueFromAmount(const CAmount& amount);

0 commit comments

Comments
 (0)