util: Add CHECK_NONFATAL and use it in src/rpc

This commit is contained in:
MarcoFalke 2019-09-23 14:45:51 -04:00
parent 0ff7cd7d0c
commit faeb666536
No known key found for this signature in database
GPG key ID: CE2B75697E69A548
6 changed files with 63 additions and 10 deletions

View file

@ -206,6 +206,7 @@ BITCOIN_CORE_H = \
undo.h \
util/bip32.h \
util/bytevectorhash.h \
util/check.h \
util/error.h \
util/fees.h \
util/spanparsing.h \

View file

@ -10,11 +10,11 @@
#include <chain.h>
#include <chainparams.h>
#include <coins.h>
#include <node/coinstats.h>
#include <consensus/validation.h>
#include <core_io.h>
#include <hash.h>
#include <index/blockfilterindex.h>
#include <node/coinstats.h>
#include <policy/feerate.h>
#include <policy/policy.h>
#include <policy/rbf.h>
@ -34,7 +34,6 @@
#include <validationinterface.h>
#include <warnings.h>
#include <assert.h>
#include <stdint.h>
#include <univalue.h>

View file

@ -3,15 +3,16 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <key_io.h>
#include <httpserver.h>
#include <key_io.h>
#include <outputtype.h>
#include <rpc/blockchain.h>
#include <rpc/server.h>
#include <rpc/util.h>
#include <script/descriptor.h>
#include <util/system.h>
#include <util/check.h>
#include <util/strencodings.h>
#include <util/system.h>
#include <util/validation.h>
#include <stdint.h>
@ -540,6 +541,7 @@ static UniValue echo(const JSONRPCRequest& request)
throw std::runtime_error(
RPCHelpMan{"echo|echojson ...",
"\nSimply echo back the input arguments. This command is for testing.\n"
"\nIt will return an internal bug report when exactly 100 arguments are passed.\n"
"\nThe difference between echo and echojson is that echojson has argument conversion enabled in the client-side table in "
"bitcoin-cli and the GUI. There is no server-side difference.",
{},
@ -548,6 +550,8 @@ static UniValue echo(const JSONRPCRequest& request)
}.ToString()
);
CHECK_NONFATAL(request.params.size() != 100);
return request.params;
}

View file

@ -7,14 +7,15 @@
#include <node/transaction.h>
#include <outputtype.h>
#include <pubkey.h>
#include <protocol.h>
#include <pubkey.h>
#include <rpc/protocol.h>
#include <rpc/request.h>
#include <script/script.h>
#include <script/sign.h>
#include <script/standard.h>
#include <univalue.h>
#include <util/check.h>
#include <string>
#include <vector>
@ -146,7 +147,7 @@ struct RPCArg {
m_oneline_description{oneline_description},
m_type_str{type_str}
{
assert(type != Type::ARR && type != Type::OBJ);
CHECK_NONFATAL(type != Type::ARR && type != Type::OBJ);
}
RPCArg(
@ -165,7 +166,7 @@ struct RPCArg {
m_oneline_description{oneline_description},
m_type_str{type_str}
{
assert(type == Type::ARR || type == Type::OBJ);
CHECK_NONFATAL(type == Type::ARR || type == Type::OBJ);
}
bool IsOptional() const;
@ -194,14 +195,14 @@ struct RPCResult {
explicit RPCResult(std::string result)
: m_cond{}, m_result{std::move(result)}
{
assert(!m_result.empty());
CHECK_NONFATAL(!m_result.empty());
}
RPCResult(std::string cond, std::string result)
: m_cond{std::move(cond)}, m_result{std::move(result)}
{
assert(!m_cond.empty());
assert(!m_result.empty());
CHECK_NONFATAL(!m_cond.empty());
CHECK_NONFATAL(!m_result.empty());
}
};

41
src/util/check.h Normal file
View file

@ -0,0 +1,41 @@
// Copyright (c) 2019 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_UTIL_CHECK_H
#define BITCOIN_UTIL_CHECK_H
#include <tinyformat.h>
#include <stdexcept>
class NonFatalCheckError : public std::runtime_error
{
using std::runtime_error::runtime_error;
};
/**
* Throw a NonFatalCheckError when the condition evaluates to false
*
* This should only be used
* - where the condition is assumed to be true, not for error handling or validating user input
* - where a failure to fulfill the condition is recoverable and does not abort the program
*
* For example in RPC code, where it is undersirable to crash the whole program, this can be generally used to replace
* asserts or recoverable logic errors. A NonFatalCheckError in RPC code is caught and passed as a string to the RPC
* caller, which can then report the issue to the developers.
*/
#define CHECK_NONFATAL(condition) \
do { \
if (!(condition)) { \
throw NonFatalCheckError( \
strprintf("%s:%d (%s)\n" \
"Internal bug detected: '%s'\n" \
"You may report this issue here: %s\n", \
__FILE__, __LINE__, __func__, \
(#condition), \
PACKAGE_BUGREPORT)); \
} \
} while (false)
#endif // BITCOIN_UTIL_CHECK_H

View file

@ -23,6 +23,13 @@ class RpcMiscTest(BitcoinTestFramework):
def run_test(self):
node = self.nodes[0]
self.log.info("test CHECK_NONFATAL")
assert_raises_rpc_error(
-1,
"Internal bug detected: 'request.params.size() != 100'",
lambda: node.echo(*[0] * 100),
)
self.log.info("test getmemoryinfo")
memory = node.getmemoryinfo()['locked']
assert_greater_than(memory['used'], 0)