Compare commits

...

14 Commits

Author SHA1 Message Date
Konstantin Akimov
3fd6f48872
Merge c2817106c6 into 032fc21198 2024-12-15 18:13:05 +00:00
pasta
032fc21198
Merge #6479: feat: enable coverage linter for functional tests
2e509b96c4 fix: add a workaround for RPC getmerkleblocks, debug, coinjoinsalt, voteraw (Konstantin Akimov)
f0decc8790 feat: add unit test for ClearDiscouraged (Konstantin Akimov)
865b24ea00 feat: hide cleardiscouraged RPC so far as it no intent to use by regular users (Konstantin Akimov)
1f5fa7e7cf feat: enable linter coverage for functional tests (Konstantin Akimov)
59ddac5656 feat: hide deprecated RPC from help and add TODOes to remove them (Konstantin Akimov)
05732aceaf feat: implement functional tests for RPC getblockheaders (Konstantin Akimov)

Pull request description:

  ## Issue being fixed or feature implemented
  https://github.com/dashpay/dash-issues/issues/63

  ## What was done?
  Add functional tests for `getblockheaders`
  Hide RPC `cleardiscouraged` (as it is used only for functional tests) and RPC `getpoolinfo` (deprecated long time ago)
  Add a workaround to ignore these RPCs `getmerkleblocks`, `voteraw`, `debug`, `coinjoinsalt` at the moment
  Enables linter for coverage

  ## How Has This Been Tested?
  Run locally with `test/functional/test_runner.py -j20 --previous-releases --coverage --extended`
  Enabled in CI

  ## Breaking Changes
  N/A if hidding `cleardiscouraged` is not a breaking change.

  ## Checklist:
  - [x] I have performed a self-review of my own code
  - [x] I have commented my code, particularly in hard-to-understand areas
  - [x] I have added or updated relevant unit/integration/functional/e2e tests
  - [x] I have made corresponding changes to the documentation
  - [x] I have assigned this pull request to a milestone

ACKs for top commit:
  UdjinM6:
    LGTM, utACK 2e509b96c4
  PastaPastaPasta:
    utACK 2e509b96c4

Tree-SHA512: bb31465d9a71ef824533d9310393d89293c87c7407ec3e37697f6d36dc6c010381a6e0408f9598354e610d51ef662485d8a653cc0e198842e2198ac1c30c90f1
2024-12-15 12:12:40 -06:00
pasta
05ca6cffff
Merge #6489: ci: allow overriding MAKEJOBS
feb6a1ad3f ci: allow overriding MAKEJOBS (UdjinM6)

Pull request description:

  ## Issue being fixed or feature implemented
  That's how these variable are ment to behave
  >echo "Fallback to default values in env (if not yet set)"

  https://github.com/dashpay/dash/blame/develop/ci/test/00_setup_env.sh#L26

  That's also how it's done in bitcoin https://github.com/bitcoin/bitcoin/blob/master/ci/test/00_setup_env.sh#L38.

  But we broke it in c52992aaa4 and I'm not sure why 🤷‍♂️

  ## What was done?

  ## How Has This Been Tested?

  ## Breaking Changes

  ## Checklist:
  - [ ] I have performed a self-review of my own code
  - [ ] I have commented my code, particularly in hard-to-understand areas
  - [ ] I have added or updated relevant unit/integration/functional/e2e tests
  - [ ] I have made corresponding changes to the documentation
  - [ ] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_

ACKs for top commit:
  PastaPastaPasta:
    utACK feb6a1ad3f
  kwvg:
    utACK feb6a1ad3f

Tree-SHA512: 617e761cf5c52d8e4329bf8aa1680c72a7816ae3248ed415d2c3232e5aa0941f18e21f0d6d363848238f53730097aa22f51a6e1cd62bd0b31d3da853f9f79e28
2024-12-15 11:57:04 -06:00
UdjinM6
feb6a1ad3f
ci: allow overriding MAKEJOBS 2024-12-15 00:16:21 +03:00
Konstantin Akimov
2e509b96c4
fix: add a workaround for RPC getmerkleblocks, debug, coinjoinsalt, voteraw
We indeed doesn't have functional tests for them yet, but this linter will help to avoid
adding new RPCs without tests
2024-12-13 21:19:11 +07:00
Konstantin Akimov
f0decc8790
feat: add unit test for ClearDiscouraged 2024-12-13 21:19:11 +07:00
Konstantin Akimov
865b24ea00
feat: hide cleardiscouraged RPC so far as it no intent to use by regular users 2024-12-13 21:19:11 +07:00
Konstantin Akimov
1f5fa7e7cf
feat: enable linter coverage for functional tests 2024-12-13 21:19:11 +07:00
Konstantin Akimov
59ddac5656
feat: hide deprecated RPC from help and add TODOes to remove them 2024-12-13 21:19:11 +07:00
Konstantin Akimov
05732aceaf
feat: implement functional tests for RPC getblockheaders 2024-12-13 21:19:11 +07:00
Konstantin Akimov
c2817106c6
fixup removal 2024-12-12 19:19:12 +07:00
Konstantin Akimov
a8798c8662
docs: added release notes for removal of -platform-user 2024-12-12 19:18:06 +07:00
Konstantin Akimov
6144978c4e
feat!: remove deprecated command-line option -platform-user 2024-12-12 19:17:59 +07:00
Konstantin Akimov
46183c6d53
chore: removed functional test rpc_deprecated_platform_filter.py 2024-12-12 19:13:48 +07:00
15 changed files with 56 additions and 241 deletions

View File

@ -25,8 +25,7 @@ export JOB_NUMBER=${JOB_NUMBER:-1}
echo "Fallback to default values in env (if not yet set)"
# The number of parallel jobs to pass down to make and test_runner.py
MAKEJOBS="-j$(nproc)"
export MAKEJOBS
export MAKEJOBS=${MAKEJOBS:--j$(nproc)}
# A folder for the ci system to put temporary files (ccache, datadirs for tests, ...)
# This folder only exists on the ci host.
export BASE_SCRATCH_DIR=${BASE_SCRATCH_DIR:-$BASE_ROOT_DIR/ci/scratch}

View File

@ -9,8 +9,7 @@ export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_native_qt5
export PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libdbus-1-dev libharfbuzz-dev"
export DEP_OPTS="NO_UPNP=1 DEBUG=1"
# TODO: we have few rpcs that aren't covered by any test, re-enable the line below once it's fixed
# export TEST_RUNNER_EXTRA="--previous-releases --coverage --extended --exclude feature_pruning,feature_dbcrash" # Run extended tests so that coverage does not fail, but exclude the very slow dbcrash
export TEST_RUNNER_EXTRA="--previous-releases --coverage --extended --exclude feature_pruning,feature_dbcrash" # Run extended tests so that coverage does not fail, but exclude the very slow dbcrash
export RUN_UNIT_TESTS_SEQUENTIAL="true"
export RUN_UNIT_TESTS="false"
export GOAL="install"

View File

@ -0,0 +1,7 @@
## Command-line Options
### Changes in Existing Command-line Options
- **`-platform-user`**
- Removed in v23, since deprecated in v22 and never has been used by platform

View File

@ -122,9 +122,6 @@ static bool JSONErrorReply(RpcHttpRequest& rpcRequest, const UniValue& objError,
nStatus = HTTP_BAD_REQUEST;
else if (code == RPC_METHOD_NOT_FOUND)
nStatus = HTTP_NOT_FOUND;
else if (code == RPC_PLATFORM_RESTRICTION) {
nStatus = HTTP_FORBIDDEN;
}
std::string strReply = JSONRPCReply(NullUniValue, objError, id);

View File

@ -1515,8 +1515,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
GetMainSignals().RegisterBackgroundSignalScheduler(*node.scheduler);
tableRPC.InitPlatformRestrictions();
/* Register RPC commands regardless of -server setting so they will be
* available in the GUI RPC console even if external calls are disabled.
*/

View File

@ -365,6 +365,7 @@ static RPCHelpMan coinjoinsalt_set()
}
#endif // ENABLE_WALLET
// TODO: remove it completely
static RPCHelpMan getpoolinfo()
{
return RPCHelpMan{"getpoolinfo",
@ -469,7 +470,6 @@ void RegisterCoinJoinRPCCommands(CRPCTable &t)
static const CRPCCommand commands[] =
{ // category actor (function)
// --------------------- -----------------------
{ "dash", &getpoolinfo, },
{ "dash", &getcoinjoininfo, },
#ifdef ENABLE_WALLET
{ "dash", &coinjoin, },
@ -480,6 +480,8 @@ static const CRPCCommand commands[] =
{ "dash", &coinjoinsalt_generate, },
{ "dash", &coinjoinsalt_get, },
{ "dash", &coinjoinsalt_set, },
{ "hidden", &getpoolinfo, },
#endif // ENABLE_WALLET
};
// clang-format on

View File

@ -134,6 +134,7 @@ static UniValue GetNextMasternodeForPayment(const CChain& active_chain, CDetermi
return obj;
}
// TODO: drop it
static RPCHelpMan masternode_winner()
{
return RPCHelpMan{"masternode winner",
@ -154,6 +155,7 @@ static RPCHelpMan masternode_winner()
};
}
// TODO: drop it
static RPCHelpMan masternode_current()
{
return RPCHelpMan{"masternode current",
@ -227,7 +229,7 @@ static RPCHelpMan masternode_status()
}
UniValue mnObj(UniValue::VOBJ);
// keep compatibility with legacy status for now (might get deprecated/removed later)
// keep compatibility with legacy status for now (TODO: get deprecated/removed later)
mnObj.pushKV("outpoint", node.mn_activeman->GetOutPoint().ToStringShort());
mnObj.pushKV("service", node.mn_activeman->GetService().ToStringAddrPort());
auto dmn = CHECK_NONFATAL(node.dmnman)->GetListAtChainTip().GetMN(node.mn_activeman->GetProTxHash());
@ -750,8 +752,8 @@ static const CRPCCommand commands[] =
{ "dash", &masternode_status, },
{ "dash", &masternode_payments, },
{ "dash", &masternode_winners, },
{ "dash", &masternode_current, },
{ "dash", &masternode_winner, },
{ "hidden", &masternode_current, },
{ "hidden", &masternode_winner, },
};
// clang-format on
for (const auto& command : commands) {

View File

@ -241,7 +241,7 @@ static RPCHelpMan getpeerinfo()
obj.pushKV("masternode", stats.m_masternode_connection);
if (fStateStats) {
if (IsDeprecatedRPCEnabled("banscore")) {
// banscore is deprecated in v21 for removal in v22
// TODO: banscore is deprecated in v21 for removal in v22, maybe impossible due to usages in p2p_quorum_data.py
obj.pushKV("banscore", statestats.m_misbehavior_score);
}
obj.pushKV("startingheight", statestats.m_starting_height);
@ -1126,10 +1126,10 @@ static const CRPCCommand commands[] =
{ "network", &setban, },
{ "network", &listbanned, },
{ "network", &clearbanned, },
{ "network", &cleardiscouraged, },
{ "network", &setnetworkactive, },
{ "network", &getnodeaddresses, },
{ "hidden", &cleardiscouraged, },
{ "hidden", &addconnection, },
{ "hidden", &addpeeraddress, },
{ "hidden", &sendmsgtopeer },

View File

@ -48,7 +48,7 @@ enum RPCErrorCode
RPC_VERIFY_ALREADY_IN_CHAIN = -27, //!< Transaction already in chain
RPC_IN_WARMUP = -28, //!< Client still warming up
RPC_METHOD_DEPRECATED = -32, //!< RPC method is deprecated
RPC_PLATFORM_RESTRICTION = -33, //!< This RPC command cannot be run by platform-user
RPC_RESERVED_UNUSED = -33, //!< This RPC code has been used in past, let it be reserved
//! Aliases for backward compatibility
RPC_TRANSACTION_ERROR = RPC_VERIFY_ERROR,

View File

@ -6,10 +6,6 @@
#include <rpc/server.h>
#include <chainparams.h>
#include <node/context.h>
#include <rpc/blockchain.h>
#include <rpc/server_util.h>
#include <rpc/util.h>
#include <shutdown.h>
#include <sync.h>
@ -20,7 +16,6 @@
#include <boost/signals2/signal.hpp>
#include <algorithm>
#include <atomic>
#include <cassert>
#include <chrono>
@ -37,10 +32,7 @@ static RPCTimerInterface* timerInterface = nullptr;
/* Map of name to timer. */
static Mutex g_deadline_timers_mutex;
static std::map<std::string, std::unique_ptr<RPCTimerBase> > deadlineTimers GUARDED_BY(g_deadline_timers_mutex);
static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& request, UniValue& result, bool last_handler, const std::multimap<std::string, std::vector<UniValue>>& mapPlatformRestrictions);
// Any commands submitted by this user will have their commands filtered based on the mapPlatformRestrictions
static const std::string defaultPlatformUser = "platform-user";
static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& request, UniValue& result, bool last_handler);
struct RPCCommandExecutionInfo
{
@ -150,21 +142,6 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest&
return strRet;
}
void CRPCTable::InitPlatformRestrictions()
{
mapPlatformRestrictions = {
{"getassetunlockstatuses", {}},
{"getbestblockhash", {}},
{"getblockhash", {}},
{"getblockcount", {}},
{"getbestchainlock", {}},
{"quorum sign", {static_cast<uint8_t>(Params().GetConsensus().llmqTypePlatform)}},
{"quorum verify", {}},
{"submitchainlock", {}},
{"verifyislock", {}},
};
}
static RPCHelpMan help()
{
return RPCHelpMan{"help",
@ -507,10 +484,10 @@ static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, c
return out;
}
static bool ExecuteCommands(const std::vector<const CRPCCommand*>& commands, const JSONRPCRequest& request, UniValue& result, const std::multimap<std::string, std::vector<UniValue>>& mapPlatformRestrictions)
static bool ExecuteCommands(const std::vector<const CRPCCommand*>& commands, const JSONRPCRequest& request, UniValue& result)
{
for (const auto& command : commands) {
if (ExecuteCommand(*command, request, result, &command == &commands.back(), mapPlatformRestrictions)) {
if (ExecuteCommand(*command, request, result, &command == &commands.back())) {
return true;
}
}
@ -542,78 +519,15 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const
if (it != mapCommands.end()) {
UniValue result;
const JSONRPCRequest new_request{subcommand.empty() ? request : request.squashed() };
if (ExecuteCommands(it->second, new_request, result, mapPlatformRestrictions)) {
if (ExecuteCommands(it->second, new_request, result)) {
return result;
}
}
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
}
static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& request, UniValue& result, bool last_handler, const std::multimap<std::string, std::vector<UniValue>>& mapPlatformRestrictions)
static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& request, UniValue& result, bool last_handler)
{
const NodeContext& node = EnsureAnyNodeContext(request.context);
// Before executing the RPC Command, filter commands from platform rpc user
if (node.mn_activeman && request.authUser == gArgs.GetArg("-deprecated-platform-user", defaultPlatformUser)) {
// replace this with structured binding in c++20
std::string command_name = command.name;
const auto& it = mapPlatformRestrictions.equal_range(command_name);
const auto& allowed_begin = it.first;
const auto& allowed_end = it.second;
/**
* allowed_begin and allowed_end are iterators that represent a range of [method_name, vec_params]
* For example, assume allowed = `quorum sign platformLlmqType`, `quorum verify` and `verifyislock`
* this range will look like:
*
* if request.strMethod == "quorum":
* [
* "quorum sign", [platformLlmqType],
* "quorum verify", []
* ]
* if request.strMethod == "verifyislock"
* [
* "verifyislock", []
* ]
*/
// If the requested method is not available in mapPlatformRestrictions
if (allowed_begin == allowed_end) {
throw JSONRPCError(RPC_PLATFORM_RESTRICTION, strprintf("Method \"%s\" prohibited", request.strMethod));
}
auto isValidRequest = [&request, &allowed_begin, &allowed_end]() {
for (auto itRequest = allowed_begin; itRequest != allowed_end; ++itRequest) {
// This is an individual group of parameters that is valid
// This will look something like `["sign", platformLlmqType]` from above.
const auto& vecAllowedParam = itRequest->second;
// An empty vector of allowed parameters represents that any parameter is allowed.
if (vecAllowedParam.empty()) {
return true;
}
if (request.params.empty()) {
throw JSONRPCError(RPC_PLATFORM_RESTRICTION, strprintf("Method \"%s\" has parameter restrictions.", request.strMethod));
}
if (request.params.size() < vecAllowedParam.size()) {
continue;
}
if (std::equal(vecAllowedParam.begin(), vecAllowedParam.end(),
request.params.getValues().begin(),
[](const UniValue& left, const UniValue& right) {
return left.type() == right.type() && left.getValStr() == right.getValStr();
})) {
return true;
}
}
return false;
};
// Try if any of the mapPlatformRestrictions entries matches the current request
if (!isValidRequest()) {
throw JSONRPCError(RPC_PLATFORM_RESTRICTION, "Request doesn't comply with the parameter restrictions.");
}
}
try
{
RPCCommandExecution execution(request.strMethod);
@ -647,7 +561,7 @@ UniValue CRPCTable::dumpArgMap(const JSONRPCRequest& args_request) const
// TODO: implement mapping argument to type for composite commands
if (cmd.first.find(' ') != std::string::npos) continue;
UniValue result;
if (ExecuteCommands(cmd.second, request, result, mapPlatformRestrictions)) {
if (ExecuteCommands(cmd.second, request, result)) {
for (const auto& values : result.getValues()) {
ret.push_back(values);
}

View File

@ -124,13 +124,10 @@ class CRPCTable
{
private:
std::map<std::string, std::vector<const CRPCCommand*>> mapCommands;
std::multimap<std::string, std::vector<UniValue>> mapPlatformRestrictions;
public:
CRPCTable();
std::string help(const std::string& name, const JSONRPCRequest& helpreq) const;
void InitPlatformRestrictions();
/**
* Execute a method.
* @param request The JSONRPCRequest to execute

View File

@ -450,6 +450,8 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
peerLogic->Misbehaving(dummyNode.GetId(), DISCOURAGEMENT_THRESHOLD);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode));
BOOST_CHECK(banman->IsDiscouraged(addr));
banman->ClearDiscouraged();
BOOST_CHECK(!banman->IsDiscouraged(addr));
peerLogic->FinalizeNode(dummyNode);
}

View File

@ -9,6 +9,7 @@ Test the following RPCs:
- getchaintxstats
- gettxoutsetinfo
- getblockheader
- getblockheaders
- getdifficulty
- getnetworkhashps
- waitforblockheight
@ -76,7 +77,8 @@ class BlockchainTest(BitcoinTestFramework):
self._test_getblockchaininfo()
self._test_getchaintxstats()
self._test_gettxoutsetinfo()
self._test_getblockheader()
self._test_getblockheader(rpc_name='getblockheader')
self._test_getblockheader(rpc_name='getblockheaders')
self._test_getdifficulty()
self._test_getnetworkhashps()
self._test_stopatheight()
@ -319,17 +321,20 @@ class BlockchainTest(BitcoinTestFramework):
# Unknown hash_type raises an error
assert_raises_rpc_error(-8, "'foo hash' is not a valid hash_type", node.gettxoutsetinfo, "foo hash")
def _test_getblockheader(self):
self.log.info("Test getblockheader")
def _test_getblockheader(self, rpc_name):
self.log.info(f"Test {rpc_name}")
node = self.nodes[0]
assert_raises_rpc_error(-8, "hash must be of length 64 (not 8, for 'nonsense')", node.getblockheader, "nonsense")
assert_raises_rpc_error(-8, "hash must be hexadecimal string (not 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844')", node.getblockheader, "ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844")
assert_raises_rpc_error(-5, "Block not found", node.getblockheader, "0cf7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844")
rpc_call = getattr(node, rpc_name)
assert_raises_rpc_error(-8, "hash must be of length 64 (not 8, for 'nonsense')", rpc_call, "nonsense")
assert_raises_rpc_error(-8, "hash must be hexadecimal string (not 'ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844')", rpc_call, "ZZZ7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844")
assert_raises_rpc_error(-5, "Block not found", rpc_call, "0cf7bb8b1697ea987f3b223ba7819250cae33efacb068d23dc24859824a77844")
besthash = node.getbestblockhash()
secondbesthash = node.getblockhash(HEIGHT - 1)
header = node.getblockheader(blockhash=besthash)
header = rpc_call(blockhash=besthash)
if rpc_name == 'getblockheaders':
assert_equal(len(header), 1)
header = header[0]
assert_equal(header['hash'], besthash)
assert_equal(header['height'], HEIGHT)
@ -349,15 +354,19 @@ class BlockchainTest(BitcoinTestFramework):
assert isinstance(header['difficulty'], Decimal)
# Test with verbose=False, which should return the header as hex.
header_hex = node.getblockheader(blockhash=besthash, verbose=False)
header_hex = rpc_call(blockhash=besthash, verbose=False)
if rpc_name == 'getblockheaders':
header_hex = header_hex[0]
assert_is_hex_string(header_hex)
header = from_hex(CBlockHeader(), header_hex)
header.calc_sha256()
assert_equal(header.hash, besthash)
assert 'previousblockhash' not in node.getblockheader(node.getblockhash(0))
assert 'nextblockhash' not in node.getblockheader(node.getbestblockhash())
if rpc_name == 'getblockheader':
assert 'previousblockhash' not in node.getblockheader(node.getblockhash(0))
assert 'nextblockhash' not in node.getblockheader(node.getbestblockhash())
def _test_getdifficulty(self):
self.log.info("Test getdifficulty")

View File

@ -1,118 +0,0 @@
#!/usr/bin/env python3
# Copyright (c) 2020-2024 The Dash Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test that commands submitted by the platform user are filtered."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import str_to_b64str, assert_equal
import http.client
import json
import os
import urllib.parse
class HTTPBasicsTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.supports_cli = False
def setup_nodes(self):
self.add_nodes(self.num_nodes)
self.start_nodes()
def setup_chain(self):
super().setup_chain()
# Append rpcauth to dash.conf before initialization
rpcauthplatform = "rpcauth=platform-user:dd88fd676186f48553775d6fb5a2d344$bc1f7898698ead19c6ec7ff47055622dd7101478f1ff6444103d3dc03cd77c13"
# rpcuser : platform-user
# rpcpassword : password123
rpcauthoperator = "rpcauth=operator:e9b45dd0b61a7be72155535435365a3a$8fb7470bc6f74d8ceaf9a23f49b06127723bd563b3ed5d9cea776ef01803d191"
# rpcuser : operator
# rpcpassword : otherpassword
masternodeblskey="masternodeblsprivkey=58af6e39bb4d86b22bda1a02b134c2f5b71caffa1377540b02f7f1ad122f59e0"
with open(os.path.join(self.options.tmpdir+"/node0", "dash.conf"), 'a', encoding='utf8') as f:
f.write(masternodeblskey+"\n")
f.write(rpcauthplatform+"\n")
f.write(rpcauthoperator+"\n")
def run_test(self):
url = urllib.parse.urlparse(self.nodes[0].url)
def test_command(method, params, auth, expected_status, should_not_match=False):
conn = http.client.HTTPConnection(url.hostname, url.port)
conn.connect()
body = {"method": method}
if len(params):
body["params"] = params
conn.request('POST', '/', json.dumps(body), {"Authorization": "Basic " + str_to_b64str(auth)})
resp = conn.getresponse()
if should_not_match:
assert resp.status != expected_status
else:
assert_equal(resp.status, expected_status)
conn.close()
whitelisted = ["getassetunlockstatuses",
"getbestblockhash",
"getblockhash",
"getblockcount",
"getbestchainlock",
"quorum",
"submitchainlock",
"verifyislock"]
help_output = self.nodes[0].help().split('\n')
nonwhitelisted = set()
for line in help_output:
line = line.strip()
# Ignore blanks, headers and whitelisted
if line and not line.startswith('='):
command = line.split()[0]
if not command in whitelisted:
nonwhitelisted.add(command)
rpcuser_authpair_platform = "platform-user:password123"
rpcuser_authpair_operator = "operator:otherpassword"
rpcuser_authpair_wrong = "platform-user:rpcpasswordwrong"
self.log.info('Try using a incorrect password for platform-user...')
test_command("getbestblockhash", [], rpcuser_authpair_wrong, 401)
self.log.info('Try using a correct password for platform-user and running all whitelisted commands...')
test_command("getbestblockhash", [], rpcuser_authpair_platform, 200)
test_command("getblockhash", [0], rpcuser_authpair_platform, 200)
test_command("getblockcount", [], rpcuser_authpair_platform, 200)
test_command("getbestchainlock", [], rpcuser_authpair_platform, 500)
test_command("quorum", ["sign", 106], rpcuser_authpair_platform, 500)
test_command("quorum", ["sign", 106, "0000000000000000000000000000000000000000000000000000000000000000",
"0000000000000000000000000000000000000000000000000000000000000001"],
rpcuser_authpair_platform, 200)
test_command("quorum", ["verify"], rpcuser_authpair_platform, 500)
test_command("verifyislock", [], rpcuser_authpair_platform, 500)
self.log.info('Try using some invalid combinations for platform-user')
test_command("quorum", [], rpcuser_authpair_platform, 403)
test_command("quorum", ["sign"], rpcuser_authpair_platform, 403)
test_command("quorum", ["sign", 102], rpcuser_authpair_platform, 403)
test_command("quorum", ["sign", "100"], rpcuser_authpair_platform, 403)
test_command("quorum", ["dkgsimerror"], rpcuser_authpair_platform, 403)
self.log.info('Try running all non-whitelisted commands as each user...')
for command in nonwhitelisted:
test_command(command, [], rpcuser_authpair_platform, 403)
if command != "stop": # avoid stopping the node while testing
# we don't care about the exact status here, should simply be anything else but 403
test_command(command, [], rpcuser_authpair_operator, 403, True)
self.log.info('Try running a not whitelisted command as the operator...')
test_command("debug", ["1"], rpcuser_authpair_operator, 200)
if __name__ == '__main__':
HTTPBasicsTest().main()

View File

@ -338,7 +338,6 @@ BASE_SCRIPTS = [
'wallet_send.py --descriptors',
'wallet_create_tx.py --descriptors',
'p2p_fingerprint.py',
'rpc_deprecated_platform_filter.py',
'rpc_external_queue.py',
'rpc_wipewallettxes.py',
'feature_uacomment.py',
@ -892,6 +891,14 @@ class RPCCoverage():
# Consider RPC generate covered, because it is overloaded in
# test_framework/test_node.py and not seen by the coverage check.
covered_cmds = set({'generate'})
# TODO: implement functional tests for coinjoinsalt
covered_cmds.add('coinjoinsalt')
# TODO: implement functional tests for voteraw
covered_cmds.add('voteraw')
# TODO: implement functional tests for getmerkleblocks
covered_cmds.add('getmerkleblocks')
# TODO: drop it with v23+: remove `debug` in favour of `logging`
covered_cmds.add('debug')
if not os.path.isfile(coverage_ref_filename):
raise RuntimeError("No coverage reference found")