Merge #7671: [RPC] Add generatetoaddress rpc to mine to an address

d5c5c71 RPC tests for generatetoaddress (Andrew C)
fe00ca7 Create generatetoaddress rpc (Andrew C)
This commit is contained in:
Wladimir J. van der Laan 2016-03-23 13:24:34 +01:00 committed by Alexander Block
parent 953aeead1f
commit 760d58e3dc
6 changed files with 106 additions and 33 deletions

View File

@ -29,5 +29,19 @@ class DisableWalletTest (BitcoinTestFramework):
x = self.nodes[0].validateaddress('ycwedq2f3sz2Yf9JqZsBCQPxp18WU3Hp4J') x = self.nodes[0].validateaddress('ycwedq2f3sz2Yf9JqZsBCQPxp18WU3Hp4J')
assert(x['isvalid'] == True) assert(x['isvalid'] == True)
# Checking mining to an address without a wallet
try:
self.nodes[0].generatetoaddress(1, 'mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ')
except JSONRPCException,e:
assert("Invalid address" not in e.error['message'])
assert("ProcessNewBlock, block not accepted" not in e.error['message'])
assert("Couldn't create new block" not in e.error['message'])
try:
self.nodes[0].generatetoaddress(1, '3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy')
raise AssertionError("Must not mine to invalid address!")
except JSONRPCException,e:
assert("Invalid address" in e.error['message'])
if __name__ == '__main__': if __name__ == '__main__':
DisableWalletTest ().main () DisableWalletTest ().main ()

View File

@ -300,6 +300,18 @@ class WalletTest (BitcoinTestFramework):
{"address": address_to_import}, {"address": address_to_import},
{"spendable": True}) {"spendable": True})
# Mine a block from node0 to an address from node1
cbAddr = self.nodes[1].getnewaddress()
blkHash = self.nodes[0].generatetoaddress(1, cbAddr)[0]
cbTxId = self.nodes[0].getblock(blkHash)['tx'][0]
self.sync_all()
# Check that the txid and balance is found by node1
try:
self.nodes[1].gettransaction(cbTxId)
except JSONRPCException,e:
assert("Invalid or non-wallet transaction id" not in e.error['message'])
#check if wallet or blochchain maintenance changes the balance #check if wallet or blochchain maintenance changes the balance
self.sync_all() self.sync_all()
blocks = self.nodes[0].generate(2) blocks = self.nodes[0].generate(2)

View File

@ -29,6 +29,9 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "getaddednodeinfo", 0 }, { "getaddednodeinfo", 0 },
{ "generate", 0 }, { "generate", 0 },
{ "generate", 1 }, { "generate", 1 },
{ "generatetoaddress", 0 },
{ "generatetoaddress", 1 },
{ "generatetoaddress", 2 },
{ "getnetworkhashps", 0 }, { "getnetworkhashps", 0 },
{ "getnetworkhashps", 1 }, { "getnetworkhashps", 1 },
{ "sendtoaddress", 1 }, { "sendtoaddress", 1 },

View File

@ -101,42 +101,12 @@ 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); return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1);
} }
UniValue generate(const UniValue& params, bool fHelp) UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript)
{ {
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"generate numblocks ( maxtries )\n"
"\nMine up to numblocks blocks immediately (before the RPC call returns)\n"
"\nArguments:\n"
"1. numblocks (numeric, required) How many blocks are generated immediately.\n"
"2. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n"
"\nResult\n"
"[ blockhashes ] (array) hashes of blocks generated\n"
"\nExamples:\n"
"\nGenerate 11 blocks\n"
+ HelpExampleCli("generate", "11")
);
static const int nInnerLoopCount = 0x10000; static const int nInnerLoopCount = 0x10000;
int nHeightStart = 0; int nHeightStart = 0;
int nHeightEnd = 0; int nHeightEnd = 0;
int nHeight = 0; int nHeight = 0;
int nGenerate = params[0].get_int();
uint64_t nMaxTries = 1000000;
if (params.size() > 1) {
nMaxTries = params[1].get_int();
}
boost::shared_ptr<CReserveScript> coinbaseScript;
GetMainSignals().ScriptForMining(coinbaseScript);
// If the keypool is exhausted, no script is returned at all. Catch this.
if (!coinbaseScript)
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
//throw an error if no script was provided
if (coinbaseScript->reserveScript.empty())
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
LOCK(cs_main); LOCK(cs_main);
@ -171,12 +141,84 @@ UniValue generate(const UniValue& params, bool fHelp)
++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 //mark script as important because it was used at least for one coinbase output if the script came from the wallet
coinbaseScript->KeepScript(); if (keepScript)
{
coinbaseScript->KeepScript();
}
} }
return blockHashes; return blockHashes;
} }
UniValue generate(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"generate numblocks ( maxtries )\n"
"\nMine up to numblocks blocks immediately (before the RPC call returns)\n"
"\nArguments:\n"
"1. numblocks (numeric, required) How many blocks are generated immediately.\n"
"2. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n"
"\nResult\n"
"[ blockhashes ] (array) hashes of blocks generated\n"
"\nExamples:\n"
"\nGenerate 11 blocks\n"
+ HelpExampleCli("generate", "11")
);
int nGenerate = params[0].get_int();
uint64_t nMaxTries = 1000000;
if (params.size() > 1) {
nMaxTries = params[1].get_int();
}
boost::shared_ptr<CReserveScript> coinbaseScript;
GetMainSignals().ScriptForMining(coinbaseScript);
// If the keypool is exhausted, no script is returned at all. Catch this.
if (!coinbaseScript)
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
//throw an error if no script was provided
if (coinbaseScript->reserveScript.empty())
throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)");
return generateBlocks(coinbaseScript, nGenerate, nMaxTries, true);
}
UniValue generatetoaddress(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 2 || params.size() > 3)
throw runtime_error(
"generatetoaddress numblocks address (maxtries)\n"
"\nMine blocks immediately to a specified address (before the RPC call returns)\n"
"\nArguments:\n"
"1. numblocks (numeric, required) How many blocks are generated immediately.\n"
"2. address (string, required) The address to send the newly generated bitcoin to.\n"
"3. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n"
"\nResult\n"
"[ blockhashes ] (array) hashes of blocks generated\n"
"\nExamples:\n"
"\nGenerate 11 blocks to myaddress\n"
+ HelpExampleCli("generatetoaddress", "11 \"myaddress\"")
);
int nGenerate = params[0].get_int();
uint64_t nMaxTries = 1000000;
if (params.size() > 2) {
nMaxTries = params[2].get_int();
}
CBitcoinAddress address(params[1].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address");
boost::shared_ptr<CReserveScript> coinbaseScript(new CReserveScript());
coinbaseScript->reserveScript = GetScriptForDestination(address.Get());
return generateBlocks(coinbaseScript, nGenerate, nMaxTries, false);
}
UniValue getmininginfo(const UniValue& params, bool fHelp) UniValue getmininginfo(const UniValue& params, bool fHelp)
{ {
if (fHelp || params.size() != 0) if (fHelp || params.size() != 0)

View File

@ -305,6 +305,7 @@ static const CRPCCommand vRPCCommands[] =
/* Coin generation */ /* Coin generation */
{ "generating", "generate", &generate, true }, { "generating", "generate", &generate, true },
{ "generating", "generatetoaddress", &generatetoaddress, true },
/* Raw transactions */ /* Raw transactions */
{ "rawtransactions", "createrawtransaction", &createrawtransaction, true }, { "rawtransactions", "createrawtransaction", &createrawtransaction, true },

View File

@ -199,6 +199,7 @@ extern UniValue clearbanned(const UniValue& params, bool fHelp);
extern UniValue setnetworkactive(const UniValue& params, bool fHelp); extern UniValue setnetworkactive(const UniValue& params, bool fHelp);
extern UniValue generate(const UniValue& params, bool fHelp); extern UniValue generate(const UniValue& params, bool fHelp);
extern UniValue generatetoaddress(const UniValue& params, bool fHelp);
extern UniValue getnetworkhashps(const UniValue& params, bool fHelp); extern UniValue getnetworkhashps(const UniValue& params, bool fHelp);
extern UniValue getmininginfo(const UniValue& params, bool fHelp); extern UniValue getmininginfo(const UniValue& params, bool fHelp);
extern UniValue prioritisetransaction(const UniValue& params, bool fHelp); extern UniValue prioritisetransaction(const UniValue& params, bool fHelp);