add CReserveScript to allow modular script keeping/returning

- use one CReserveScript per mining thread
This commit is contained in:
Jonas Schnelli 2015-07-01 08:32:30 +02:00
parent 087e65def9
commit 5496253966
6 changed files with 42 additions and 23 deletions

View file

@ -421,7 +421,7 @@ static bool ProcessBlockFound(CBlock* pblock, const CChainParams& chainparams)
return true; return true;
} }
void static BitcoinMiner(const CChainParams& chainparams, const CScript& coinbaseScript) void static BitcoinMiner(const CChainParams& chainparams)
{ {
LogPrintf("BitcoinMiner started\n"); LogPrintf("BitcoinMiner started\n");
SetThreadPriority(THREAD_PRIORITY_LOWEST); SetThreadPriority(THREAD_PRIORITY_LOWEST);
@ -429,7 +429,14 @@ void static BitcoinMiner(const CChainParams& chainparams, const CScript& coinbas
unsigned int nExtraNonce = 0; unsigned int nExtraNonce = 0;
boost::shared_ptr<CReserveScript> coinbaseScript;
GetMainSignals().ScriptForMining(coinbaseScript);
try { 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) { while (true) {
if (chainparams.MiningRequiresPeers()) { if (chainparams.MiningRequiresPeers()) {
// Busy-wait for the network to come online so we don't waste time mining // Busy-wait for the network to come online so we don't waste time mining
@ -452,7 +459,7 @@ void static BitcoinMiner(const CChainParams& chainparams, const CScript& coinbas
unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
CBlockIndex* pindexPrev = chainActive.Tip(); CBlockIndex* pindexPrev = chainActive.Tip();
auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(coinbaseScript)); auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(coinbaseScript->reserveScript));
if (!pblocktemplate.get()) if (!pblocktemplate.get())
{ {
LogPrintf("Error in BitcoinMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n"); LogPrintf("Error in BitcoinMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n");
@ -486,6 +493,7 @@ void static BitcoinMiner(const CChainParams& chainparams, const CScript& coinbas
LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex(), hashTarget.GetHex()); LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex(), hashTarget.GetHex());
ProcessBlockFound(pblock, chainparams); ProcessBlockFound(pblock, chainparams);
SetThreadPriority(THREAD_PRIORITY_LOWEST); SetThreadPriority(THREAD_PRIORITY_LOWEST);
coinbaseScript->KeepScript();
// In regression test mode, stop mining after a block is found. // In regression test mode, stop mining after a block is found.
if (chainparams.MineBlocksOnDemand()) if (chainparams.MineBlocksOnDemand())
@ -551,14 +559,7 @@ void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainpar
if (nThreads == 0 || !fGenerate) if (nThreads == 0 || !fGenerate)
return; return;
CScript coinbaseScript;
GetMainSignals().ScriptForMining(coinbaseScript);
//throw an error if no script was provided
if (!coinbaseScript.size())
throw std::runtime_error("No coinbase script available (mining requires a wallet)");
minerThreads = new boost::thread_group(); minerThreads = new boost::thread_group();
for (int i = 0; i < nThreads; i++) for (int i = 0; i < nThreads; i++)
minerThreads->create_thread(boost::bind(&BitcoinMiner, boost::cref(chainparams), coinbaseScript)); minerThreads->create_thread(boost::bind(&BitcoinMiner, boost::cref(chainparams)));
} }

View file

@ -20,6 +20,7 @@
#include <stdint.h> #include <stdint.h>
#include <boost/assign/list_of.hpp> #include <boost/assign/list_of.hpp>
#include <boost/shared_ptr.hpp>
#include "univalue/univalue.h" #include "univalue/univalue.h"
@ -131,11 +132,11 @@ UniValue generate(const UniValue& params, bool fHelp)
int nHeight = 0; int nHeight = 0;
int nGenerate = params[0].get_int(); int nGenerate = params[0].get_int();
CScript coinbaseScript; boost::shared_ptr<CReserveScript> coinbaseScript;
GetMainSignals().ScriptForMining(coinbaseScript); GetMainSignals().ScriptForMining(coinbaseScript);
//throw an error if no script was provided //throw an error if no script was provided
if (!coinbaseScript.size()) if (!coinbaseScript->reserveScript.size())
throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)"); throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)");
{ // Don't keep cs_main locked { // Don't keep cs_main locked
@ -148,7 +149,7 @@ UniValue generate(const UniValue& params, bool fHelp)
UniValue blockHashes(UniValue::VARR); UniValue blockHashes(UniValue::VARR);
while (nHeight < nHeightEnd) while (nHeight < nHeightEnd)
{ {
auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(coinbaseScript)); auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(coinbaseScript->reserveScript));
if (!pblocktemplate.get()) if (!pblocktemplate.get())
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
CBlock *pblock = &pblocktemplate->block; CBlock *pblock = &pblocktemplate->block;
@ -166,6 +167,9 @@ UniValue generate(const UniValue& params, bool fHelp)
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
++nHeight; ++nHeight;
blockHashes.push_back(pblock->GetHash().GetHex()); blockHashes.push_back(pblock->GetHash().GetHex());
//mark script as important because it was used at least for one coinbase output
coinbaseScript->KeepScript();
} }
return blockHashes; return blockHashes;
} }

View file

@ -609,4 +609,13 @@ public:
} }
}; };
class CReserveScript
{
public:
CScript reserveScript;
virtual void KeepScript() {}
CReserveScript() {}
virtual ~CReserveScript() {}
};
#endif // BITCOIN_SCRIPT_SCRIPT_H #endif // BITCOIN_SCRIPT_SCRIPT_H

View file

@ -7,10 +7,11 @@
#define BITCOIN_VALIDATIONINTERFACE_H #define BITCOIN_VALIDATIONINTERFACE_H
#include <boost/signals2/signal.hpp> #include <boost/signals2/signal.hpp>
#include <boost/shared_ptr.hpp>
class CBlock; class CBlock;
struct CBlockLocator; struct CBlockLocator;
class CScript; class CReserveScript;
class CTransaction; class CTransaction;
class CValidationInterface; class CValidationInterface;
class CValidationState; class CValidationState;
@ -35,7 +36,7 @@ protected:
virtual void Inventory(const uint256 &hash) {} virtual void Inventory(const uint256 &hash) {}
virtual void ResendWalletTransactions(int64_t nBestBlockTime) {} virtual void ResendWalletTransactions(int64_t nBestBlockTime) {}
virtual void BlockChecked(const CBlock&, const CValidationState&) {} virtual void BlockChecked(const CBlock&, const CValidationState&) {}
virtual void GetScriptForMining(CScript &script) {}; virtual void GetScriptForMining(boost::shared_ptr<CReserveScript>&) {};
virtual void UpdateRequestCount(const CBlock&) {}; virtual void UpdateRequestCount(const CBlock&) {};
friend void ::RegisterValidationInterface(CValidationInterface*); friend void ::RegisterValidationInterface(CValidationInterface*);
friend void ::UnregisterValidationInterface(CValidationInterface*); friend void ::UnregisterValidationInterface(CValidationInterface*);
@ -56,7 +57,7 @@ struct CMainSignals {
/** Notifies listeners of a block validation result */ /** Notifies listeners of a block validation result */
boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked; boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
/** Notifies listeners that a key for mining is required (coinbase) */ /** Notifies listeners that a key for mining is required (coinbase) */
boost::signals2::signal<void (CScript &script)> ScriptForMining; boost::signals2::signal<void (boost::shared_ptr<CReserveScript>&)> ScriptForMining;
/** Notifies listeners that a block has been successfully mined */ /** Notifies listeners that a block has been successfully mined */
boost::signals2::signal<void (const CBlock&)> BlockFound; boost::signals2::signal<void (const CBlock&)> BlockFound;
}; };

View file

@ -2583,14 +2583,15 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx)
} }
} }
void CWallet::GetScriptForMining(CScript &script) void CWallet::GetScriptForMining(boost::shared_ptr<CReserveScript> &script)
{ {
CReserveKey reservekey(this); boost::shared_ptr<CReserveKey> rKey(new CReserveKey(this));
CPubKey pubkey; CPubKey pubkey;
if (!reservekey.GetReservedKey(pubkey)) if (!rKey->GetReservedKey(pubkey))
return; return;
script = CScript() << ToByteVector(pubkey) << OP_CHECKSIG;
reservekey.KeepKey(); script = rKey;
script->reserveScript = CScript() << ToByteVector(pubkey) << OP_CHECKSIG;
} }
void CWallet::LockCoin(COutPoint& output) void CWallet::LockCoin(COutPoint& output)

View file

@ -28,6 +28,8 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <boost/shared_ptr.hpp>
/** /**
* Settings * Settings
*/ */
@ -680,7 +682,7 @@ public:
} }
} }
void GetScriptForMining(CScript &script); void GetScriptForMining(boost::shared_ptr<CReserveScript> &script);
void UpdateRequestCount(const CBlock& block) void UpdateRequestCount(const CBlock& block)
{ {
LOCK(cs_wallet); LOCK(cs_wallet);
@ -742,7 +744,7 @@ public:
}; };
/** A key allocated from the key pool. */ /** A key allocated from the key pool. */
class CReserveKey class CReserveKey : public CReserveScript
{ {
protected: protected:
CWallet* pwallet; CWallet* pwallet;
@ -763,6 +765,7 @@ public:
void ReturnKey(); void ReturnKey();
bool GetReservedKey(CPubKey &pubkey); bool GetReservedKey(CPubKey &pubkey);
void KeepKey(); void KeepKey();
void KeepScript() { KeepKey(); }
}; };