aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rwxr-xr-xtest/functional/feature_cltv.py18
-rwxr-xr-xtest/functional/feature_dersig.py19
-rwxr-xr-xtest/functional/interface_rpc.py2
-rwxr-xr-xtest/functional/rpc_createmultisig.py5
-rwxr-xr-xtest/functional/rpc_psbt.py30
-rwxr-xr-xtest/functional/tool_wallet.py128
-rwxr-xr-xtest/functional/wallet_resendwallettransactions.py3
-rwxr-xr-xtest/lint/commit-script-check.sh8
-rwxr-xr-xtest/lint/extended-lint-all.sh26
-rwxr-xr-xtest/lint/extended-lint-cppcheck.sh80
-rwxr-xr-xtest/lint/lint-circular-dependencies.sh2
-rwxr-xr-xtest/lint/lint-format-strings.py3
-rwxr-xr-xtest/lint/lint-logs.sh1
-rwxr-xr-xtest/lint/lint-shell.sh16
14 files changed, 298 insertions, 43 deletions
diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py
index b16eafccca..7712e8bdf6 100755
--- a/test/functional/feature_cltv.py
+++ b/test/functional/feature_cltv.py
@@ -64,9 +64,23 @@ class BIP65Test(BitcoinTestFramework):
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
+ def test_cltv_info(self, *, is_active):
+ assert_equal(
+ next(s for s in self.nodes[0].getblockchaininfo()['softforks'] if s['id'] == 'bip65'),
+ {
+ "id": "bip65",
+ "version": 4,
+ "reject": {
+ "status": is_active
+ }
+ },
+ )
+
def run_test(self):
self.nodes[0].add_p2p_connection(P2PInterface())
+ self.test_cltv_info(is_active=False)
+
self.log.info("Mining %d blocks", CLTV_HEIGHT - 2)
self.coinbase_txids = [self.nodes[0].getblock(b)['tx'][0] for b in self.nodes[0].generate(CLTV_HEIGHT - 2)]
self.nodeaddress = self.nodes[0].getnewaddress()
@@ -86,7 +100,9 @@ class BIP65Test(BitcoinTestFramework):
block.hashMerkleRoot = block.calc_merkle_root()
block.solve()
+ self.test_cltv_info(is_active=False)
self.nodes[0].p2p.send_and_ping(msg_block(block))
+ self.test_cltv_info(is_active=False) # Not active as of current tip, but next block must obey rules
assert_equal(self.nodes[0].getbestblockhash(), block.hash)
self.log.info("Test that blocks must now be at least version 4")
@@ -135,7 +151,9 @@ class BIP65Test(BitcoinTestFramework):
block.hashMerkleRoot = block.calc_merkle_root()
block.solve()
+ self.test_cltv_info(is_active=False) # Not active as of current tip, but next block must obey rules
self.nodes[0].p2p.send_and_ping(msg_block(block))
+ self.test_cltv_info(is_active=True) # Active as of current tip
assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.sha256)
diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py
index 7480e5c5ba..067e3be1f4 100755
--- a/test/functional/feature_dersig.py
+++ b/test/functional/feature_dersig.py
@@ -51,9 +51,23 @@ class BIP66Test(BitcoinTestFramework):
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
+ def test_dersig_info(self, *, is_active):
+ assert_equal(
+ next(s for s in self.nodes[0].getblockchaininfo()['softforks'] if s['id'] == 'bip66'),
+ {
+ "id": "bip66",
+ "version": 3,
+ "reject": {
+ "status": is_active
+ }
+ },
+ )
+
def run_test(self):
self.nodes[0].add_p2p_connection(P2PInterface())
+ self.test_dersig_info(is_active=False)
+
self.log.info("Mining %d blocks", DERSIG_HEIGHT - 2)
self.coinbase_txids = [self.nodes[0].getblock(b)['tx'][0] for b in self.nodes[0].generate(DERSIG_HEIGHT - 2)]
self.nodeaddress = self.nodes[0].getnewaddress()
@@ -74,7 +88,9 @@ class BIP66Test(BitcoinTestFramework):
block.rehash()
block.solve()
+ self.test_dersig_info(is_active=False)
self.nodes[0].p2p.send_and_ping(msg_block(block))
+ self.test_dersig_info(is_active=False) # Not active as of current tip, but next block must obey rules
assert_equal(self.nodes[0].getbestblockhash(), block.hash)
self.log.info("Test that blocks must now be at least version 3")
@@ -128,8 +144,11 @@ class BIP66Test(BitcoinTestFramework):
block.rehash()
block.solve()
+ self.test_dersig_info(is_active=False) # Not active as of current tip, but next block must obey rules
self.nodes[0].p2p.send_and_ping(msg_block(block))
+ self.test_dersig_info(is_active=True) # Active as of current tip
assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.sha256)
+
if __name__ == '__main__':
BIP66Test().main()
diff --git a/test/functional/interface_rpc.py b/test/functional/interface_rpc.py
index 49ae0fb1a9..e99fa22646 100755
--- a/test/functional/interface_rpc.py
+++ b/test/functional/interface_rpc.py
@@ -4,6 +4,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Tests some generic aspects of the RPC interface."""
+import os
from test_framework.authproxy import JSONRPCException
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_greater_than_or_equal
@@ -31,6 +32,7 @@ class RPCInterfaceTest(BitcoinTestFramework):
command = info['active_commands'][0]
assert_equal(command['method'], 'getrpcinfo')
assert_greater_than_or_equal(command['duration'], 0)
+ assert_equal(info['logpath'], os.path.join(self.nodes[0].datadir, 'regtest', 'debug.log'))
def test_batch_request(self):
self.log.info("Testing basic JSON-RPC batch request...")
diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py
index 58010f7c2e..62f3843756 100755
--- a/test/functional/rpc_createmultisig.py
+++ b/test/functional/rpc_createmultisig.py
@@ -129,6 +129,11 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
outval = value - decimal.Decimal("0.00001000")
rawtx = node2.createrawtransaction([{"txid": txid, "vout": vout}], [{self.final: outval}])
+ prevtx_err = dict(prevtxs[0])
+ del prevtx_err["redeemScript"]
+
+ assert_raises_rpc_error(-8, "Missing redeemScript/witnessScript", node2.signrawtransactionwithkey, rawtx, self.priv[0:self.nsigs-1], [prevtx_err])
+
rawtx2 = node2.signrawtransactionwithkey(rawtx, self.priv[0:self.nsigs - 1], prevtxs)
rawtx3 = node2.signrawtransactionwithkey(rawtx2["hex"], [self.priv[-1]], prevtxs)
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
index f7fc10886a..b3d8696208 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -325,18 +325,32 @@ class PSBTTest(BitcoinTestFramework):
vout3 = find_output(self.nodes[0], txid3, 11)
self.sync_all()
- # Update a PSBT with UTXOs from the node
- # Bech32 inputs should be filled with witness UTXO. Other inputs should not be filled because they are non-witness
+ def test_psbt_input_keys(psbt_input, keys):
+ """Check that the psbt input has only the expected keys."""
+ assert_equal(set(keys), set(psbt_input.keys()))
+
+ # Create a PSBT. None of the inputs are filled initially
psbt = self.nodes[1].createpsbt([{"txid":txid1, "vout":vout1},{"txid":txid2, "vout":vout2},{"txid":txid3, "vout":vout3}], {self.nodes[0].getnewaddress():32.999})
decoded = self.nodes[1].decodepsbt(psbt)
- assert "witness_utxo" not in decoded['inputs'][0] and "non_witness_utxo" not in decoded['inputs'][0]
- assert "witness_utxo" not in decoded['inputs'][1] and "non_witness_utxo" not in decoded['inputs'][1]
- assert "witness_utxo" not in decoded['inputs'][2] and "non_witness_utxo" not in decoded['inputs'][2]
+ test_psbt_input_keys(decoded['inputs'][0], [])
+ test_psbt_input_keys(decoded['inputs'][1], [])
+ test_psbt_input_keys(decoded['inputs'][2], [])
+
+ # Update a PSBT with UTXOs from the node
+ # Bech32 inputs should be filled with witness UTXO. Other inputs should not be filled because they are non-witness
updated = self.nodes[1].utxoupdatepsbt(psbt)
decoded = self.nodes[1].decodepsbt(updated)
- assert "witness_utxo" in decoded['inputs'][0] and "non_witness_utxo" not in decoded['inputs'][0]
- assert "witness_utxo" not in decoded['inputs'][1] and "non_witness_utxo" not in decoded['inputs'][1]
- assert "witness_utxo" not in decoded['inputs'][2] and "non_witness_utxo" not in decoded['inputs'][2]
+ test_psbt_input_keys(decoded['inputs'][0], ['witness_utxo'])
+ test_psbt_input_keys(decoded['inputs'][1], [])
+ test_psbt_input_keys(decoded['inputs'][2], [])
+
+ # Try again, now while providing descriptors, making P2SH-segwit work, and causing bip32_derivs and redeem_script to be filled in
+ descs = [self.nodes[1].getaddressinfo(addr)['desc'] for addr in [addr1,addr2,addr3]]
+ updated = self.nodes[1].utxoupdatepsbt(psbt=psbt, descriptors=descs)
+ decoded = self.nodes[1].decodepsbt(updated)
+ test_psbt_input_keys(decoded['inputs'][0], ['witness_utxo', 'bip32_derivs'])
+ test_psbt_input_keys(decoded['inputs'][1], [])
+ test_psbt_input_keys(decoded['inputs'][2], ['witness_utxo', 'bip32_derivs', 'redeem_script'])
# Two PSBTs with a common input should not be joinable
psbt1 = self.nodes[1].createpsbt([{"txid":txid1, "vout":vout1}], {self.nodes[0].getnewaddress():Decimal('10.999')})
diff --git a/test/functional/tool_wallet.py b/test/functional/tool_wallet.py
index fbcf21e729..28a65f7823 100755
--- a/test/functional/tool_wallet.py
+++ b/test/functional/tool_wallet.py
@@ -1,14 +1,20 @@
#!/usr/bin/env python3
-# Copyright (c) 2018 The Bitcoin Core developers
+# Copyright (c) 2018-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.
"""Test bitcoin-wallet."""
+
+import hashlib
+import os
+import stat
import subprocess
import textwrap
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
+BUFFER_SIZE = 16 * 1024
+
class ToolWalletTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
@@ -32,23 +38,54 @@ class ToolWalletTest(BitcoinTestFramework):
def assert_tool_output(self, output, *args):
p = self.bitcoin_wallet_process(*args)
stdout, stderr = p.communicate()
- assert_equal(p.poll(), 0)
assert_equal(stderr, '')
assert_equal(stdout, output)
+ assert_equal(p.poll(), 0)
- def run_test(self):
+ def wallet_shasum(self):
+ h = hashlib.sha1()
+ mv = memoryview(bytearray(BUFFER_SIZE))
+ with open(self.wallet_path, 'rb', buffering=0) as f:
+ for n in iter(lambda : f.readinto(mv), 0):
+ h.update(mv[:n])
+ return h.hexdigest()
+ def wallet_timestamp(self):
+ return os.path.getmtime(self.wallet_path)
+
+ def wallet_permissions(self):
+ return oct(os.lstat(self.wallet_path).st_mode)[-3:]
+
+ def log_wallet_timestamp_comparison(self, old, new):
+ result = 'unchanged' if new == old else 'increased!'
+ self.log.debug('Wallet file timestamp {}'.format(result))
+
+ def test_invalid_tool_commands_and_args(self):
+ self.log.info('Testing that various invalid commands raise with specific error messages')
self.assert_raises_tool_error('Invalid command: foo', 'foo')
- # `bitcoin-wallet help` is an error. Use `bitcoin-wallet -help`
+ # `bitcoin-wallet help` raises an error. Use `bitcoin-wallet -help`.
self.assert_raises_tool_error('Invalid command: help', 'help')
self.assert_raises_tool_error('Error: two methods provided (info and create). Only one method should be provided.', 'info', 'create')
self.assert_raises_tool_error('Error parsing command line arguments: Invalid parameter -foo', '-foo')
self.assert_raises_tool_error('Error loading wallet.dat. Is wallet being used by other process?', '-wallet=wallet.dat', 'info')
self.assert_raises_tool_error('Error: no wallet file at nonexistent.dat', '-wallet=nonexistent.dat', 'info')
- # stop the node to close the wallet to call info command
+ def test_tool_wallet_info(self):
+ # Stop the node to close the wallet to call the info command.
self.stop_node(0)
-
+ self.log.info('Calling wallet tool info, testing output')
+ #
+ # TODO: Wallet tool info should work with wallet file permissions set to
+ # read-only without raising:
+ # "Error loading wallet.dat. Is wallet being used by another process?"
+ # The following lines should be uncommented and the tests still succeed:
+ #
+ # self.log.debug('Setting wallet file permissions to 400 (read-only)')
+ # os.chmod(self.wallet_path, stat.S_IRUSR)
+ # assert(self.wallet_permissions() in ['400', '666']) # Sanity check. 666 because Appveyor.
+ # shasum_before = self.wallet_shasum()
+ timestamp_before = self.wallet_timestamp()
+ self.log.debug('Wallet file timestamp before calling info: {}'.format(timestamp_before))
out = textwrap.dedent('''\
Wallet info
===========
@@ -59,12 +96,35 @@ class ToolWalletTest(BitcoinTestFramework):
Address Book: 3
''')
self.assert_tool_output(out, '-wallet=wallet.dat', 'info')
-
- # mutate the wallet to check the info command output changes accordingly
+ timestamp_after = self.wallet_timestamp()
+ self.log.debug('Wallet file timestamp after calling info: {}'.format(timestamp_after))
+ self.log_wallet_timestamp_comparison(timestamp_before, timestamp_after)
+ self.log.debug('Setting wallet file permissions back to 600 (read/write)')
+ os.chmod(self.wallet_path, stat.S_IRUSR | stat.S_IWUSR)
+ assert(self.wallet_permissions() in ['600', '666']) # Sanity check. 666 because Appveyor.
+ #
+ # TODO: Wallet tool info should not write to the wallet file.
+ # The following lines should be uncommented and the tests still succeed:
+ #
+ # assert_equal(timestamp_before, timestamp_after)
+ # shasum_after = self.wallet_shasum()
+ # assert_equal(shasum_before, shasum_after)
+ # self.log.debug('Wallet file shasum unchanged\n')
+
+ def test_tool_wallet_info_after_transaction(self):
+ """
+ Mutate the wallet with a transaction to verify that the info command
+ output changes accordingly.
+ """
self.start_node(0)
+ self.log.info('Generating transaction to mutate wallet')
self.nodes[0].generate(1)
self.stop_node(0)
+ self.log.info('Calling wallet tool info after generating a transaction, testing output')
+ shasum_before = self.wallet_shasum()
+ timestamp_before = self.wallet_timestamp()
+ self.log.debug('Wallet file timestamp before calling info: {}'.format(timestamp_before))
out = textwrap.dedent('''\
Wallet info
===========
@@ -75,7 +135,22 @@ class ToolWalletTest(BitcoinTestFramework):
Address Book: 3
''')
self.assert_tool_output(out, '-wallet=wallet.dat', 'info')
-
+ shasum_after = self.wallet_shasum()
+ timestamp_after = self.wallet_timestamp()
+ self.log.debug('Wallet file timestamp after calling info: {}'.format(timestamp_after))
+ self.log_wallet_timestamp_comparison(timestamp_before, timestamp_after)
+ #
+ # TODO: Wallet tool info should not write to the wallet file.
+ # This assertion should be uncommented and succeed:
+ # assert_equal(timestamp_before, timestamp_after)
+ assert_equal(shasum_before, shasum_after)
+ self.log.debug('Wallet file shasum unchanged\n')
+
+ def test_tool_wallet_create_on_existing_wallet(self):
+ self.log.info('Calling wallet tool create on an existing wallet, testing output')
+ shasum_before = self.wallet_shasum()
+ timestamp_before = self.wallet_timestamp()
+ self.log.debug('Wallet file timestamp before calling create: {}'.format(timestamp_before))
out = textwrap.dedent('''\
Topping up keypool...
Wallet info
@@ -87,15 +162,48 @@ class ToolWalletTest(BitcoinTestFramework):
Address Book: 0
''')
self.assert_tool_output(out, '-wallet=foo', 'create')
-
+ shasum_after = self.wallet_shasum()
+ timestamp_after = self.wallet_timestamp()
+ self.log.debug('Wallet file timestamp after calling create: {}'.format(timestamp_after))
+ self.log_wallet_timestamp_comparison(timestamp_before, timestamp_after)
+ assert_equal(timestamp_before, timestamp_after)
+ assert_equal(shasum_before, shasum_after)
+ self.log.debug('Wallet file shasum unchanged\n')
+
+ def test_getwalletinfo_on_different_wallet(self):
+ self.log.info('Starting node with arg -wallet=foo')
self.start_node(0, ['-wallet=foo'])
+
+ self.log.info('Calling getwalletinfo on a different wallet ("foo"), testing output')
+ shasum_before = self.wallet_shasum()
+ timestamp_before = self.wallet_timestamp()
+ self.log.debug('Wallet file timestamp before calling getwalletinfo: {}'.format(timestamp_before))
out = self.nodes[0].getwalletinfo()
self.stop_node(0)
+ shasum_after = self.wallet_shasum()
+ timestamp_after = self.wallet_timestamp()
+ self.log.debug('Wallet file timestamp after calling getwalletinfo: {}'.format(timestamp_after))
+
assert_equal(0, out['txcount'])
assert_equal(1000, out['keypoolsize'])
assert_equal(1000, out['keypoolsize_hd_internal'])
assert_equal(True, 'hdseedid' in out)
+ self.log_wallet_timestamp_comparison(timestamp_before, timestamp_after)
+ assert_equal(timestamp_before, timestamp_after)
+ assert_equal(shasum_after, shasum_before)
+ self.log.debug('Wallet file shasum unchanged\n')
+
+ def run_test(self):
+ self.wallet_path = os.path.join(self.nodes[0].datadir, 'regtest', 'wallets', 'wallet.dat')
+ self.test_invalid_tool_commands_and_args()
+ # Warning: The following tests are order-dependent.
+ self.test_tool_wallet_info()
+ self.test_tool_wallet_info_after_transaction()
+ self.test_tool_wallet_create_on_existing_wallet()
+ self.test_getwalletinfo_on_different_wallet()
+
+
if __name__ == '__main__':
ToolWalletTest().main()
diff --git a/test/functional/wallet_resendwallettransactions.py b/test/functional/wallet_resendwallettransactions.py
index 5810e94938..91d26e9cb3 100755
--- a/test/functional/wallet_resendwallettransactions.py
+++ b/test/functional/wallet_resendwallettransactions.py
@@ -57,8 +57,7 @@ class ResendWalletTransactionsTest(BitcoinTestFramework):
# after the last time we tried to broadcast. Use mocktime and give an extra minute to be sure.
block_time = int(time.time()) + 6 * 60
node.setmocktime(block_time)
- block = create_block(int(node.getbestblockhash(), 16), create_coinbase(node.getblockchaininfo()['blocks']), block_time)
- block.nVersion = 3
+ block = create_block(int(node.getbestblockhash(), 16), create_coinbase(node.getblockcount() + 1), block_time)
block.rehash()
block.solve()
node.submitblock(ToHex(block))
diff --git a/test/lint/commit-script-check.sh b/test/lint/commit-script-check.sh
index 4267f9fa0d..5603456e62 100755
--- a/test/lint/commit-script-check.sh
+++ b/test/lint/commit-script-check.sh
@@ -18,12 +18,12 @@ if test "x$1" = "x"; then
fi
RET=0
-PREV_BRANCH=`git name-rev --name-only HEAD`
-PREV_HEAD=`git rev-parse HEAD`
-for commit in `git rev-list --reverse $1`; do
+PREV_BRANCH=$(git name-rev --name-only HEAD)
+PREV_HEAD=$(git rev-parse HEAD)
+for commit in $(git rev-list --reverse $1); do
if git rev-list -n 1 --pretty="%s" $commit | grep -q "^scripted-diff:"; then
git checkout --quiet $commit^ || exit
- SCRIPT="`git rev-list --format=%b -n1 $commit | sed '/^-BEGIN VERIFY SCRIPT-$/,/^-END VERIFY SCRIPT-$/{//!b};d'`"
+ SCRIPT="$(git rev-list --format=%b -n1 $commit | sed '/^-BEGIN VERIFY SCRIPT-$/,/^-END VERIFY SCRIPT-$/{//!b};d')"
if test "x$SCRIPT" = "x"; then
echo "Error: missing script for: $commit"
echo "Failed"
diff --git a/test/lint/extended-lint-all.sh b/test/lint/extended-lint-all.sh
new file mode 100755
index 0000000000..65c51e02f5
--- /dev/null
+++ b/test/lint/extended-lint-all.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+#
+# 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.
+#
+# This script runs all contrib/devtools/extended-lint-*.sh files, and fails if
+# any exit with a non-zero status code.
+
+# This script is intentionally locale dependent by not setting "export LC_ALL=C"
+# in order to allow for the executed lint scripts to opt in or opt out of locale
+# dependence themselves.
+
+set -u
+
+SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
+LINTALL=$(basename "${BASH_SOURCE[0]}")
+
+for f in "${SCRIPTDIR}"/extended-lint-*.sh; do
+ if [ "$(basename "$f")" != "$LINTALL" ]; then
+ if ! "$f"; then
+ echo "^---- failure generated from $f"
+ exit 1
+ fi
+ fi
+done
diff --git a/test/lint/extended-lint-cppcheck.sh b/test/lint/extended-lint-cppcheck.sh
new file mode 100755
index 0000000000..47df25ba6b
--- /dev/null
+++ b/test/lint/extended-lint-cppcheck.sh
@@ -0,0 +1,80 @@
+#!/usr/bin/env bash
+#
+# 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.
+#
+
+export LC_ALL=C
+
+ENABLED_CHECKS=(
+ "Class '.*' has a constructor with 1 argument that is not explicit."
+ "Struct '.*' has a constructor with 1 argument that is not explicit."
+)
+
+IGNORED_WARNINGS=(
+ "src/arith_uint256.h:.* Class 'arith_uint256' has a constructor with 1 argument that is not explicit."
+ "src/arith_uint256.h:.* Class 'base_uint < 256 >' has a constructor with 1 argument that is not explicit."
+ "src/arith_uint256.h:.* Class 'base_uint' has a constructor with 1 argument that is not explicit."
+ "src/coins.h:.* Class 'CCoinsViewBacked' has a constructor with 1 argument that is not explicit."
+ "src/coins.h:.* Class 'CCoinsViewCache' has a constructor with 1 argument that is not explicit."
+ "src/coins.h:.* Class 'CCoinsViewCursor' has a constructor with 1 argument that is not explicit."
+ "src/net.h:.* Class 'CNetMessage' has a constructor with 1 argument that is not explicit."
+ "src/policy/feerate.h:.* Class 'CFeeRate' has a constructor with 1 argument that is not explicit."
+ "src/prevector.h:.* Class 'const_iterator' has a constructor with 1 argument that is not explicit."
+ "src/prevector.h:.* Class 'const_reverse_iterator' has a constructor with 1 argument that is not explicit."
+ "src/prevector.h:.* Class 'iterator' has a constructor with 1 argument that is not explicit."
+ "src/prevector.h:.* Class 'reverse_iterator' has a constructor with 1 argument that is not explicit."
+ "src/primitives/block.h:.* Class 'CBlock' has a constructor with 1 argument that is not explicit."
+ "src/primitives/transaction.h:.* Class 'CTransaction' has a constructor with 1 argument that is not explicit."
+ "src/protocol.h:.* Class 'CMessageHeader' has a constructor with 1 argument that is not explicit."
+ "src/qt/guiutil.h:.* Class 'ItemDelegate' has a constructor with 1 argument that is not explicit."
+ "src/rpc/util.h:.* Struct 'RPCResults' has a constructor with 1 argument that is not explicit."
+ "src/rpc/util.h:.* style: Struct 'UniValueType' has a constructor with 1 argument that is not explicit."
+ "src/script/descriptor.cpp:.* Class 'AddressDescriptor' has a constructor with 1 argument that is not explicit."
+ "src/script/descriptor.cpp:.* Class 'ComboDescriptor' has a constructor with 1 argument that is not explicit."
+ "src/script/descriptor.cpp:.* Class 'ConstPubkeyProvider' has a constructor with 1 argument that is not explicit."
+ "src/script/descriptor.cpp:.* Class 'PKDescriptor' has a constructor with 1 argument that is not explicit."
+ "src/script/descriptor.cpp:.* Class 'PKHDescriptor' has a constructor with 1 argument that is not explicit."
+ "src/script/descriptor.cpp:.* Class 'RawDescriptor' has a constructor with 1 argument that is not explicit."
+ "src/script/descriptor.cpp:.* Class 'SHDescriptor' has a constructor with 1 argument that is not explicit."
+ "src/script/descriptor.cpp:.* Class 'WPKHDescriptor' has a constructor with 1 argument that is not explicit."
+ "src/script/descriptor.cpp:.* Class 'WSHDescriptor' has a constructor with 1 argument that is not explicit."
+ "src/script/script.h:.* Class 'CScript' has a constructor with 1 argument that is not explicit."
+ "src/script/standard.h:.* Class 'CScriptID' has a constructor with 1 argument that is not explicit."
+ "src/support/allocators/secure.h:.* Struct 'secure_allocator < char >' has a constructor with 1 argument that is not explicit."
+ "src/support/allocators/secure.h:.* Struct 'secure_allocator < RNGState >' has a constructor with 1 argument that is not explicit."
+ "src/support/allocators/secure.h:.* Struct 'secure_allocator < unsigned char >' has a constructor with 1 argument that is not explicit."
+ "src/support/allocators/zeroafterfree.h:.* Struct 'zero_after_free_allocator < char >' has a constructor with 1 argument that is not explicit."
+ "src/test/checkqueue_tests.cpp:.* Struct 'FailingCheck' has a constructor with 1 argument that is not explicit."
+ "src/test/checkqueue_tests.cpp:.* Struct 'MemoryCheck' has a constructor with 1 argument that is not explicit."
+ "src/test/checkqueue_tests.cpp:.* Struct 'UniqueCheck' has a constructor with 1 argument that is not explicit."
+ "src/wallet/db.h:.* Class 'BerkeleyEnvironment' has a constructor with 1 argument that is not explicit."
+)
+
+if ! command -v cppcheck > /dev/null; then
+ echo "Skipping cppcheck linting since cppcheck is not installed. Install by running \"apt install cppcheck\""
+ exit 0
+fi
+
+function join_array {
+ local IFS="$1"
+ shift
+ echo "$*"
+}
+
+ENABLED_CHECKS_REGEXP=$(join_array "|" "${ENABLED_CHECKS[@]}")
+IGNORED_WARNINGS_REGEXP=$(join_array "|" "${IGNORED_WARNINGS[@]}")
+WARNINGS=$(git ls-files -- "*.cpp" "*.h" ":(exclude)src/leveldb/" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/" | \
+ xargs cppcheck --enable=all -j "$(getconf _NPROCESSORS_ONLN)" --language=c++ --std=c++11 --template=gcc -D__cplusplus -DCLIENT_VERSION_BUILD -DCLIENT_VERSION_IS_RELEASE -DCLIENT_VERSION_MAJOR -DCLIENT_VERSION_MINOR -DCLIENT_VERSION_REVISION -DCOPYRIGHT_YEAR -DDEBUG -DHAVE_WORKING_BOOST_SLEEP_FOR -I src/ -q 2>&1 | sort -u | \
+ grep -E "${ENABLED_CHECKS_REGEXP}" | \
+ grep -vE "${IGNORED_WARNINGS_REGEXP}")
+if [[ ${WARNINGS} != "" ]]; then
+ echo "${WARNINGS}"
+ echo
+ echo "Advice not applicable in this specific case? Add an exception by updating"
+ echo "IGNORED_WARNINGS in $0"
+ # Uncomment to enforce the developer note policy "By default, declare single-argument constructors `explicit`"
+ # exit 1
+fi
+exit 0
diff --git a/test/lint/lint-circular-dependencies.sh b/test/lint/lint-circular-dependencies.sh
index 70cc16337e..8607fc4371 100755
--- a/test/lint/lint-circular-dependencies.sh
+++ b/test/lint/lint-circular-dependencies.sh
@@ -39,7 +39,7 @@ CIRCULAR_DEPENDENCIES=()
IFS=$'\n'
for CIRC in $(cd src && ../contrib/devtools/circular-dependencies.py {*,*/*,*/*/*}.{h,cpp} | sed -e 's/^Circular dependency: //'); do
- CIRCULAR_DEPENDENCIES+=($CIRC)
+ CIRCULAR_DEPENDENCIES+=( "$CIRC" )
IS_EXPECTED_CIRC=0
for EXPECTED_CIRC in "${EXPECTED_CIRCULAR_DEPENDENCIES[@]}"; do
if [[ "${CIRC}" == "${EXPECTED_CIRC}" ]]; then
diff --git a/test/lint/lint-format-strings.py b/test/lint/lint-format-strings.py
index 224e62f04a..99b0eaa38e 100755
--- a/test/lint/lint-format-strings.py
+++ b/test/lint/lint-format-strings.py
@@ -16,8 +16,7 @@ FALSE_POSITIVES = [
("src/dbwrapper.cpp", "vsnprintf(p, limit - p, format, backup_ap)"),
("src/index/base.cpp", "FatalError(const char* fmt, const Args&... args)"),
("src/netbase.cpp", "LogConnectFailure(bool manual_connection, const char* fmt, const Args&... args)"),
- ("src/util/system.cpp", "strprintf(_(COPYRIGHT_HOLDERS), _(COPYRIGHT_HOLDERS_SUBSTITUTION))"),
- ("src/util/system.cpp", "strprintf(COPYRIGHT_HOLDERS, COPYRIGHT_HOLDERS_SUBSTITUTION)"),
+ ("src/util/system.cpp", "strprintf(_(COPYRIGHT_HOLDERS), COPYRIGHT_HOLDERS_SUBSTITUTION)"),
("src/wallet/wallet.h", "WalletLogPrintf(std::string fmt, Params... parameters)"),
("src/wallet/wallet.h", "LogPrintf((\"%s \" + fmt).c_str(), GetDisplayName(), parameters...)"),
("src/logging.h", "LogPrintf(const char* fmt, const Args&... args)"),
diff --git a/test/lint/lint-logs.sh b/test/lint/lint-logs.sh
index 1afd4cfc1a..632ed7c812 100755
--- a/test/lint/lint-logs.sh
+++ b/test/lint/lint-logs.sh
@@ -19,6 +19,7 @@ UNTERMINATED_LOGS=$(git grep --extended-regexp "LogPrintf?\(" -- "*.cpp" | \
grep -v "LogPrint()" | \
grep -v "LogPrintf()")
if [[ ${UNTERMINATED_LOGS} != "" ]]; then
+ # shellcheck disable=SC2028
echo "All calls to LogPrintf() and LogPrint() should be terminated with \\n"
echo
echo "${UNTERMINATED_LOGS}"
diff --git a/test/lint/lint-shell.sh b/test/lint/lint-shell.sh
index 6f5e6546c5..69fc3cf368 100755
--- a/test/lint/lint-shell.sh
+++ b/test/lint/lint-shell.sh
@@ -23,25 +23,9 @@ fi
# Disabled warnings:
disabled=(
- SC1087 # Use braces when expanding arrays, e.g. ${array[idx]} (or ${var}[.. to quiet).
- SC2001 # See if you can use ${variable//search/replace} instead.
- SC2004 # $/${} is unnecessary on arithmetic variables.
- SC2005 # Useless echo? Instead of 'echo $(cmd)', just use 'cmd'.
- SC2006 # Use $(..) instead of legacy `..`.
- SC2016 # Expressions don't expand in single quotes, use double quotes for that.
- SC2028 # echo won't expand escape sequences. Consider printf.
SC2046 # Quote this to prevent word splitting.
- SC2048 # Use "$@" (with quotes) to prevent whitespace problems.
- SC2066 # Since you double quoted this, it will not word split, and the loop will only run once.
SC2086 # Double quote to prevent globbing and word splitting.
- SC2116 # Useless echo? Instead of 'cmd $(echo foo)', just use 'cmd foo'.
SC2162 # read without -r will mangle backslashes.
- SC2166 # Prefer [ p ] {&&,||} [ q ] as [ p -{a,o} q ] is not well defined.
- SC2181 # Check exit code directly with e.g. 'if mycmd;', not indirectly with $?.
- SC2206 # Quote to prevent word splitting, or split robustly with mapfile or read -a.
- SC2207 # Prefer mapfile or read -a to split command output (or quote to avoid splitting).
- SC2230 # which is non-standard. Use builtin 'command -v' instead.
- SC2236 # Don't force -n instead of ! -z.
)
shellcheck -e "$(IFS=","; echo "${disabled[*]}")" \
$(git ls-files -- "*.sh" | grep -vE 'src/(secp256k1|univalue)/')