From 4a85e067502a5df340e1b8c49df21e4c30a0de68 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sun, 8 Dec 2013 15:26:08 +0100 Subject: [PATCH 1/3] Allow mining RPCs with --disable-wallet The following mining-related RPC calls don't use the wallet: - getnetworkhashps - getmininginfo - getblocktemplate - submitblock Enable them when compiling with --disable-wallet. --- doc/build-unix.md | 4 ++++ src/Makefile.am | 4 ++-- src/init.cpp | 4 +--- src/miner.cpp | 9 +++++++-- src/rpcmining.cpp | 24 ++++++++++++++++++------ src/rpcserver.cpp | 19 ++++++++++++------- 6 files changed, 44 insertions(+), 20 deletions(-) diff --git a/doc/build-unix.md b/doc/build-unix.md index 1d9d96a1c..6cf88edff 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -187,3 +187,7 @@ disable-wallet mode with: ./configure --disable-wallet In this case there is no dependency on Berkeley DB 4.8. + +Mining is also possible in disable-wallet mode, but only using the `getblocktemplate` RPC +call not `getwork`. + diff --git a/src/Makefile.am b/src/Makefile.am index df4087c31..62dd63abe 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -48,9 +48,11 @@ libbitcoin_server_a_SOURCES = \ keystore.cpp \ leveldbwrapper.cpp \ main.cpp \ + miner.cpp \ net.cpp \ noui.cpp \ rpcblockchain.cpp \ + rpcmining.cpp \ rpcnet.cpp \ rpcrawtransaction.cpp \ txdb.cpp \ @@ -61,9 +63,7 @@ libbitcoin_server_a_SOURCES = \ libbitcoin_wallet_a_SOURCES = \ db.cpp \ crypter.cpp \ - miner.cpp \ rpcdump.cpp \ - rpcmining.cpp \ rpcwallet.cpp \ wallet.cpp \ walletdb.cpp \ diff --git a/src/init.cpp b/src/init.cpp index fc15df059..f4424b6ba 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -113,8 +113,8 @@ void Shutdown() RenameThread("bitcoin-shutoff"); mempool.AddTransactionsUpdated(1); StopRPCThreads(); -#ifdef ENABLE_WALLET ShutdownRPCMining(); +#ifdef ENABLE_WALLET if (pwalletMain) bitdb.Flush(false); GenerateBitcoins(false, NULL, 0); @@ -1041,10 +1041,8 @@ bool AppInit2(boost::thread_group& threadGroup, bool fForceServer) #endif StartNode(threadGroup); -#ifdef ENABLE_WALLET // InitRPCMining is needed here so getwork/getblocktemplate in the GUI debug console works properly. InitRPCMining(); -#endif if (fServer) StartRPCThreads(); diff --git a/src/miner.cpp b/src/miner.cpp index ecc40ac70..384ebd27c 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -10,8 +10,11 @@ #include "net.h" #include "wallet.h" +#ifdef ENABLE_WALLET +// These globals are only used by the built-in miner double dHashesPerSec = 0.0; int64_t nHPSTimerStart = 0; +#endif ////////////////////////////////////////////////////////////////////////////// // @@ -381,6 +384,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) return pblocktemplate.release(); } +#ifdef ENABLE_WALLET CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey) { CPubKey pubkey; @@ -390,6 +394,7 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey) CScript scriptPubKey = CScript() << pubkey << OP_CHECKSIG; return CreateNewBlock(scriptPubKey); } +#endif void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce) { @@ -454,7 +459,7 @@ void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash memcpy(phash1, &tmp.hash1, 64); } - +#ifdef ENABLE_WALLET bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) { uint256 hash = pblock->GetHash(); @@ -665,5 +670,5 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads) minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet)); } - +#endif diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 131a258c8..b81433120 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -20,7 +20,8 @@ using namespace json_spirit; using namespace std; -// Key used by getwork/getblocktemplate miners. +#ifdef ENABLE_WALLET +// Key used by getwork miners. // Allocated in InitRPCMining, free'd in ShutdownRPCMining static CReserveKey* pMiningKey = NULL; @@ -40,6 +41,14 @@ void ShutdownRPCMining() 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. @@ -99,7 +108,7 @@ Value getnetworkhashps(const Array& params, bool fHelp) return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1); } - +#ifdef ENABLE_WALLET Value getgenerate(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -197,7 +206,6 @@ Value setgenerate(const Array& params, bool fHelp) return Value::null; } - Value gethashespersec(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -216,6 +224,7 @@ Value gethashespersec(const Array& params, bool fHelp) return (boost::int64_t)0; return (boost::int64_t)dHashesPerSec; } +#endif Value getmininginfo(const Array& params, bool fHelp) @@ -248,16 +257,19 @@ Value getmininginfo(const Array& params, bool fHelp) obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx)); obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("errors", GetWarnings("statusbar"))); - obj.push_back(Pair("generate", getgenerate(params, false))); obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1))); - obj.push_back(Pair("hashespersec", gethashespersec(params, false))); obj.push_back(Pair("networkhashps", getnetworkhashps(params, false))); obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); obj.push_back(Pair("testnet", TestNet())); +#ifdef ENABLE_WALLET + obj.push_back(Pair("generate", getgenerate(params, false))); + obj.push_back(Pair("hashespersec", gethashespersec(params, false))); +#endif return obj; } +#ifdef ENABLE_WALLET Value getwork(const Array& params, bool fHelp) { if (fHelp || params.size() > 1) @@ -381,7 +393,7 @@ Value getwork(const Array& params, bool fHelp) return CheckWork(pblock, *pwalletMain, *pMiningKey); } } - +#endif Value getblocktemplate(const Array& params, bool fHelp) { diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 2dc7b34f8..c95f450c8 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -248,12 +248,14 @@ static const CRPCCommand vRPCCommands[] = { "gettxout", &gettxout, true, false, false }, { "verifychain", &verifychain, true, false, false }, -#ifdef ENABLE_WALLET + /* Mining */ { "getnetworkhashps", &getnetworkhashps, true, false, false }, - { "getgenerate", &getgenerate, true, false, false }, - { "setgenerate", &setgenerate, true, true, false }, - { "gethashespersec", &gethashespersec, true, false, false }, { "getmininginfo", &getmininginfo, true, false, false }, + { "getblocktemplate", &getblocktemplate, true, false, false }, + { "submitblock", &submitblock, false, false, false }, + +#ifdef ENABLE_WALLET + /* Wallet */ { "getnewaddress", &getnewaddress, true, false, true }, { "getaccountaddress", &getaccountaddress, true, false, true }, { "getrawchangeaddress", &getrawchangeaddress, true, false, true }, @@ -283,10 +285,7 @@ static const CRPCCommand vRPCCommands[] = { "listaddressgroupings", &listaddressgroupings, false, false, true }, { "signmessage", &signmessage, false, false, true }, { "verifymessage", &verifymessage, false, false, false }, - { "getwork", &getwork, true, false, true }, { "listaccounts", &listaccounts, false, false, true }, - { "getblocktemplate", &getblocktemplate, true, false, false }, - { "submitblock", &submitblock, false, false, false }, { "listsinceblock", &listsinceblock, false, false, true }, { "dumpprivkey", &dumpprivkey, true, false, true }, { "dumpwallet", &dumpwallet, true, false, true }, @@ -295,6 +294,12 @@ static const CRPCCommand vRPCCommands[] = { "listunspent", &listunspent, false, false, true }, { "lockunspent", &lockunspent, false, false, true }, { "listlockunspent", &listlockunspent, false, false, true }, + + /* Wallet-enabled mining */ + { "getgenerate", &getgenerate, true, false, false }, + { "setgenerate", &setgenerate, true, true, false }, + { "gethashespersec", &gethashespersec, true, false, false }, + { "getwork", &getwork, true, false, true }, #endif // ENABLE_WALLET }; From acfa03337e8224ef778d4a5b2177271611f74593 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 9 Dec 2013 08:55:56 +0100 Subject: [PATCH 2/3] Move internal miner functionality together --- src/miner.cpp | 105 +++++++++++++++++++++++++------------------------- 1 file changed, 52 insertions(+), 53 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 384ebd27c..49f6ec6b9 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -10,12 +10,6 @@ #include "net.h" #include "wallet.h" -#ifdef ENABLE_WALLET -// These globals are only used by the built-in miner -double dHashesPerSec = 0.0; -int64_t nHPSTimerStart = 0; -#endif - ////////////////////////////////////////////////////////////////////////////// // // BitcoinMiner @@ -57,41 +51,6 @@ void SHA256Transform(void* pstate, void* pinput, const void* pinit) ((uint32_t*)pstate)[i] = ctx.h[i]; } -// -// ScanHash scans nonces looking for a hash with at least some zero bits. -// It operates on big endian data. Caller does the byte reversing. -// All input buffers are 16-byte aligned. nNonce is usually preserved -// between calls, but periodically or if nNonce is 0xffff0000 or above, -// the block is rebuilt and nNonce starts over at zero. -// -unsigned int static ScanHash_CryptoPP(char* pmidstate, char* pdata, char* phash1, char* phash, unsigned int& nHashesDone) -{ - unsigned int& nNonce = *(unsigned int*)(pdata + 12); - for (;;) - { - // Crypto++ SHA256 - // Hash pdata using pmidstate as the starting state into - // pre-formatted buffer phash1, then hash phash1 into phash - nNonce++; - SHA256Transform(phash1, pdata, pmidstate); - SHA256Transform(phash, phash1, pSHA256InitState); - - // Return the nonce if the hash has at least some zero bits, - // caller will check if it has enough to reach the target - if (((unsigned short*)phash)[14] == 0) - return nNonce; - - // If nothing found after trying for a while, return -1 - if ((nNonce & 0xffff) == 0) - { - nHashesDone = 0xffff+1; - return (unsigned int) -1; - } - if ((nNonce & 0xfff) == 0) - boost::this_thread::interruption_point(); - } -} - // Some explaining would be appreciated class COrphan { @@ -384,18 +343,6 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) return pblocktemplate.release(); } -#ifdef ENABLE_WALLET -CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey) -{ - CPubKey pubkey; - if (!reservekey.GetReservedKey(pubkey)) - return NULL; - - CScript scriptPubKey = CScript() << pubkey << OP_CHECKSIG; - return CreateNewBlock(scriptPubKey); -} -#endif - void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce) { // Update nExtraNonce @@ -460,6 +407,58 @@ void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash } #ifdef ENABLE_WALLET +////////////////////////////////////////////////////////////////////////////// +// +// Internal miner +// +double dHashesPerSec = 0.0; +int64_t nHPSTimerStart = 0; + +// +// ScanHash scans nonces looking for a hash with at least some zero bits. +// It operates on big endian data. Caller does the byte reversing. +// All input buffers are 16-byte aligned. nNonce is usually preserved +// between calls, but periodically or if nNonce is 0xffff0000 or above, +// the block is rebuilt and nNonce starts over at zero. +// +unsigned int static ScanHash_CryptoPP(char* pmidstate, char* pdata, char* phash1, char* phash, unsigned int& nHashesDone) +{ + unsigned int& nNonce = *(unsigned int*)(pdata + 12); + for (;;) + { + // Crypto++ SHA256 + // Hash pdata using pmidstate as the starting state into + // pre-formatted buffer phash1, then hash phash1 into phash + nNonce++; + SHA256Transform(phash1, pdata, pmidstate); + SHA256Transform(phash, phash1, pSHA256InitState); + + // Return the nonce if the hash has at least some zero bits, + // caller will check if it has enough to reach the target + if (((unsigned short*)phash)[14] == 0) + return nNonce; + + // If nothing found after trying for a while, return -1 + if ((nNonce & 0xffff) == 0) + { + nHashesDone = 0xffff+1; + return (unsigned int) -1; + } + if ((nNonce & 0xfff) == 0) + boost::this_thread::interruption_point(); + } +} + +CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey) +{ + CPubKey pubkey; + if (!reservekey.GetReservedKey(pubkey)) + return NULL; + + CScript scriptPubKey = CScript() << pubkey << OP_CHECKSIG; + return CreateNewBlock(scriptPubKey); +} + bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) { uint256 hash = pblock->GetHash(); From fbc7a96d03200e55021c9e04f7fa9114272e6960 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 9 Dec 2013 09:22:15 +0100 Subject: [PATCH 3/3] Re-enable miner tests in --disable-wallet mode Use a fixed script instead of a CReserveKey from the wallet. This does not affect the functionality or result of the tests as they never check the state of the wallet in the first place. --- src/test/Makefile.am | 4 ++-- src/test/miner_tests.cpp | 25 ++++++++++++------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/test/Makefile.am b/src/test/Makefile.am index dccd264e5..ccc8da169 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -31,14 +31,14 @@ test_bitcoin_SOURCES = alert_tests.cpp \ allocator_tests.cpp base32_tests.cpp base58_tests.cpp base64_tests.cpp \ bignum_tests.cpp bloom_tests.cpp canonical_tests.cpp checkblock_tests.cpp \ Checkpoints_tests.cpp compress_tests.cpp DoS_tests.cpp getarg_tests.cpp \ - key_tests.cpp mruset_tests.cpp multisig_tests.cpp \ + key_tests.cpp miner_tests.cpp mruset_tests.cpp multisig_tests.cpp \ netbase_tests.cpp pmt_tests.cpp rpc_tests.cpp script_P2SH_tests.cpp \ script_tests.cpp serialize_tests.cpp sigopcount_tests.cpp test_bitcoin.cpp \ transaction_tests.cpp uint160_tests.cpp uint256_tests.cpp util_tests.cpp \ sighash_tests.cpp $(JSON_TEST_FILES) $(RAW_TEST_FILES) if ENABLE_WALLET -test_bitcoin_SOURCES += accounting_tests.cpp wallet_tests.cpp miner_tests.cpp rpc_wallet_tests.cpp +test_bitcoin_SOURCES += accounting_tests.cpp wallet_tests.cpp rpc_wallet_tests.cpp endif nodist_test_bitcoin_SOURCES = $(BUILT_SOURCES) diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 46c9ae021..ea6abb7e9 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -8,7 +8,6 @@ #include -extern CWallet* pwalletMain; extern void SHA256Transform(void* pstate, void* pinput, const void* pinit); BOOST_AUTO_TEST_SUITE(miner_tests) @@ -51,7 +50,7 @@ struct { // NOTE: These tests rely on CreateNewBlock doing its own self-validation! BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { - CReserveKey reservekey(pwalletMain); + CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; CBlockTemplate *pblocktemplate; CTransaction tx; CScript script; @@ -60,7 +59,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) LOCK(cs_main); // Simple block creation, nothing special yet: - BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); // We can't make transactions until we have inputs // Therefore, load 100 blocks :) @@ -86,7 +85,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) delete pblocktemplate; // Just to make sure we can still make simple blocks - BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; // block sigops > limit: 1000 CHECKMULTISIG + 1 @@ -104,7 +103,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -124,14 +123,14 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; mempool.clear(); // orphan in mempool hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -149,7 +148,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue = 5900000000LL; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -160,7 +159,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue = 0; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -178,7 +177,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue -= 1000000; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -192,17 +191,17 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].scriptPubKey = CScript() << OP_2; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; mempool.clear(); // subsidy changing int nHeight = chainActive.Height(); chainActive.Tip()->nHeight = 209999; - BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; chainActive.Tip()->nHeight = 210000; - BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; chainActive.Tip()->nHeight = nHeight;