mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-21 14:34:49 +01:00
Merge #19133: rpc, cli, test: add bitcoin-cli -generate command
22cb303cf0
rpc: add missing space in JSON parsing error message, update test (Jon Atack)bf53ebef06
test: add multiwallet tests for bitcoin-cli -generate (Jon Atack)4b859cfff9
cli: add multiwallet capability to GetNewAddress and -generate (Jon Atack)18f93545a1
test: add tests for bitcoin-cli -generate (Jon Atack)4818124137
cli: create bitcoin-cli -generate command (Jon Atack)ff41a36900
cli: extract ParseResult() and ParseError() (Jon Atack)f4185b26d9
cli: create GenerateToAddressRequestHandler class (Harris)f7c65a3350
cli: create GetNewAddress() (Jon Atack)9be7fd35c5
rpc: make generatetoaddress locals const (Jon Atack)cb00510dba
rpc: create rpc/mining.h, hoist default max tries values to constant (Jon Atack) Pull request description: This PR continues and completes the work begun in #17700 working on issue #16000 to create a client-side version of RPC `generate`. Basically, `bitcoin-cli -generate` wraps calling `generatenewaddress` followed by `generatetoaddress [nblocks] [maxtries]` and prints the following: ``` $ bitcoin-cli -generate { "address": "bcrt1qn4aszr2y2xvpa70y675a76wsu70wlkwvdyyln6" "blocks": [ "01d2ebcddf663da90b28da7f6805115e2ba7818f16fe747258836646a43a0bb5", ] } $ bitcoin-cli -rpcwallet=wallet-name -generate 3 100 { "address": "bcrt1q4cunfw0gnsj7g7e6mk0v0uuvvau9mwr09dj45l", "blocks": [ "7a6650ca5e0c614992ee64fb148a7e5e022af842e4b6003f81abd8baf1e75136", "01d2ebcddf663da90b28da7f6805115e2ba7818f16fe747258836646a43a0bb5", "3f8795ec40b1ad812b818c177680841be319a3f6753d4e32dc7dfb5bafe5d00e" ] } ``` Help doc: ``` $ bitcoin-cli -h | grep -A5 "\-generate" -generate Generate blocks immediately, equivalent to RPC generatenewaddress followed by RPC generatetoaddress. Optional positional arguments are number of blocks to generate (default: 1) and maximum iterations to try (default: 1000000), equivalent to RPC generatetoaddress nblocks and maxtries arguments. Example: bitcoin-cli -generate 4 1000 ``` Quite a bit of test coverage turned out to be needed to cover the change and the different cases (arguments, multiwallet mode) and error-handling. This PR also improves some things that working on these changes brought to light. Credit to Harris Brakmić for the initial work in #17700. ACKs for top commit: adamjonas: utACK22cb303cf0
meshcollider: utACK22cb303cf0
Tree-SHA512: 94f67f632fe093d076f614e0ecff09ce7342ac6e424579200d5211a6615260e438d857861767fb788950ec6da0b26ef56dc8268c430012a3b3d4822b24ca6fbf
This commit is contained in:
commit
47a30ef0c6
6 changed files with 222 additions and 48 deletions
|
@ -184,6 +184,7 @@ BITCOIN_CORE_H = \
|
|||
reverse_iterator.h \
|
||||
rpc/blockchain.h \
|
||||
rpc/client.h \
|
||||
rpc/mining.h \
|
||||
rpc/protocol.h \
|
||||
rpc/rawtransaction_util.h \
|
||||
rpc/register.h \
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <clientversion.h>
|
||||
#include <optional.h>
|
||||
#include <rpc/client.h>
|
||||
#include <rpc/mining.h>
|
||||
#include <rpc/protocol.h>
|
||||
#include <rpc/request.h>
|
||||
#include <util/strencodings.h>
|
||||
|
@ -39,6 +40,9 @@ static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
|
|||
static const bool DEFAULT_NAMED=false;
|
||||
static const int CONTINUE_EXECUTION=-1;
|
||||
|
||||
/** Default number of blocks to generate for RPC generatetoaddress. */
|
||||
static const std::string DEFAULT_NBLOCKS = "1";
|
||||
|
||||
static void SetupCliArgs()
|
||||
{
|
||||
SetupHelpOptions(gArgs);
|
||||
|
@ -50,6 +54,7 @@ static void SetupCliArgs()
|
|||
gArgs.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
gArgs.AddArg("-conf=<file>", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
gArgs.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
gArgs.AddArg("-generate", strprintf("Generate blocks immediately, equivalent to RPC generatenewaddress followed by RPC generatetoaddress. Optional positional integer arguments are number of blocks to generate (default: %s) and maximum iterations to try (default: %s), equivalent to RPC generatetoaddress nblocks and maxtries arguments. Example: bitcoin-cli -generate 4 1000", DEFAULT_NBLOCKS, DEFAULT_MAX_TRIES), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
gArgs.AddArg("-getinfo", "Get general information from the remote server. Note that unlike server-side RPC calls, the results of -getinfo is the result of multiple non-atomic requests. Some entries in the result may represent results from different states (e.g. wallet balance may be as of a different block from the chain state reported)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
SetupChainParamsBaseOptions();
|
||||
gArgs.AddArg("-named", strprintf("Pass named instead of positional arguments (default: %s)", DEFAULT_NAMED), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
|
@ -286,6 +291,28 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/** Process RPC generatetoaddress request. */
|
||||
class GenerateToAddressRequestHandler : public BaseRequestHandler
|
||||
{
|
||||
public:
|
||||
UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) override
|
||||
{
|
||||
address_str = args.at(1);
|
||||
UniValue params{RPCConvertValues("generatetoaddress", args)};
|
||||
return JSONRPCRequestObj("generatetoaddress", params, 1);
|
||||
}
|
||||
|
||||
UniValue ProcessReply(const UniValue &reply) override
|
||||
{
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.pushKV("address", address_str);
|
||||
result.pushKV("blocks", reply.get_obj()["result"]);
|
||||
return JSONRPCReplyObj(result, NullUniValue, 1);
|
||||
}
|
||||
protected:
|
||||
std::string address_str;
|
||||
};
|
||||
|
||||
/** Process default single requests */
|
||||
class DefaultRequestHandler: public BaseRequestHandler {
|
||||
public:
|
||||
|
@ -453,6 +480,34 @@ static UniValue ConnectAndCallRPC(BaseRequestHandler* rh, const std::string& str
|
|||
return response;
|
||||
}
|
||||
|
||||
/** Parse UniValue result to update the message to print to std::cout. */
|
||||
static void ParseResult(const UniValue& result, std::string& strPrint)
|
||||
{
|
||||
if (result.isNull()) return;
|
||||
strPrint = result.isStr() ? result.get_str() : result.write(2);
|
||||
}
|
||||
|
||||
/** Parse UniValue error to update the message to print to std::cerr and the code to return. */
|
||||
static void ParseError(const UniValue& error, std::string& strPrint, int& nRet)
|
||||
{
|
||||
if (error.isObject()) {
|
||||
const UniValue& err_code = find_value(error, "code");
|
||||
const UniValue& err_msg = find_value(error, "message");
|
||||
if (!err_code.isNull()) {
|
||||
strPrint = "error code: " + err_code.getValStr() + "\n";
|
||||
}
|
||||
if (err_msg.isStr()) {
|
||||
strPrint += ("error message:\n" + err_msg.get_str());
|
||||
}
|
||||
if (err_code.isNum() && err_code.get_int() == RPC_WALLET_NOT_SPECIFIED) {
|
||||
strPrint += "\nTry adding \"-rpcwallet=<filename>\" option to bitcoin-cli command line.";
|
||||
}
|
||||
} else {
|
||||
strPrint = "error: " + error.write();
|
||||
}
|
||||
nRet = abs(error["code"].get_int());
|
||||
}
|
||||
|
||||
/**
|
||||
* GetWalletBalances calls listwallets; if more than one wallet is loaded, it then
|
||||
* fetches mine.trusted balances for each loaded wallet and pushes them to `result`.
|
||||
|
@ -477,6 +532,34 @@ static void GetWalletBalances(UniValue& result)
|
|||
result.pushKV("balances", balances);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call RPC getnewaddress.
|
||||
* @returns getnewaddress response as a UniValue object.
|
||||
*/
|
||||
static UniValue GetNewAddress()
|
||||
{
|
||||
Optional<std::string> wallet_name{};
|
||||
if (gArgs.IsArgSet("-rpcwallet")) wallet_name = gArgs.GetArg("-rpcwallet", "");
|
||||
std::unique_ptr<BaseRequestHandler> rh{MakeUnique<DefaultRequestHandler>()};
|
||||
return ConnectAndCallRPC(rh.get(), "getnewaddress", /* args=*/{}, wallet_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check bounds and set up args for RPC generatetoaddress params: nblocks, address, maxtries.
|
||||
* @param[in] address Reference to const string address to insert into the args.
|
||||
* @param args Reference to vector of string args to modify.
|
||||
*/
|
||||
static void SetGenerateToAddressArgs(const std::string& address, std::vector<std::string>& args)
|
||||
{
|
||||
if (args.size() > 2) throw std::runtime_error("too many arguments (maximum 2 for nblocks and maxtries)");
|
||||
if (args.size() == 0) {
|
||||
args.emplace_back(DEFAULT_NBLOCKS);
|
||||
} else if (args.at(0) == "0") {
|
||||
throw std::runtime_error("the first argument (number of blocks to generate, default: " + DEFAULT_NBLOCKS + ") must be an integer value greater than zero");
|
||||
}
|
||||
args.emplace(args.begin() + 1, address);
|
||||
}
|
||||
|
||||
static int CommandLineRPC(int argc, char *argv[])
|
||||
{
|
||||
std::string strPrint;
|
||||
|
@ -535,6 +618,15 @@ static int CommandLineRPC(int argc, char *argv[])
|
|||
std::string method;
|
||||
if (gArgs.IsArgSet("-getinfo")) {
|
||||
rh.reset(new GetinfoRequestHandler());
|
||||
} else if (gArgs.GetBoolArg("-generate", false)) {
|
||||
const UniValue getnewaddress{GetNewAddress()};
|
||||
const UniValue& error{find_value(getnewaddress, "error")};
|
||||
if (error.isNull()) {
|
||||
SetGenerateToAddressArgs(find_value(getnewaddress, "result").get_str(), args);
|
||||
rh.reset(new GenerateToAddressRequestHandler());
|
||||
} else {
|
||||
ParseError(error, strPrint, nRet);
|
||||
}
|
||||
} else {
|
||||
rh.reset(new DefaultRequestHandler());
|
||||
if (args.size() < 1) {
|
||||
|
@ -543,40 +635,22 @@ static int CommandLineRPC(int argc, char *argv[])
|
|||
method = args[0];
|
||||
args.erase(args.begin()); // Remove trailing method name from arguments vector
|
||||
}
|
||||
Optional<std::string> wallet_name{};
|
||||
if (gArgs.IsArgSet("-rpcwallet")) wallet_name = gArgs.GetArg("-rpcwallet", "");
|
||||
const UniValue reply = ConnectAndCallRPC(rh.get(), method, args, wallet_name);
|
||||
if (nRet == 0) {
|
||||
// Perform RPC call
|
||||
Optional<std::string> wallet_name{};
|
||||
if (gArgs.IsArgSet("-rpcwallet")) wallet_name = gArgs.GetArg("-rpcwallet", "");
|
||||
const UniValue reply = ConnectAndCallRPC(rh.get(), method, args, wallet_name);
|
||||
|
||||
// Parse reply
|
||||
UniValue result = find_value(reply, "result");
|
||||
const UniValue& error = find_value(reply, "error");
|
||||
if (!error.isNull()) {
|
||||
// Error
|
||||
strPrint = "error: " + error.write();
|
||||
nRet = abs(error["code"].get_int());
|
||||
if (error.isObject()) {
|
||||
const UniValue& errCode = find_value(error, "code");
|
||||
const UniValue& errMsg = find_value(error, "message");
|
||||
strPrint = errCode.isNull() ? "" : ("error code: " + errCode.getValStr() + "\n");
|
||||
|
||||
if (errMsg.isStr()) {
|
||||
strPrint += ("error message:\n" + errMsg.get_str());
|
||||
// Parse reply
|
||||
UniValue result = find_value(reply, "result");
|
||||
const UniValue& error = find_value(reply, "error");
|
||||
if (error.isNull()) {
|
||||
if (gArgs.IsArgSet("-getinfo") && !gArgs.IsArgSet("-rpcwallet")) {
|
||||
GetWalletBalances(result); // fetch multiwallet balances and append to result
|
||||
}
|
||||
if (errCode.isNum() && errCode.get_int() == RPC_WALLET_NOT_SPECIFIED) {
|
||||
strPrint += "\nTry adding \"-rpcwallet=<filename>\" option to bitcoin-cli command line.";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (gArgs.IsArgSet("-getinfo") && !gArgs.IsArgSet("-rpcwallet")) {
|
||||
GetWalletBalances(result); // fetch multiwallet balances and append to result
|
||||
}
|
||||
// Result
|
||||
if (result.isNull()) {
|
||||
strPrint = "";
|
||||
} else if (result.isStr()) {
|
||||
strPrint = result.get_str();
|
||||
ParseResult(result, strPrint);
|
||||
} else {
|
||||
strPrint = result.write(2);
|
||||
ParseError(error, strPrint, nRet);
|
||||
}
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
|
|
|
@ -217,7 +217,7 @@ UniValue ParseNonRFCJSONValue(const std::string& strVal)
|
|||
UniValue jVal;
|
||||
if (!jVal.read(std::string("[")+strVal+std::string("]")) ||
|
||||
!jVal.isArray() || jVal.size()!=1)
|
||||
throw std::runtime_error(std::string("Error parsing JSON:")+strVal);
|
||||
throw std::runtime_error(std::string("Error parsing JSON: ") + strVal);
|
||||
return jVal[0];
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <policy/fees.h>
|
||||
#include <pow.h>
|
||||
#include <rpc/blockchain.h>
|
||||
#include <rpc/mining.h>
|
||||
#include <rpc/server.h>
|
||||
#include <rpc/util.h>
|
||||
#include <script/descriptor.h>
|
||||
|
@ -207,7 +208,7 @@ static UniValue generatetodescriptor(const JSONRPCRequest& request)
|
|||
{
|
||||
{"num_blocks", RPCArg::Type::NUM, RPCArg::Optional::NO, "How many blocks are generated immediately."},
|
||||
{"descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The descriptor to send the newly generated bitcoin to."},
|
||||
{"maxtries", RPCArg::Type::NUM, /* default */ "1000000", "How many iterations to try."},
|
||||
{"maxtries", RPCArg::Type::NUM, /* default */ ToString(DEFAULT_MAX_TRIES), "How many iterations to try."},
|
||||
},
|
||||
RPCResult{
|
||||
RPCResult::Type::ARR, "", "hashes of blocks generated",
|
||||
|
@ -221,7 +222,7 @@ static UniValue generatetodescriptor(const JSONRPCRequest& request)
|
|||
.Check(request);
|
||||
|
||||
const int num_blocks{request.params[0].get_int()};
|
||||
const int64_t max_tries{request.params[2].isNull() ? 1000000 : request.params[2].get_int()};
|
||||
const uint64_t max_tries{request.params[2].isNull() ? DEFAULT_MAX_TRIES : request.params[2].get_int()};
|
||||
|
||||
CScript coinbase_script;
|
||||
std::string error;
|
||||
|
@ -242,7 +243,7 @@ static UniValue generatetoaddress(const JSONRPCRequest& request)
|
|||
{
|
||||
{"nblocks", RPCArg::Type::NUM, RPCArg::Optional::NO, "How many blocks are generated immediately."},
|
||||
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The address to send the newly generated bitcoin to."},
|
||||
{"maxtries", RPCArg::Type::NUM, /* default */ "1000000", "How many iterations to try."},
|
||||
{"maxtries", RPCArg::Type::NUM, /* default */ ToString(DEFAULT_MAX_TRIES), "How many iterations to try."},
|
||||
},
|
||||
RPCResult{
|
||||
RPCResult::Type::ARR, "", "hashes of blocks generated",
|
||||
|
@ -257,11 +258,8 @@ static UniValue generatetoaddress(const JSONRPCRequest& request)
|
|||
},
|
||||
}.Check(request);
|
||||
|
||||
int nGenerate = request.params[0].get_int();
|
||||
uint64_t nMaxTries = 1000000;
|
||||
if (!request.params[2].isNull()) {
|
||||
nMaxTries = request.params[2].get_int();
|
||||
}
|
||||
const int num_blocks{request.params[0].get_int()};
|
||||
const uint64_t max_tries{request.params[2].isNull() ? DEFAULT_MAX_TRIES : request.params[2].get_int()};
|
||||
|
||||
CTxDestination destination = DecodeDestination(request.params[1].get_str());
|
||||
if (!IsValidDestination(destination)) {
|
||||
|
@ -273,7 +271,7 @@ static UniValue generatetoaddress(const JSONRPCRequest& request)
|
|||
|
||||
CScript coinbase_script = GetScriptForDestination(destination);
|
||||
|
||||
return generateBlocks(chainman, mempool, coinbase_script, nGenerate, nMaxTries);
|
||||
return generateBlocks(chainman, mempool, coinbase_script, num_blocks, max_tries);
|
||||
}
|
||||
|
||||
static UniValue generateblock(const JSONRPCRequest& request)
|
||||
|
@ -371,7 +369,7 @@ static UniValue generateblock(const JSONRPCRequest& request)
|
|||
}
|
||||
|
||||
uint256 block_hash;
|
||||
uint64_t max_tries{1000000};
|
||||
uint64_t max_tries{DEFAULT_MAX_TRIES};
|
||||
unsigned int extra_nonce{0};
|
||||
|
||||
if (!GenerateBlock(EnsureChainman(request.context), block, max_tries, extra_nonce, block_hash) || block_hash.IsNull()) {
|
||||
|
|
11
src/rpc/mining.h
Normal file
11
src/rpc/mining.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) 2020 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_RPC_MINING_H
|
||||
#define BITCOIN_RPC_MINING_H
|
||||
|
||||
/** Default max iterations to try in RPC generatetodescriptor, generatetoaddress, and generateblock. */
|
||||
static const uint64_t DEFAULT_MAX_TRIES{1000000};
|
||||
|
||||
#endif // BITCOIN_RPC_MINING_H
|
|
@ -3,9 +3,15 @@
|
|||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
"""Test bitcoin-cli"""
|
||||
|
||||
from decimal import Decimal
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import assert_equal, assert_raises_process_error, get_auth_cookie
|
||||
from test_framework.util import (
|
||||
assert_equal,
|
||||
assert_raises_process_error,
|
||||
assert_raises_rpc_error,
|
||||
get_auth_cookie,
|
||||
)
|
||||
|
||||
# The block reward of coinbaseoutput.nValue (50) BTC/block matures after
|
||||
# COINBASE_MATURITY (100) blocks. Therefore, after mining 101 blocks we expect
|
||||
|
@ -13,6 +19,12 @@ from test_framework.util import assert_equal, assert_raises_process_error, get_a
|
|||
BLOCKS = 101
|
||||
BALANCE = (BLOCKS - 100) * 50
|
||||
|
||||
JSON_PARSING_ERROR = 'error: Error parsing JSON: foo'
|
||||
BLOCKS_VALUE_OF_ZERO = 'error: the first argument (number of blocks to generate, default: 1) must be an integer value greater than zero'
|
||||
TOO_MANY_ARGS = 'error: too many arguments (maximum 2 for nblocks and maxtries)'
|
||||
WALLET_NOT_LOADED = 'Requested wallet does not exist or is not loaded'
|
||||
WALLET_NOT_SPECIFIED = 'Wallet file not specified'
|
||||
|
||||
class TestBitcoinCli(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.setup_clean_chain = True
|
||||
|
@ -75,7 +87,7 @@ class TestBitcoinCli(BitcoinTestFramework):
|
|||
assert_equal(cli_get_info['relayfee'], network_info['relayfee'])
|
||||
assert_equal(self.nodes[0].cli.getwalletinfo(), wallet_info)
|
||||
|
||||
# Setup to test -getinfo and -rpcwallet= with multiple wallets.
|
||||
# Setup to test -getinfo, -generate, and -rpcwallet= with multiple wallets.
|
||||
wallets = ['', 'Encrypted', 'secret']
|
||||
amounts = [BALANCE + Decimal('9.999928'), Decimal(9), Decimal(31)]
|
||||
self.nodes[0].createwallet(wallet_name=wallets[1])
|
||||
|
@ -83,6 +95,8 @@ class TestBitcoinCli(BitcoinTestFramework):
|
|||
w1 = self.nodes[0].get_wallet_rpc(wallets[0])
|
||||
w2 = self.nodes[0].get_wallet_rpc(wallets[1])
|
||||
w3 = self.nodes[0].get_wallet_rpc(wallets[2])
|
||||
rpcwallet2 = '-rpcwallet={}'.format(wallets[1])
|
||||
rpcwallet3 = '-rpcwallet={}'.format(wallets[2])
|
||||
w1.walletpassphrase(password, self.rpc_timeout)
|
||||
w2.encryptwallet(password)
|
||||
w1.sendtoaddress(w2.getnewaddress(), amounts[1])
|
||||
|
@ -123,17 +137,93 @@ class TestBitcoinCli(BitcoinTestFramework):
|
|||
assert_equal(cli_get_info['balance'], amounts[1])
|
||||
|
||||
self.log.info("Test -getinfo with -rpcwallet=remaining-non-default-wallet returns only its balance")
|
||||
cli_get_info = self.nodes[0].cli('-getinfo', '-rpcwallet={}'.format(wallets[1])).send_cli()
|
||||
cli_get_info = self.nodes[0].cli('-getinfo', rpcwallet2).send_cli()
|
||||
assert 'balances' not in cli_get_info.keys()
|
||||
assert_equal(cli_get_info['balance'], amounts[1])
|
||||
|
||||
self.log.info("Test -getinfo with -rpcwallet=unloaded wallet returns no balances")
|
||||
cli_get_info = self.nodes[0].cli('-getinfo', '-rpcwallet={}'.format(wallets[2])).send_cli()
|
||||
cli_get_info = self.nodes[0].cli('-getinfo', rpcwallet3).send_cli()
|
||||
assert 'balance' not in cli_get_info_keys
|
||||
assert 'balances' not in cli_get_info_keys
|
||||
|
||||
# Test bitcoin-cli -generate.
|
||||
n1 = 3
|
||||
n2 = 4
|
||||
w2.walletpassphrase(password, self.rpc_timeout)
|
||||
blocks = self.nodes[0].getblockcount()
|
||||
|
||||
self.log.info('Test -generate with no args')
|
||||
generate = self.nodes[0].cli('-generate').send_cli()
|
||||
assert_equal(set(generate.keys()), {'address', 'blocks'})
|
||||
assert_equal(len(generate["blocks"]), 1)
|
||||
assert_equal(self.nodes[0].getblockcount(), blocks + 1)
|
||||
|
||||
self.log.info('Test -generate with bad args')
|
||||
assert_raises_process_error(1, JSON_PARSING_ERROR, self.nodes[0].cli('-generate', 'foo').echo)
|
||||
assert_raises_process_error(1, BLOCKS_VALUE_OF_ZERO, self.nodes[0].cli('-generate', 0).echo)
|
||||
assert_raises_process_error(1, TOO_MANY_ARGS, self.nodes[0].cli('-generate', 1, 2, 3).echo)
|
||||
|
||||
self.log.info('Test -generate with nblocks')
|
||||
generate = self.nodes[0].cli('-generate', n1).send_cli()
|
||||
assert_equal(set(generate.keys()), {'address', 'blocks'})
|
||||
assert_equal(len(generate["blocks"]), n1)
|
||||
assert_equal(self.nodes[0].getblockcount(), blocks + 1 + n1)
|
||||
|
||||
self.log.info('Test -generate with nblocks and maxtries')
|
||||
generate = self.nodes[0].cli('-generate', n2, 1000000).send_cli()
|
||||
assert_equal(set(generate.keys()), {'address', 'blocks'})
|
||||
assert_equal(len(generate["blocks"]), n2)
|
||||
assert_equal(self.nodes[0].getblockcount(), blocks + 1 + n1 + n2)
|
||||
|
||||
self.log.info('Test -generate -rpcwallet in single-wallet mode')
|
||||
generate = self.nodes[0].cli(rpcwallet2, '-generate').send_cli()
|
||||
assert_equal(set(generate.keys()), {'address', 'blocks'})
|
||||
assert_equal(len(generate["blocks"]), 1)
|
||||
assert_equal(self.nodes[0].getblockcount(), blocks + 2 + n1 + n2)
|
||||
|
||||
self.log.info('Test -generate -rpcwallet=unloaded wallet raises RPC error')
|
||||
assert_raises_rpc_error(-18, WALLET_NOT_LOADED, self.nodes[0].cli(rpcwallet3, '-generate').echo)
|
||||
assert_raises_rpc_error(-18, WALLET_NOT_LOADED, self.nodes[0].cli(rpcwallet3, '-generate', 'foo').echo)
|
||||
assert_raises_rpc_error(-18, WALLET_NOT_LOADED, self.nodes[0].cli(rpcwallet3, '-generate', 0).echo)
|
||||
assert_raises_rpc_error(-18, WALLET_NOT_LOADED, self.nodes[0].cli(rpcwallet3, '-generate', 1, 2, 3).echo)
|
||||
|
||||
# Test bitcoin-cli -generate with -rpcwallet in multiwallet mode.
|
||||
self.nodes[0].loadwallet(wallets[2])
|
||||
n3 = 4
|
||||
n4 = 10
|
||||
blocks = self.nodes[0].getblockcount()
|
||||
|
||||
self.log.info('Test -generate -rpcwallet with no args')
|
||||
generate = self.nodes[0].cli(rpcwallet2, '-generate').send_cli()
|
||||
assert_equal(set(generate.keys()), {'address', 'blocks'})
|
||||
assert_equal(len(generate["blocks"]), 1)
|
||||
assert_equal(self.nodes[0].getblockcount(), blocks + 1)
|
||||
|
||||
self.log.info('Test -generate -rpcwallet with bad args')
|
||||
assert_raises_process_error(1, JSON_PARSING_ERROR, self.nodes[0].cli(rpcwallet2, '-generate', 'foo').echo)
|
||||
assert_raises_process_error(1, BLOCKS_VALUE_OF_ZERO, self.nodes[0].cli(rpcwallet2, '-generate', 0).echo)
|
||||
assert_raises_process_error(1, TOO_MANY_ARGS, self.nodes[0].cli(rpcwallet2, '-generate', 1, 2, 3).echo)
|
||||
|
||||
self.log.info('Test -generate -rpcwallet with nblocks')
|
||||
generate = self.nodes[0].cli(rpcwallet2, '-generate', n3).send_cli()
|
||||
assert_equal(set(generate.keys()), {'address', 'blocks'})
|
||||
assert_equal(len(generate["blocks"]), n3)
|
||||
assert_equal(self.nodes[0].getblockcount(), blocks + 1 + n3)
|
||||
|
||||
self.log.info('Test -generate -rpcwallet with nblocks and maxtries')
|
||||
generate = self.nodes[0].cli(rpcwallet2, '-generate', n4, 1000000).send_cli()
|
||||
assert_equal(set(generate.keys()), {'address', 'blocks'})
|
||||
assert_equal(len(generate["blocks"]), n4)
|
||||
assert_equal(self.nodes[0].getblockcount(), blocks + 1 + n3 + n4)
|
||||
|
||||
self.log.info('Test -generate without -rpcwallet in multiwallet mode raises RPC error')
|
||||
assert_raises_rpc_error(-19, WALLET_NOT_SPECIFIED, self.nodes[0].cli('-generate').echo)
|
||||
assert_raises_rpc_error(-19, WALLET_NOT_SPECIFIED, self.nodes[0].cli('-generate', 'foo').echo)
|
||||
assert_raises_rpc_error(-19, WALLET_NOT_SPECIFIED, self.nodes[0].cli('-generate', 0).echo)
|
||||
assert_raises_rpc_error(-19, WALLET_NOT_SPECIFIED, self.nodes[0].cli('-generate', 1, 2, 3).echo)
|
||||
else:
|
||||
self.log.info("*** Wallet not compiled; cli getwalletinfo and -getinfo wallet tests skipped")
|
||||
self.nodes[0].generate(1) # maintain block parity with the wallet_compiled conditional branch
|
||||
self.nodes[0].generate(25) # maintain block parity with the wallet_compiled conditional branch
|
||||
|
||||
self.log.info("Test -version with node stopped")
|
||||
self.stop_node(0)
|
||||
|
@ -145,7 +235,7 @@ class TestBitcoinCli(BitcoinTestFramework):
|
|||
self.nodes[0].wait_for_cookie_credentials() # ensure cookie file is available to avoid race condition
|
||||
blocks = self.nodes[0].cli('-rpcwait').send_cli('getblockcount')
|
||||
self.nodes[0].wait_for_rpc_connection()
|
||||
assert_equal(blocks, BLOCKS + 1)
|
||||
assert_equal(blocks, BLOCKS + 25)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
Loading…
Add table
Reference in a new issue