aboutsummaryrefslogtreecommitdiff
path: root/src/rpcmining.cpp
diff options
context:
space:
mode:
authorPatrick Lodder <[email protected]>2015-07-11 14:41:33 +0200
committerPatrick Lodder <[email protected]>2015-07-11 14:41:33 +0200
commitb66e509800025bbcd90f518b90f3b7cb582b99db (patch)
tree0422e17d73ffc244e48ba41c4ea63cd39c8b09dd /src/rpcmining.cpp
parentMerge pull request #1199 from patricklodder/1.10-partition-alert (diff)
parentAdapt AuxPoW to Dogecoin (diff)
downloaddiscoin-b66e509800025bbcd90f518b90f3b7cb582b99db.tar.xz
discoin-b66e509800025bbcd90f518b90f3b7cb582b99db.zip
Merge pull request #1200 from rnicoll/1.10-auxpow-clean
Add AuxPoW support
Diffstat (limited to 'src/rpcmining.cpp')
-rw-r--r--src/rpcmining.cpp191
1 files changed, 189 insertions, 2 deletions
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index 528d5406f..7eee8bb05 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -8,6 +8,7 @@
#include "consensus/consensus.h"
#include "consensus/validation.h"
#include "core_io.h"
+#include "dogecoin.h"
#include "init.h"
#include "main.h"
#include "miner.h"
@@ -158,7 +159,7 @@ Value generate(const Array& params, bool fHelp)
LOCK(cs_main);
IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce);
}
- while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) {
+ while (!CheckProofOfWork(pblock->GetPoWHash(), pblock->nBits, Params().GetConsensus())) {
// Yes, there is a chance every nonce could fail to satisfy the -regtest
// target -- 1 in 2^(2^32). That ain't gonna happen.
++pblock->nNonce;
@@ -569,7 +570,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
Object result;
result.push_back(Pair("capabilities", aCaps));
- result.push_back(Pair("version", pblock->nVersion));
+ result.push_back(Pair("version", pblock->nVersion.GetFullVersion()));
result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
result.push_back(Pair("transactions", transactions));
result.push_back(Pair("coinbaseaux", aux));
@@ -726,3 +727,189 @@ Value estimatepriority(const Array& params, bool fHelp)
return mempool.estimatePriority(nBlocks);
}
+
+/* ************************************************************************** */
+/* Merge mining. */
+
+#ifdef ENABLE_WALLET
+Value getauxblock(const Array& params, bool fHelp)
+{
+ if (fHelp || (params.size() != 0 && params.size() != 2))
+ throw std::runtime_error(
+ "getauxblock (hash auxpow)\n"
+ "\nCreate or submit a merge-mined block.\n"
+ "\nWithout arguments, create a new block and return information\n"
+ "required to merge-mine it. With arguments, submit a solved\n"
+ "auxpow for a previously returned block.\n"
+ "\nArguments:\n"
+ "1. \"hash\" (string, optional) hash of the block to submit\n"
+ "2. \"auxpow\" (string, optional) serialised auxpow found\n"
+ "\nResult (without arguments):\n"
+ "{\n"
+ " \"hash\" (string) hash of the created block\n"
+ " \"chainid\" (numeric) chain ID for this block\n"
+ " \"previousblockhash\" (string) hash of the previous block\n"
+ " \"coinbasevalue\" (numeric) value of the block's coinbase\n"
+ " \"bits\" (string) compressed target of the block\n"
+ " \"height\" (numeric) height of the block\n"
+ " \"_target\" (string) target in reversed byte order, deprecated\n"
+ "}\n"
+ "\nResult (with arguments):\n"
+ "xxxxx (boolean) whether the submitted block was correct\n"
+ "\nExamples:\n"
+ + HelpExampleCli("getauxblock", "")
+ + HelpExampleCli("getauxblock", "\"hash\" \"serialised auxpow\"")
+ + HelpExampleRpc("getauxblock", "")
+ );
+
+ if (pwalletMain == NULL)
+ throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
+
+ if (vNodes.empty() && !Params().MineBlocksOnDemand())
+ throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED,
+ "Namecoin is not connected!");
+
+ if (IsInitialBlockDownload() && !Params().MineBlocksOnDemand())
+ throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD,
+ "Namecoin is downloading blocks...");
+
+ /* This should never fail, since the chain is already
+ past the point of merge-mining start. Check nevertheless. */
+ {
+ LOCK(cs_main);
+ if (chainActive.Height() + 1 < Params().GetConsensus().nAuxpowStartHeight)
+ throw std::runtime_error("getauxblock method is not yet available");
+ }
+
+ /* The variables below are used to keep track of created and not yet
+ submitted auxpow blocks. Lock them, just in case. In principle
+ there's only one RPC thread, so it should be fine without locking
+ as well. But it cannot hurt to be safe. */
+ static CCriticalSection cs_auxblockCache;
+ LOCK(cs_auxblockCache);
+ static std::map<uint256, CBlock*> mapNewBlock;
+ static std::vector<CBlockTemplate*> vNewBlockTemplate;
+
+ /* Create a new block? */
+ if (params.size() == 0)
+ {
+ static unsigned nTransactionsUpdatedLast;
+ static const CBlockIndex* pindexPrev = NULL;
+ static uint64_t nStart;
+ static CBlockTemplate* pblocktemplate;
+ static unsigned nExtraNonce = 0;
+ CReserveKey reservekey(pwalletMain);
+
+ // Update block
+ {
+ LOCK(cs_main);
+ 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* pbt, vNewBlockTemplate)
+ delete pbt;
+ vNewBlockTemplate.clear();
+ }
+
+ // Create new block with nonce = 0 and extraNonce = 1
+ pblocktemplate = CreateNewBlockWithKey(reservekey);
+ if (!pblocktemplate)
+ throw JSONRPCError(RPC_OUT_OF_MEMORY, "out of memory");
+
+ // Update state only when CreateNewBlock succeeded
+ nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
+ pindexPrev = chainActive.Tip();
+ nStart = GetTime();
+
+ // Finalise it by setting the version and building the merkle root
+ CBlock* pblock = &pblocktemplate->block;
+ IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
+ pblock->nVersion.SetAuxpow(true);
+ pblock->hashMerkleRoot = pblock->BuildMerkleTree();
+
+ // Save
+ mapNewBlock[pblock->GetHash()] = pblock;
+ vNewBlockTemplate.push_back(pblocktemplate);
+ }
+ }
+
+ const CBlock& block = pblocktemplate->block;
+
+ arith_uint256 target;
+ bool fNegative, fOverflow;
+ target.SetCompact(block.nBits, &fNegative, &fOverflow);
+ if (fNegative || fOverflow || target == 0)
+ throw std::runtime_error("invalid difficulty bits in block");
+
+ json_spirit::Object result;
+ result.push_back(Pair("hash", block.GetHash().GetHex()));
+ result.push_back(Pair("chainid", block.nVersion.GetChainId()));
+ result.push_back(Pair("previousblockhash", block.hashPrevBlock.GetHex()));
+ result.push_back(Pair("coinbasevalue", (int64_t)block.vtx[0].vout[0].nValue));
+ result.push_back(Pair("bits", strprintf("%08x", block.nBits)));
+ result.push_back(Pair("height", static_cast<int64_t> (pindexPrev->nHeight + 1)));
+ result.push_back(Pair("_target", HexStr(BEGIN(target), END(target))));
+
+ return result;
+ }
+
+ /* Submit a block instead. Note that this need not lock cs_main,
+ since ProcessBlockFound below locks it instead. */
+
+ assert(params.size() == 2);
+ uint256 hash;
+ hash.SetHex(params[0].get_str());
+
+ const std::map<uint256, CBlock*>::iterator mit = mapNewBlock.find(hash);
+ if (mit == mapNewBlock.end())
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "block hash unknown");
+ CBlock& block = *mit->second;
+
+ const std::vector<unsigned char> vchAuxPow = ParseHex(params[1].get_str());
+ CDataStream ss(vchAuxPow, SER_GETHASH, PROTOCOL_VERSION);
+ CAuxPow pow;
+ ss >> pow;
+ block.SetAuxpow(new CAuxPow(pow));
+ assert(block.GetHash() == hash);
+
+ // This is a straight cut & paste job from submitblock()
+ bool fBlockPresent = false;
+ {
+ LOCK(cs_main);
+ BlockMap::iterator mi = mapBlockIndex.find(hash);
+ if (mi != mapBlockIndex.end()) {
+ CBlockIndex *pindex = mi->second;
+ if (pindex->IsValid(BLOCK_VALID_SCRIPTS))
+ return "duplicate";
+ if (pindex->nStatus & BLOCK_FAILED_MASK)
+ return "duplicate-invalid";
+ // Otherwise, we might only have the header - process the block before returning
+ fBlockPresent = true;
+ }
+ }
+
+ CValidationState state;
+ submitblock_StateCatcher sc(block.GetHash());
+ RegisterValidationInterface(&sc);
+ bool fAccepted = ProcessNewBlock(state, NULL, &block, true, NULL);
+ UnregisterValidationInterface(&sc);
+ if (fBlockPresent)
+ {
+ if (fAccepted && !sc.found)
+ return "duplicate-inconclusive";
+ return "duplicate";
+ }
+ if (fAccepted)
+ {
+ if (!sc.found)
+ return "inconclusive";
+ state = sc.state;
+ }
+ return BIP22ValidationResult(state);
+}
+#endif // ENABLE_WALLET