diff --git a/src/init.cpp b/src/init.cpp index c4e3573de..b9510bec9 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -156,8 +156,8 @@ void Shutdown() #ifdef ENABLE_WALLET if (pwalletMain) pwalletMain->Flush(false); - GenerateBitcoins(false, NULL, 0); #endif + GenerateBitcoins(false, 0, Params()); StopNode(); UnregisterNodeSignals(GetNodeSignals()); @@ -370,10 +370,8 @@ std::string HelpMessage(HelpMessageMode mode) debugCategories += ", qt"; strUsage += HelpMessageOpt("-debug=", strprintf(_("Output debugging information (default: %u, supplying is optional)"), 0) + ". " + _("If is not supplied or if = 1, output all debugging information.") + _(" can be:") + " " + debugCategories + "."); -#ifdef ENABLE_WALLET strUsage += HelpMessageOpt("-gen", strprintf(_("Generate coins (default: %u)"), 0)); strUsage += HelpMessageOpt("-genproclimit=", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), 1)); -#endif strUsage += HelpMessageOpt("-help-debug", _("Show all debugging options (usage: --help -help-debug)")); strUsage += HelpMessageOpt("-logips", strprintf(_("Include IP addresses in debug output (default: %u)"), 0)); strUsage += HelpMessageOpt("-logtimestamps", strprintf(_("Prepend debug output with timestamp (default: %u)"), 1)); @@ -1439,11 +1437,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) boost::ref(cs_main), boost::cref(pindexBestHeader), nPowTargetSpacing); scheduler.scheduleEvery(f, nPowTargetSpacing); -#ifdef ENABLE_WALLET // Generate coins in the background - if (pwalletMain) - GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain, GetArg("-genproclimit", 1)); -#endif + GenerateBitcoins(GetBoolArg("-gen", false), GetArg("-genproclimit", 1), Params()); // ********************************************************* Step 11: finished diff --git a/src/miner.cpp b/src/miner.cpp index f5919ca3a..2c5cba742 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -17,9 +17,7 @@ #include "timedata.h" #include "util.h" #include "utilmoneystr.h" -#ifdef ENABLE_WALLET -#include "wallet/wallet.h" -#endif +#include "validationinterface.h" #include #include @@ -362,7 +360,6 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& pblock->hashMerkleRoot = pblock->BuildMerkleTree(); } -#ifdef ENABLE_WALLET ////////////////////////////////////////////////////////////////////////////// // // Internal miner @@ -401,17 +398,7 @@ bool static ScanHash(const CBlockHeader *pblock, uint32_t& nNonce, uint256 *phas } } -CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey) -{ - CPubKey pubkey; - if (!reservekey.GetReservedKey(pubkey)) - return NULL; - - CScript scriptPubKey = CScript() << ToByteVector(pubkey) << OP_CHECKSIG; - return CreateNewBlock(scriptPubKey); -} - -static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) +static bool ProcessBlockFound(CBlock* pblock, const CChainParams& chainparams) { LogPrintf("%s\n", pblock->ToString()); LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue)); @@ -423,14 +410,8 @@ static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& rese return error("BitcoinMiner: generated block is stale"); } - // Remove key from key pool - reservekey.KeepKey(); - - // Track how many getdata requests this block gets - { - LOCK(wallet.cs_wallet); - wallet.mapRequestCount[pblock->GetHash()] = 0; - } + // Inform about the new block + GetMainSignals().BlockFound(pblock->GetHash()); // Process this block the same as if we had received it from another node CValidationState state; @@ -440,18 +421,22 @@ static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& rese return true; } -void static BitcoinMiner(CWallet *pwallet) +void static BitcoinMiner(const CChainParams& chainparams) { LogPrintf("BitcoinMiner started\n"); SetThreadPriority(THREAD_PRIORITY_LOWEST); RenameThread("bitcoin-miner"); - const CChainParams& chainparams = Params(); - // Each thread has its own key and counter - CReserveKey reservekey(pwallet); unsigned int nExtraNonce = 0; + boost::shared_ptr coinbaseScript; + GetMainSignals().ScriptForMining(coinbaseScript); + try { + //throw an error if no script was provided + if (!coinbaseScript->reserveScript.size()) + throw std::runtime_error("No coinbase script available (mining requires a wallet)"); + while (true) { if (chainparams.MiningRequiresPeers()) { // Busy-wait for the network to come online so we don't waste time mining @@ -474,7 +459,7 @@ void static BitcoinMiner(CWallet *pwallet) unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); CBlockIndex* pindexPrev = chainActive.Tip(); - auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey)); + auto_ptr pblocktemplate(CreateNewBlock(coinbaseScript->reserveScript)); if (!pblocktemplate.get()) { LogPrintf("Error in BitcoinMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n"); @@ -506,8 +491,9 @@ void static BitcoinMiner(CWallet *pwallet) SetThreadPriority(THREAD_PRIORITY_NORMAL); LogPrintf("BitcoinMiner:\n"); LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex(), hashTarget.GetHex()); - ProcessBlockFound(pblock, *pwallet, reservekey); + ProcessBlockFound(pblock, chainparams); SetThreadPriority(THREAD_PRIORITY_LOWEST); + coinbaseScript->KeepScript(); // In regression test mode, stop mining after a block is found. if (chainparams.MineBlocksOnDemand()) @@ -551,7 +537,7 @@ void static BitcoinMiner(CWallet *pwallet) } } -void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads) +void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams) { static boost::thread_group* minerThreads = NULL; @@ -575,7 +561,5 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads) minerThreads = new boost::thread_group(); for (int i = 0; i < nThreads; i++) - minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet)); + minerThreads->create_thread(boost::bind(&BitcoinMiner, boost::cref(chainparams))); } - -#endif // ENABLE_WALLET diff --git a/src/miner.h b/src/miner.h index 96a6b70ec..777a09196 100644 --- a/src/miner.h +++ b/src/miner.h @@ -11,6 +11,7 @@ #include class CBlockIndex; +class CChainParams; class CReserveKey; class CScript; class CWallet; @@ -24,10 +25,9 @@ struct CBlockTemplate }; /** Run the miner threads */ -void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads); +void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams); /** Generate a new block, without valid proof-of-work */ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn); -CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey); /** Modify the extranonce in a block */ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce); void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev); diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index f33281461..9c6fb10af 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -16,13 +16,11 @@ #include "rpcserver.h" #include "util.h" #include "validationinterface.h" -#ifdef ENABLE_WALLET -#include "wallet/wallet.h" -#endif #include #include +#include #include "univalue/univalue.h" @@ -92,7 +90,6 @@ UniValue getnetworkhashps(const UniValue& params, bool fHelp) return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1); } -#ifdef ENABLE_WALLET UniValue getgenerate(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -127,8 +124,6 @@ UniValue generate(const UniValue& params, bool fHelp) + HelpExampleCli("generate", "11") ); - if (pwalletMain == NULL) - throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)"); if (!Params().MineBlocksOnDemand()) throw JSONRPCError(RPC_METHOD_NOT_FOUND, "This method can only be used on regtest"); @@ -136,7 +131,13 @@ UniValue generate(const UniValue& params, bool fHelp) int nHeightEnd = 0; int nHeight = 0; int nGenerate = params[0].get_int(); - CReserveKey reservekey(pwalletMain); + + boost::shared_ptr coinbaseScript; + GetMainSignals().ScriptForMining(coinbaseScript); + + //throw an error if no script was provided + if (!coinbaseScript->reserveScript.size()) + throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)"); { // Don't keep cs_main locked LOCK(cs_main); @@ -148,9 +149,9 @@ UniValue generate(const UniValue& params, bool fHelp) UniValue blockHashes(UniValue::VARR); while (nHeight < nHeightEnd) { - auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey)); + auto_ptr pblocktemplate(CreateNewBlock(coinbaseScript->reserveScript)); if (!pblocktemplate.get()) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty"); + throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); CBlock *pblock = &pblocktemplate->block; { LOCK(cs_main); @@ -166,11 +167,13 @@ UniValue generate(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); ++nHeight; blockHashes.push_back(pblock->GetHash().GetHex()); + + //mark script as important because it was used at least for one coinbase output + coinbaseScript->KeepScript(); } return blockHashes; } - UniValue setgenerate(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) @@ -193,8 +196,6 @@ UniValue setgenerate(const UniValue& params, bool fHelp) + HelpExampleRpc("setgenerate", "true, 1") ); - if (pwalletMain == NULL) - throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)"); if (Params().MineBlocksOnDemand()) throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Use the generate method instead of setgenerate on this network"); @@ -212,12 +213,10 @@ UniValue setgenerate(const UniValue& params, bool fHelp) mapArgs["-gen"] = (fGenerate ? "1" : "0"); mapArgs ["-genproclimit"] = itostr(nGenProcLimit); - GenerateBitcoins(fGenerate, pwalletMain, nGenProcLimit); + GenerateBitcoins(fGenerate, nGenProcLimit, Params()); return NullUniValue; } -#endif - UniValue getmininginfo(const UniValue& params, bool fHelp) { @@ -257,9 +256,7 @@ UniValue getmininginfo(const UniValue& params, bool fHelp) obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); obj.push_back(Pair("chain", Params().NetworkIDString())); -#ifdef ENABLE_WALLET obj.push_back(Pair("generate", getgenerate(params, false))); -#endif return obj; } diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 2f2897158..840bf57c2 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -306,12 +306,10 @@ static const CRPCCommand vRPCCommands[] = { "mining", "prioritisetransaction", &prioritisetransaction, true }, { "mining", "submitblock", &submitblock, true }, -#ifdef ENABLE_WALLET /* Coin generation */ { "generating", "getgenerate", &getgenerate, true }, { "generating", "setgenerate", &setgenerate, true }, { "generating", "generate", &generate, true }, -#endif /* Raw transactions */ { "rawtransactions", "createrawtransaction", &createrawtransaction, true }, diff --git a/src/script/script.h b/src/script/script.h index c09899aab..e39ca57f4 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -609,4 +609,13 @@ public: } }; +class CReserveScript +{ +public: + CScript reserveScript; + virtual void KeepScript() {} + CReserveScript() {} + virtual ~CReserveScript() {} +}; + #endif // BITCOIN_SCRIPT_SCRIPT_H diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 0532da5f3..d365f0300 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -19,9 +19,13 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1)); g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); + g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1)); + g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1)); } void UnregisterValidationInterface(CValidationInterface* pwalletIn) { + g_signals.BlockFound.disconnect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1)); + g_signals.ScriptForMining.disconnect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1)); g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1)); g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); @@ -31,6 +35,8 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) { } void UnregisterAllValidationInterfaces() { + g_signals.BlockFound.disconnect_all_slots(); + g_signals.ScriptForMining.disconnect_all_slots(); g_signals.BlockChecked.disconnect_all_slots(); g_signals.Broadcast.disconnect_all_slots(); g_signals.Inventory.disconnect_all_slots(); diff --git a/src/validationinterface.h b/src/validationinterface.h index a911d1efe..fb0ce0bda 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -7,9 +7,11 @@ #define BITCOIN_VALIDATIONINTERFACE_H #include +#include class CBlock; struct CBlockLocator; +class CReserveScript; class CTransaction; class CValidationInterface; class CValidationState; @@ -34,6 +36,8 @@ protected: virtual void Inventory(const uint256 &hash) {} virtual void ResendWalletTransactions(int64_t nBestBlockTime) {} virtual void BlockChecked(const CBlock&, const CValidationState&) {} + virtual void GetScriptForMining(boost::shared_ptr&) {}; + virtual void ResetRequestCount(const uint256 &hash) {}; friend void ::RegisterValidationInterface(CValidationInterface*); friend void ::UnregisterValidationInterface(CValidationInterface*); friend void ::UnregisterAllValidationInterfaces(); @@ -52,6 +56,10 @@ struct CMainSignals { boost::signals2::signal Broadcast; /** Notifies listeners of a block validation result */ boost::signals2::signal BlockChecked; + /** Notifies listeners that a key for mining is required (coinbase) */ + boost::signals2::signal&)> ScriptForMining; + /** Notifies listeners that a block has been successfully mined */ + boost::signals2::signal BlockFound; }; CMainSignals& GetMainSignals(); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index eee57900b..238f62a57 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2583,6 +2583,17 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx) } } +void CWallet::GetScriptForMining(boost::shared_ptr &script) +{ + boost::shared_ptr rKey(new CReserveKey(this)); + CPubKey pubkey; + if (!rKey->GetReservedKey(pubkey)) + return; + + script = rKey; + script->reserveScript = CScript() << ToByteVector(pubkey) << OP_CHECKSIG; +} + void CWallet::LockCoin(COutPoint& output) { AssertLockHeld(cs_wallet); // setLockedCoins diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index b6a8e8671..f36c98e9f 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -28,6 +28,8 @@ #include #include +#include + /** * Settings */ @@ -680,6 +682,13 @@ public: } } + void GetScriptForMining(boost::shared_ptr &script); + void ResetRequestCount(const uint256 &hash) + { + LOCK(cs_wallet); + mapRequestCount[hash] = 0; + }; + unsigned int GetKeyPoolSize() { AssertLockHeld(cs_wallet); // setKeyPool @@ -735,7 +744,7 @@ public: }; /** A key allocated from the key pool. */ -class CReserveKey +class CReserveKey : public CReserveScript { protected: CWallet* pwallet; @@ -756,6 +765,7 @@ public: void ReturnKey(); bool GetReservedKey(CPubKey &pubkey); void KeepKey(); + void KeepScript() { KeepKey(); } };