From fcfa4c2445d34fd6dabd791412eee5a06af2f671 Mon Sep 17 00:00:00 2001 From: div72 <60045611+div72@users.noreply.github.com> Date: Wed, 12 Aug 2020 12:00:39 +0300 Subject: [PATCH 01/16] Port lint scripts from bitcoin --- ci/lint/04_install.sh | 20 + ci/lint/05_before_script.sh | 9 + ci/lint/06_script.sh | 26 + contrib/devtools/README.md | 118 +++- contrib/devtools/circular-dependencies.py | 91 +++ contrib/devtools/clang-format-diff.py | 166 +++++ contrib/devtools/copyright_header.py | 606 ++++++++++++++++++ contrib/devtools/split-debug.sh.in | 2 +- contrib/devtools/symbol-check.py | 298 ++++++--- .../devtools/test_deterministic_coverage.sh | 151 +++++ src/.clang-format | 55 ++ test/lint/README.md | 38 ++ test/lint/check-doc.py | 66 ++ test/lint/check-rpc-mappings.py | 162 +++++ test/lint/commit-script-check.sh | 47 ++ test/lint/extended-lint-all.sh | 26 + test/lint/extended-lint-cppcheck.sh | 80 +++ test/lint/git-subtree-check.sh | 96 +++ test/lint/lint-all.sh | 30 + test/lint/lint-assertions.sh | 34 + test/lint/lint-circular-dependencies.sh | 64 ++ test/lint/lint-filenames.sh | 24 + test/lint/lint-format-strings.py | 293 +++++++++ test/lint/lint-format-strings.sh | 44 ++ test/lint/lint-git-commit-check.sh | 47 ++ test/lint/lint-include-guards.sh | 30 + test/lint/lint-includes.sh | 114 ++++ test/lint/lint-locale-dependence.sh | 220 +++++++ test/lint/lint-logs.sh | 28 + .../lint-python-mutable-default-parameters.sh | 52 ++ test/lint/lint-python-utf8-encoding.sh | 28 + test/lint/lint-python.sh | 108 ++++ test/lint/lint-qt.sh | 20 + test/lint/lint-rpc-help.sh | 24 + test/lint/lint-shebang.sh | 24 + test/lint/lint-shell-locale.sh | 25 + test/lint/lint-shell.sh | 61 ++ test/lint/lint-spelling.ignore-words.txt | 17 + test/lint/lint-spelling.sh | 20 + test/lint/lint-submodule.sh | 20 + test/lint/lint-tests.sh | 35 + test/lint/lint-whitespace.sh | 113 ++++ 42 files changed, 3447 insertions(+), 85 deletions(-) create mode 100644 ci/lint/04_install.sh create mode 100644 ci/lint/05_before_script.sh create mode 100644 ci/lint/06_script.sh create mode 100644 contrib/devtools/circular-dependencies.py create mode 100644 contrib/devtools/clang-format-diff.py create mode 100644 contrib/devtools/copyright_header.py create mode 100644 contrib/devtools/test_deterministic_coverage.sh create mode 100644 src/.clang-format create mode 100644 test/lint/README.md create mode 100644 test/lint/check-doc.py create mode 100644 test/lint/check-rpc-mappings.py create mode 100644 test/lint/commit-script-check.sh create mode 100644 test/lint/extended-lint-all.sh create mode 100644 test/lint/extended-lint-cppcheck.sh create mode 100644 test/lint/git-subtree-check.sh create mode 100644 test/lint/lint-all.sh create mode 100644 test/lint/lint-assertions.sh create mode 100644 test/lint/lint-circular-dependencies.sh create mode 100644 test/lint/lint-filenames.sh create mode 100644 test/lint/lint-format-strings.py create mode 100644 test/lint/lint-format-strings.sh create mode 100644 test/lint/lint-git-commit-check.sh create mode 100644 test/lint/lint-include-guards.sh create mode 100644 test/lint/lint-includes.sh create mode 100644 test/lint/lint-locale-dependence.sh create mode 100644 test/lint/lint-logs.sh create mode 100644 test/lint/lint-python-mutable-default-parameters.sh create mode 100644 test/lint/lint-python-utf8-encoding.sh create mode 100644 test/lint/lint-python.sh create mode 100644 test/lint/lint-qt.sh create mode 100644 test/lint/lint-rpc-help.sh create mode 100644 test/lint/lint-shebang.sh create mode 100644 test/lint/lint-shell-locale.sh create mode 100644 test/lint/lint-shell.sh create mode 100644 test/lint/lint-spelling.ignore-words.txt create mode 100644 test/lint/lint-spelling.sh create mode 100644 test/lint/lint-submodule.sh create mode 100644 test/lint/lint-tests.sh create mode 100644 test/lint/lint-whitespace.sh diff --git a/ci/lint/04_install.sh b/ci/lint/04_install.sh new file mode 100644 index 0000000000..fae424051d --- /dev/null +++ b/ci/lint/04_install.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# +# 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. + +export LC_ALL=C + +travis_retry sudo apt update && sudo apt install -y clang-format-9 +sudo update-alternatives --install /usr/bin/clang-format clang-format $(which clang-format-9 ) 100 +sudo update-alternatives --install /usr/bin/clang-format-diff clang-format-diff $(which clang-format-diff-9) 100 + +travis_retry pip3 install codespell==1.17.1 +travis_retry pip3 install flake8==3.8.3 +travis_retry pip3 install yq +travis_retry pip3 install mypy==0.781 + +SHELLCHECK_VERSION=v0.7.1 +curl -sL "https://github.com/koalaman/shellcheck/releases/download/${SHELLCHECK_VERSION}/shellcheck-${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" | tar --xz -xf - --directory /tmp/ +export PATH="/tmp/shellcheck-${SHELLCHECK_VERSION}:${PATH}" diff --git a/ci/lint/05_before_script.sh b/ci/lint/05_before_script.sh new file mode 100644 index 0000000000..2987812c8e --- /dev/null +++ b/ci/lint/05_before_script.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +# +# 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. + +export LC_ALL=C + +git fetch --unshallow diff --git a/ci/lint/06_script.sh b/ci/lint/06_script.sh new file mode 100644 index 0000000000..c55ead31da --- /dev/null +++ b/ci/lint/06_script.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# +# 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. + +export LC_ALL=C + +if [ "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then + test/lint/commit-script-check.sh $TRAVIS_COMMIT_RANGE +fi + +test/lint/git-subtree-check.sh src/crypto/ctaes +#test/lint/git-subtree-check.sh src/secp256k1 +test/lint/git-subtree-check.sh src/univalue +test/lint/git-subtree-check.sh src/leveldb +#test/lint/git-subtree-check.sh src/crc32c +test/lint/check-doc.py +test/lint/check-rpc-mappings.py . +test/lint/lint-all.sh + +#if [ "$TRAVIS_REPO_SLUG" = "gridcoin-community/Gridcoin-Research" ] && [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then +# git log --merges --before="2 days ago" -1 --format='%H' > ./contrib/verify-commits/trusted-sha512-root-commit +# travis_retry gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys $( [verbose] +$ ./copyright_header.py update +$ ./copyright_header.py insert +``` +Running these subcommands without arguments displays a usage string. + +copyright\_header.py report \ [verbose] +--------------------------------------------------------- + +Produces a report of all copyright header notices found inside the source files +of a repository. Useful to quickly visualize the state of the headers. +Specifying `verbose` will list the full filenames of files of each category. + +copyright\_header.py update \ [verbose] +--------------------------------------------------------- +Updates all the copyright headers of `The Bitcoin Core developers` which were +changed in a year more recent than is listed. For example: +``` +// Copyright (c) - The Bitcoin Core developers +``` +will be updated to: +``` +// Copyright (c) - The Bitcoin Core developers +``` +where `` is obtained from the `git log` history. + +This subcommand also handles copyright headers that have only a single year. In +those cases: +``` +// Copyright (c) The Bitcoin Core developers +``` +will be updated to: +``` +// Copyright (c) - The Bitcoin Core developers +``` +where the update is appropriate. + +copyright\_header.py insert \ +------------------------------------ +Inserts a copyright header for `The Bitcoin Core developers` at the top of the +file in either Python or C++ style as determined by the file extension. If the +file is a Python file and it has `#!` starting the first line, the header is +inserted in the line below it. + +The copyright dates will be set to be `-` where +`` is according to the `git log` history. If +`` is equal to ``, it will be set as a single +year rather than two hyphenated years. + +If the file already has a copyright for `The Bitcoin Core developers`, the +script will exit. + +gen-manpages.sh +=============== + +A small script to automatically create manpages in ../../doc/man by running the release binaries with the -help option. +This requires help2man which can be found at: https://www.gnu.org/software/help2man/ + +With in-tree builds this tool can be run from any directory within the +repostitory. To use this tool with out-of-tree builds set `BUILDDIR`. For +example: + +```bash +BUILDDIR=$PWD/build contrib/devtools/gen-manpages.sh +``` + +security-check.py and test-security-check.py +============================================ + +Perform basic security checks on a series of executables. + symbol-check.py =============== -A script to check that the (Linux) executables produced by gitian only contain -allowed gcc, glibc and libstdc++ version symbols. This makes sure they are -still compatible with the minimum supported Linux distribution versions. +A script to check that the executables produced by gitian only contain +certain symbols and are only linked against allowed libraries. + +For Linux this means checking for allowed gcc, glibc and libstdc++ version symbols. +This makes sure they are still compatible with the minimum supported distribution versions. + +For macOS and Windows we check that the executables are only linked against libraries we allow. Example usage after a gitian build: - find ../gitian-builder/build -type f -executable | xargs python contrib/devtools/symbol-check.py + find ../gitian-builder/build -type f -executable | xargs python3 contrib/devtools/symbol-check.py -If only supported symbols are used the return value will be 0 and the output will be empty. +If no errors occur the return value will be 0 and the output will be empty. -If there are 'unsupported' symbols, the return value will be 1 a list like this will be printed: +If there are any errors the return value will be 1 and output like this will be printed: .../64/test_bitcoin: symbol memcpy from unsupported version GLIBC_2.14 .../64/test_bitcoin: symbol __fdelt_chk from unsupported version GLIBC_2.15 .../64/test_bitcoin: symbol std::out_of_range::~out_of_range() from unsupported version GLIBCXX_3.4.15 .../64/test_bitcoin: symbol _ZNSt8__detail15_List_nod from unsupported version GLIBCXX_3.4.15 +circular-dependencies.py +======================== + +Run this script from the root of the source tree (`src/`) to find circular dependencies in the source code. +This looks only at which files include other files, treating the `.cpp` and `.h` file as one unit. + +Example usage: + + cd .../src + ../contrib/devtools/circular-dependencies.py {*,*/*,*/*/*}.{h,cpp} diff --git a/contrib/devtools/circular-dependencies.py b/contrib/devtools/circular-dependencies.py new file mode 100644 index 0000000000..bc5f09a3e2 --- /dev/null +++ b/contrib/devtools/circular-dependencies.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 +# 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. + +import sys +import re + +MAPPING = { + 'core_read.cpp': 'core_io.cpp', + 'core_write.cpp': 'core_io.cpp', +} + +# Directories with header-based modules, where the assumption that .cpp files +# define functions and variables declared in corresponding .h files is +# incorrect. +HEADER_MODULE_PATHS = [ + 'interfaces/' +] + +def module_name(path): + if path in MAPPING: + path = MAPPING[path] + if any(path.startswith(dirpath) for dirpath in HEADER_MODULE_PATHS): + return path + if path.endswith(".h"): + return path[:-2] + if path.endswith(".c"): + return path[:-2] + if path.endswith(".cpp"): + return path[:-4] + return None + +files = dict() +deps = dict() + +RE = re.compile("^#include <(.*)>") + +# Iterate over files, and create list of modules +for arg in sys.argv[1:]: + module = module_name(arg) + if module is None: + print("Ignoring file %s (does not constitute module)\n" % arg) + else: + files[arg] = module + deps[module] = set() + +# Iterate again, and build list of direct dependencies for each module +# TODO: implement support for multiple include directories +for arg in sorted(files.keys()): + module = files[arg] + with open(arg, 'r', encoding="utf8") as f: + for line in f: + match = RE.match(line) + if match: + include = match.group(1) + included_module = module_name(include) + if included_module is not None and included_module in deps and included_module != module: + deps[module].add(included_module) + +# Loop to find the shortest (remaining) circular dependency +have_cycle = False +while True: + shortest_cycle = None + for module in sorted(deps.keys()): + # Build the transitive closure of dependencies of module + closure = dict() + for dep in deps[module]: + closure[dep] = [] + while True: + old_size = len(closure) + old_closure_keys = sorted(closure.keys()) + for src in old_closure_keys: + for dep in deps[src]: + if dep not in closure: + closure[dep] = closure[src] + [src] + if len(closure) == old_size: + break + # If module is in its own transitive closure, it's a circular dependency; check if it is the shortest + if module in closure and (shortest_cycle is None or len(closure[module]) + 1 < len(shortest_cycle)): + shortest_cycle = [module] + closure[module] + if shortest_cycle is None: + break + # We have the shortest circular dependency; report it + module = shortest_cycle[0] + print("Circular dependency: %s" % (" -> ".join(shortest_cycle + [module]))) + # And then break the dependency to avoid repeating in other cycles + deps[shortest_cycle[-1]] = deps[shortest_cycle[-1]] - set([module]) + have_cycle = True + +sys.exit(1 if have_cycle else 0) diff --git a/contrib/devtools/clang-format-diff.py b/contrib/devtools/clang-format-diff.py new file mode 100644 index 0000000000..98eee67f43 --- /dev/null +++ b/contrib/devtools/clang-format-diff.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python3 +# +#===- clang-format-diff.py - ClangFormat Diff Reformatter ----*- python -*--===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. +# +# ============================================================ +# +# University of Illinois/NCSA +# Open Source License +# +# Copyright (c) 2007-2015 University of Illinois at Urbana-Champaign. +# All rights reserved. +# +# Developed by: +# +# LLVM Team +# +# University of Illinois at Urbana-Champaign +# +# http://llvm.org +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal with +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimers. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimers in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the names of the LLVM Team, University of Illinois at +# Urbana-Champaign, nor the names of its contributors may be used to +# endorse or promote products derived from this Software without specific +# prior written permission. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +# SOFTWARE. +# +# ============================================================ +# +#===------------------------------------------------------------------------===# + +r""" +ClangFormat Diff Reformatter +============================ + +This script reads input from a unified diff and reformats all the changed +lines. This is useful to reformat all the lines touched by a specific patch. +Example usage for git/svn users: + + git diff -U0 HEAD^ | clang-format-diff.py -p1 -i + svn diff --diff-cmd=diff -x-U0 | clang-format-diff.py -i + +""" + +import argparse +import difflib +import io +import re +import subprocess +import sys + + +# Change this to the full path if clang-format is not on the path. +binary = 'clang-format' + + +def main(): + parser = argparse.ArgumentParser(description= + 'Reformat changed lines in diff. Without -i ' + 'option just output the diff that would be ' + 'introduced.') + parser.add_argument('-i', action='store_true', default=False, + help='apply edits to files instead of displaying a diff') + parser.add_argument('-p', metavar='NUM', default=0, + help='strip the smallest prefix containing P slashes') + parser.add_argument('-regex', metavar='PATTERN', default=None, + help='custom pattern selecting file paths to reformat ' + '(case sensitive, overrides -iregex)') + parser.add_argument('-iregex', metavar='PATTERN', default= + r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm|inc|js|ts|proto' + r'|protodevel|java)', + help='custom pattern selecting file paths to reformat ' + '(case insensitive, overridden by -regex)') + parser.add_argument('-sort-includes', action='store_true', default=False, + help='let clang-format sort include blocks') + parser.add_argument('-v', '--verbose', action='store_true', + help='be more verbose, ineffective without -i') + args = parser.parse_args() + + # Extract changed lines for each file. + filename = None + lines_by_file = {} + for line in sys.stdin: + match = re.search(r'^\+\+\+\ (.*?/){%s}(\S*)' % args.p, line) + if match: + filename = match.group(2) + if filename is None: + continue + + if args.regex is not None: + if not re.match('^%s$' % args.regex, filename): + continue + else: + if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE): + continue + + match = re.search(r'^@@.*\+(\d+)(,(\d+))?', line) + if match: + start_line = int(match.group(1)) + line_count = 1 + if match.group(3): + line_count = int(match.group(3)) + if line_count == 0: + continue + end_line = start_line + line_count - 1 + lines_by_file.setdefault(filename, []).extend( + ['-lines', str(start_line) + ':' + str(end_line)]) + + # Reformat files containing changes in place. + for filename, lines in lines_by_file.items(): + if args.i and args.verbose: + print('Formatting {}'.format(filename)) + command = [binary, filename] + if args.i: + command.append('-i') + if args.sort_includes: + command.append('-sort-includes') + command.extend(lines) + command.extend(['-style=file', '-fallback-style=none']) + p = subprocess.Popen(command, + stdout=subprocess.PIPE, + stderr=None, + stdin=subprocess.PIPE, + universal_newlines=True) + stdout, stderr = p.communicate() + if p.returncode != 0: + sys.exit(p.returncode) + + if not args.i: + with open(filename, encoding="utf8") as f: + code = f.readlines() + formatted_code = io.StringIO(stdout).readlines() + diff = difflib.unified_diff(code, formatted_code, + filename, filename, + '(before formatting)', '(after formatting)') + diff_string = ''.join(diff) + if len(diff_string) > 0: + sys.stdout.write(diff_string) + +if __name__ == '__main__': + main() diff --git a/contrib/devtools/copyright_header.py b/contrib/devtools/copyright_header.py new file mode 100644 index 0000000000..9a555c70bb --- /dev/null +++ b/contrib/devtools/copyright_header.py @@ -0,0 +1,606 @@ +#!/usr/bin/env python3 +# Copyright (c) 2016-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. + +import re +import fnmatch +import sys +import subprocess +import datetime +import os + +################################################################################ +# file filtering +################################################################################ + +EXCLUDE = [ + # auto generated: + 'src/qt/bitcoinstrings.cpp', + 'src/chainparamsseeds.h', + # other external copyrights: + 'src/reverse_iterator.h', + 'src/test/fuzz/FuzzedDataProvider.h', + 'src/tinyformat.h', + 'src/bench/nanobench.h', + 'test/functional/test_framework/bignum.py', + # python init: + '*__init__.py', +] +EXCLUDE_COMPILED = re.compile('|'.join([fnmatch.translate(m) for m in EXCLUDE])) + +EXCLUDE_DIRS = [ + # git subtrees + "src/crypto/ctaes/", + "src/leveldb/", + "src/secp256k1/", + "src/univalue/", + "src/crc32c/", +] + +INCLUDE = ['*.h', '*.cpp', '*.cc', '*.c', '*.mm', '*.py', '*.sh', '*.bash-completion'] +INCLUDE_COMPILED = re.compile('|'.join([fnmatch.translate(m) for m in INCLUDE])) + +def applies_to_file(filename): + for excluded_dir in EXCLUDE_DIRS: + if filename.startswith(excluded_dir): + return False + return ((EXCLUDE_COMPILED.match(filename) is None) and + (INCLUDE_COMPILED.match(filename) is not None)) + +################################################################################ +# obtain list of files in repo according to INCLUDE and EXCLUDE +################################################################################ + +GIT_LS_CMD = 'git ls-files --full-name'.split(' ') +GIT_TOPLEVEL_CMD = 'git rev-parse --show-toplevel'.split(' ') + +def call_git_ls(base_directory): + out = subprocess.check_output([*GIT_LS_CMD, base_directory]) + return [f for f in out.decode("utf-8").split('\n') if f != ''] + +def call_git_toplevel(): + "Returns the absolute path to the project root" + return subprocess.check_output(GIT_TOPLEVEL_CMD).strip().decode("utf-8") + +def get_filenames_to_examine(base_directory): + "Returns an array of absolute paths to any project files in the base_directory that pass the include/exclude filters" + root = call_git_toplevel() + filenames = call_git_ls(base_directory) + return sorted([os.path.join(root, filename) for filename in filenames if + applies_to_file(filename)]) + +################################################################################ +# define and compile regexes for the patterns we are looking for +################################################################################ + + +COPYRIGHT_WITH_C = r'Copyright \(c\)' +COPYRIGHT_WITHOUT_C = 'Copyright' +ANY_COPYRIGHT_STYLE = '(%s|%s)' % (COPYRIGHT_WITH_C, COPYRIGHT_WITHOUT_C) + +YEAR = "20[0-9][0-9]" +YEAR_RANGE = '(%s)(-%s)?' % (YEAR, YEAR) +YEAR_LIST = '(%s)(, %s)+' % (YEAR, YEAR) +ANY_YEAR_STYLE = '(%s|%s)' % (YEAR_RANGE, YEAR_LIST) +ANY_COPYRIGHT_STYLE_OR_YEAR_STYLE = ("%s %s" % (ANY_COPYRIGHT_STYLE, + ANY_YEAR_STYLE)) + +ANY_COPYRIGHT_COMPILED = re.compile(ANY_COPYRIGHT_STYLE_OR_YEAR_STYLE) + +def compile_copyright_regex(copyright_style, year_style, name): + return re.compile(r'%s %s,? %s( +\*)?\n' % (copyright_style, year_style, name)) + +EXPECTED_HOLDER_NAMES = [ + r"Satoshi Nakamoto", + r"The Bitcoin Core developers", + r"BitPay Inc\.", + r"University of Illinois at Urbana-Champaign\.", + r"Pieter Wuille", + r"Wladimir J\. van der Laan", + r"Jeff Garzik", + r"Jan-Klaas Kollhof", + r"ArtForz -- public domain half-a-node", + r"Intel Corporation ?", + r"The Zcash developers", + r"Jeremy Rubin", +] + +DOMINANT_STYLE_COMPILED = {} +YEAR_LIST_STYLE_COMPILED = {} +WITHOUT_C_STYLE_COMPILED = {} + +for holder_name in EXPECTED_HOLDER_NAMES: + DOMINANT_STYLE_COMPILED[holder_name] = ( + compile_copyright_regex(COPYRIGHT_WITH_C, YEAR_RANGE, holder_name)) + YEAR_LIST_STYLE_COMPILED[holder_name] = ( + compile_copyright_regex(COPYRIGHT_WITH_C, YEAR_LIST, holder_name)) + WITHOUT_C_STYLE_COMPILED[holder_name] = ( + compile_copyright_regex(COPYRIGHT_WITHOUT_C, ANY_YEAR_STYLE, + holder_name)) + +################################################################################ +# search file contents for copyright message of particular category +################################################################################ + +def get_count_of_copyrights_of_any_style_any_holder(contents): + return len(ANY_COPYRIGHT_COMPILED.findall(contents)) + +def file_has_dominant_style_copyright_for_holder(contents, holder_name): + match = DOMINANT_STYLE_COMPILED[holder_name].search(contents) + return match is not None + +def file_has_year_list_style_copyright_for_holder(contents, holder_name): + match = YEAR_LIST_STYLE_COMPILED[holder_name].search(contents) + return match is not None + +def file_has_without_c_style_copyright_for_holder(contents, holder_name): + match = WITHOUT_C_STYLE_COMPILED[holder_name].search(contents) + return match is not None + +################################################################################ +# get file info +################################################################################ + +def read_file(filename): + return open(filename, 'r', encoding="utf8").read() + +def gather_file_info(filename): + info = {} + info['filename'] = filename + c = read_file(filename) + info['contents'] = c + + info['all_copyrights'] = get_count_of_copyrights_of_any_style_any_holder(c) + + info['classified_copyrights'] = 0 + info['dominant_style'] = {} + info['year_list_style'] = {} + info['without_c_style'] = {} + for holder_name in EXPECTED_HOLDER_NAMES: + has_dominant_style = ( + file_has_dominant_style_copyright_for_holder(c, holder_name)) + has_year_list_style = ( + file_has_year_list_style_copyright_for_holder(c, holder_name)) + has_without_c_style = ( + file_has_without_c_style_copyright_for_holder(c, holder_name)) + info['dominant_style'][holder_name] = has_dominant_style + info['year_list_style'][holder_name] = has_year_list_style + info['without_c_style'][holder_name] = has_without_c_style + if has_dominant_style or has_year_list_style or has_without_c_style: + info['classified_copyrights'] = info['classified_copyrights'] + 1 + return info + +################################################################################ +# report execution +################################################################################ + +SEPARATOR = '-'.join(['' for _ in range(80)]) + +def print_filenames(filenames, verbose): + if not verbose: + return + for filename in filenames: + print("\t%s" % filename) + +def print_report(file_infos, verbose): + print(SEPARATOR) + examined = [i['filename'] for i in file_infos] + print("%d files examined according to INCLUDE and EXCLUDE fnmatch rules" % + len(examined)) + print_filenames(examined, verbose) + + print(SEPARATOR) + print('') + zero_copyrights = [i['filename'] for i in file_infos if + i['all_copyrights'] == 0] + print("%4d with zero copyrights" % len(zero_copyrights)) + print_filenames(zero_copyrights, verbose) + one_copyright = [i['filename'] for i in file_infos if + i['all_copyrights'] == 1] + print("%4d with one copyright" % len(one_copyright)) + print_filenames(one_copyright, verbose) + two_copyrights = [i['filename'] for i in file_infos if + i['all_copyrights'] == 2] + print("%4d with two copyrights" % len(two_copyrights)) + print_filenames(two_copyrights, verbose) + three_copyrights = [i['filename'] for i in file_infos if + i['all_copyrights'] == 3] + print("%4d with three copyrights" % len(three_copyrights)) + print_filenames(three_copyrights, verbose) + four_or_more_copyrights = [i['filename'] for i in file_infos if + i['all_copyrights'] >= 4] + print("%4d with four or more copyrights" % len(four_or_more_copyrights)) + print_filenames(four_or_more_copyrights, verbose) + print('') + print(SEPARATOR) + print('Copyrights with dominant style:\ne.g. "Copyright (c)" and ' + '"" or "-":\n') + for holder_name in EXPECTED_HOLDER_NAMES: + dominant_style = [i['filename'] for i in file_infos if + i['dominant_style'][holder_name]] + if len(dominant_style) > 0: + print("%4d with '%s'" % (len(dominant_style), + holder_name.replace('\n', '\\n'))) + print_filenames(dominant_style, verbose) + print('') + print(SEPARATOR) + print('Copyrights with year list style:\ne.g. "Copyright (c)" and ' + '", , ...":\n') + for holder_name in EXPECTED_HOLDER_NAMES: + year_list_style = [i['filename'] for i in file_infos if + i['year_list_style'][holder_name]] + if len(year_list_style) > 0: + print("%4d with '%s'" % (len(year_list_style), + holder_name.replace('\n', '\\n'))) + print_filenames(year_list_style, verbose) + print('') + print(SEPARATOR) + print('Copyrights with no "(c)" style:\ne.g. "Copyright" and "" or ' + '"-":\n') + for holder_name in EXPECTED_HOLDER_NAMES: + without_c_style = [i['filename'] for i in file_infos if + i['without_c_style'][holder_name]] + if len(without_c_style) > 0: + print("%4d with '%s'" % (len(without_c_style), + holder_name.replace('\n', '\\n'))) + print_filenames(without_c_style, verbose) + + print('') + print(SEPARATOR) + + unclassified_copyrights = [i['filename'] for i in file_infos if + i['classified_copyrights'] < i['all_copyrights']] + print("%d with unexpected copyright holder names" % + len(unclassified_copyrights)) + print_filenames(unclassified_copyrights, verbose) + print(SEPARATOR) + +def exec_report(base_directory, verbose): + filenames = get_filenames_to_examine(base_directory) + file_infos = [gather_file_info(f) for f in filenames] + print_report(file_infos, verbose) + +################################################################################ +# report cmd +################################################################################ + +REPORT_USAGE = """ +Produces a report of all copyright header notices found inside the source files +of a repository. + +Usage: + $ ./copyright_header.py report [verbose] + +Arguments: + - The base directory of a bitcoin source code repository. + [verbose] - Includes a list of every file of each subcategory in the report. +""" + +def report_cmd(argv): + if len(argv) == 2: + sys.exit(REPORT_USAGE) + + base_directory = argv[2] + if not os.path.exists(base_directory): + sys.exit("*** bad : %s" % base_directory) + + if len(argv) == 3: + verbose = False + elif argv[3] == 'verbose': + verbose = True + else: + sys.exit("*** unknown argument: %s" % argv[2]) + + exec_report(base_directory, verbose) + +################################################################################ +# query git for year of last change +################################################################################ + +GIT_LOG_CMD = "git log --pretty=format:%%ai %s" + +def call_git_log(filename): + out = subprocess.check_output((GIT_LOG_CMD % filename).split(' ')) + return out.decode("utf-8").split('\n') + +def get_git_change_years(filename): + git_log_lines = call_git_log(filename) + if len(git_log_lines) == 0: + return [datetime.date.today().year] + # timestamp is in ISO 8601 format. e.g. "2016-09-05 14:25:32 -0600" + return [line.split(' ')[0].split('-')[0] for line in git_log_lines] + +def get_most_recent_git_change_year(filename): + return max(get_git_change_years(filename)) + +################################################################################ +# read and write to file +################################################################################ + +def read_file_lines(filename): + f = open(filename, 'r', encoding="utf8") + file_lines = f.readlines() + f.close() + return file_lines + +def write_file_lines(filename, file_lines): + f = open(filename, 'w', encoding="utf8") + f.write(''.join(file_lines)) + f.close() + +################################################################################ +# update header years execution +################################################################################ + +COPYRIGHT = r'Copyright \(c\)' +YEAR = "20[0-9][0-9]" +YEAR_RANGE = '(%s)(-%s)?' % (YEAR, YEAR) +HOLDER = 'The Bitcoin Core developers' +UPDATEABLE_LINE_COMPILED = re.compile(' '.join([COPYRIGHT, YEAR_RANGE, HOLDER])) + +def get_updatable_copyright_line(file_lines): + index = 0 + for line in file_lines: + if UPDATEABLE_LINE_COMPILED.search(line) is not None: + return index, line + index = index + 1 + return None, None + +def parse_year_range(year_range): + year_split = year_range.split('-') + start_year = year_split[0] + if len(year_split) == 1: + return start_year, start_year + return start_year, year_split[1] + +def year_range_to_str(start_year, end_year): + if start_year == end_year: + return start_year + return "%s-%s" % (start_year, end_year) + +def create_updated_copyright_line(line, last_git_change_year): + copyright_splitter = 'Copyright (c) ' + copyright_split = line.split(copyright_splitter) + # Preserve characters on line that are ahead of the start of the copyright + # notice - they are part of the comment block and vary from file-to-file. + before_copyright = copyright_split[0] + after_copyright = copyright_split[1] + + space_split = after_copyright.split(' ') + year_range = space_split[0] + start_year, end_year = parse_year_range(year_range) + if end_year == last_git_change_year: + return line + return (before_copyright + copyright_splitter + + year_range_to_str(start_year, last_git_change_year) + ' ' + + ' '.join(space_split[1:])) + +def update_updatable_copyright(filename): + file_lines = read_file_lines(filename) + index, line = get_updatable_copyright_line(file_lines) + if not line: + print_file_action_message(filename, "No updatable copyright.") + return + last_git_change_year = get_most_recent_git_change_year(filename) + new_line = create_updated_copyright_line(line, last_git_change_year) + if line == new_line: + print_file_action_message(filename, "Copyright up-to-date.") + return + file_lines[index] = new_line + write_file_lines(filename, file_lines) + print_file_action_message(filename, + "Copyright updated! -> %s" % last_git_change_year) + +def exec_update_header_year(base_directory): + for filename in get_filenames_to_examine(base_directory): + update_updatable_copyright(filename) + +################################################################################ +# update cmd +################################################################################ + +UPDATE_USAGE = """ +Updates all the copyright headers of "The Bitcoin Core developers" which were +changed in a year more recent than is listed. For example: + +// Copyright (c) - The Bitcoin Core developers + +will be updated to: + +// Copyright (c) - The Bitcoin Core developers + +where is obtained from the 'git log' history. + +This subcommand also handles copyright headers that have only a single year. In those cases: + +// Copyright (c) The Bitcoin Core developers + +will be updated to: + +// Copyright (c) - The Bitcoin Core developers + +where the update is appropriate. + +Usage: + $ ./copyright_header.py update + +Arguments: + - The base directory of a bitcoin source code repository. +""" + +def print_file_action_message(filename, action): + print("%-52s %s" % (filename, action)) + +def update_cmd(argv): + if len(argv) != 3: + sys.exit(UPDATE_USAGE) + + base_directory = argv[2] + if not os.path.exists(base_directory): + sys.exit("*** bad base_directory: %s" % base_directory) + exec_update_header_year(base_directory) + +################################################################################ +# inserted copyright header format +################################################################################ + +def get_header_lines(header, start_year, end_year): + lines = header.split('\n')[1:-1] + lines[0] = lines[0] % year_range_to_str(start_year, end_year) + return [line + '\n' for line in lines] + +CPP_HEADER = ''' +// Copyright (c) %s The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +''' + +def get_cpp_header_lines_to_insert(start_year, end_year): + return reversed(get_header_lines(CPP_HEADER, start_year, end_year)) + +SCRIPT_HEADER = ''' +# Copyright (c) %s The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +''' + +def get_script_header_lines_to_insert(start_year, end_year): + return reversed(get_header_lines(SCRIPT_HEADER, start_year, end_year)) + +################################################################################ +# query git for year of last change +################################################################################ + +def get_git_change_year_range(filename): + years = get_git_change_years(filename) + return min(years), max(years) + +################################################################################ +# check for existing core copyright +################################################################################ + +def file_already_has_core_copyright(file_lines): + index, _ = get_updatable_copyright_line(file_lines) + return index is not None + +################################################################################ +# insert header execution +################################################################################ + +def file_has_hashbang(file_lines): + if len(file_lines) < 1: + return False + if len(file_lines[0]) <= 2: + return False + return file_lines[0][:2] == '#!' + +def insert_script_header(filename, file_lines, start_year, end_year): + if file_has_hashbang(file_lines): + insert_idx = 1 + else: + insert_idx = 0 + header_lines = get_script_header_lines_to_insert(start_year, end_year) + for line in header_lines: + file_lines.insert(insert_idx, line) + write_file_lines(filename, file_lines) + +def insert_cpp_header(filename, file_lines, start_year, end_year): + file_lines.insert(0, '\n') + header_lines = get_cpp_header_lines_to_insert(start_year, end_year) + for line in header_lines: + file_lines.insert(0, line) + write_file_lines(filename, file_lines) + +def exec_insert_header(filename, style): + file_lines = read_file_lines(filename) + if file_already_has_core_copyright(file_lines): + sys.exit('*** %s already has a copyright by The Bitcoin Core developers' + % (filename)) + start_year, end_year = get_git_change_year_range(filename) + if style in ['python', 'shell']: + insert_script_header(filename, file_lines, start_year, end_year) + else: + insert_cpp_header(filename, file_lines, start_year, end_year) + +################################################################################ +# insert cmd +################################################################################ + +INSERT_USAGE = """ +Inserts a copyright header for "The Bitcoin Core developers" at the top of the +file in either Python or C++ style as determined by the file extension. If the +file is a Python file and it has a '#!' starting the first line, the header is +inserted in the line below it. + +The copyright dates will be set to be: + +"-" + +where is according to the 'git log' history. If + is equal to , the date will be set to be: + +"" + +If the file already has a copyright for "The Bitcoin Core developers", the +script will exit. + +Usage: + $ ./copyright_header.py insert + +Arguments: + - A source file in the bitcoin repository. +""" + +def insert_cmd(argv): + if len(argv) != 3: + sys.exit(INSERT_USAGE) + + filename = argv[2] + if not os.path.isfile(filename): + sys.exit("*** bad filename: %s" % filename) + _, extension = os.path.splitext(filename) + if extension not in ['.h', '.cpp', '.cc', '.c', '.py', '.sh']: + sys.exit("*** cannot insert for file extension %s" % extension) + + if extension == '.py': + style = 'python' + elif extension == '.sh': + style = 'shell' + else: + style = 'cpp' + exec_insert_header(filename, style) + +################################################################################ +# UI +################################################################################ + +USAGE = """ +copyright_header.py - utilities for managing copyright headers of 'The Bitcoin +Core developers' in repository source files. + +Usage: + $ ./copyright_header + +Subcommands: + report + update + insert + +To see subcommand usage, run them without arguments. +""" + +SUBCOMMANDS = ['report', 'update', 'insert'] + +if __name__ == "__main__": + if len(sys.argv) == 1: + sys.exit(USAGE) + subcommand = sys.argv[1] + if subcommand not in SUBCOMMANDS: + sys.exit(USAGE) + if subcommand == 'report': + report_cmd(sys.argv) + elif subcommand == 'update': + update_cmd(sys.argv) + elif subcommand == 'insert': + insert_cmd(sys.argv) diff --git a/contrib/devtools/split-debug.sh.in b/contrib/devtools/split-debug.sh.in index deda49cc54..92b72b1446 100644 --- a/contrib/devtools/split-debug.sh.in +++ b/contrib/devtools/split-debug.sh.in @@ -1,5 +1,5 @@ #!/bin/sh - +set -e if [ $# -ne 3 ]; then echo "usage: $0 " fi diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py index 8f8685006e..6949cb7ced 100644 --- a/contrib/devtools/symbol-check.py +++ b/contrib/devtools/symbol-check.py @@ -1,74 +1,124 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2014 Wladimir J. van der Laan # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. ''' -A script to check that the (Linux) executables produced by gitian only contain -allowed gcc, glibc and libstdc++ version symbols. This makes sure they are -still compatible with the minimum supported Linux distribution versions. +A script to check that the executables produced by gitian only contain +certain symbols and are only linked against allowed libraries. Example usage: - find ../gitian-builder/build -type f -executable | xargs python contrib/devtools/symbol-check.py + find ../gitian-builder/build -type f -executable | xargs python3 contrib/devtools/symbol-check.py ''' -from __future__ import division, print_function, unicode_literals import subprocess import re import sys import os +from typing import List, Optional, Tuple -# Debian 6.0.9 (Squeeze) has: +# Debian 8 (Jessie) EOL: 2020. https://wiki.debian.org/DebianReleases#Production_Releases # -# - g++ version 4.4.5 (https://packages.debian.org/search?suite=default§ion=all&arch=any&searchon=names&keywords=g%2B%2B) -# - libc version 2.11.3 (https://packages.debian.org/search?suite=default§ion=all&arch=any&searchon=names&keywords=libc6) -# - libstdc++ version 4.4.5 (https://packages.debian.org/search?suite=default§ion=all&arch=any&searchon=names&keywords=libstdc%2B%2B6) +# - g++ version 4.9.2 (https://packages.debian.org/search?suite=jessie&arch=any&searchon=names&keywords=g%2B%2B) +# - libc version 2.19 (https://packages.debian.org/search?suite=jessie&arch=any&searchon=names&keywords=libc6) # -# Ubuntu 10.04.4 (Lucid Lynx) has: +# Ubuntu 16.04 (Xenial) EOL: 2024. https://wiki.ubuntu.com/Releases # -# - g++ version 4.4.3 (http://packages.ubuntu.com/search?keywords=g%2B%2B&searchon=names&suite=lucid§ion=all) -# - libc version 2.11.1 (http://packages.ubuntu.com/search?keywords=libc6&searchon=names&suite=lucid§ion=all) -# - libstdc++ version 4.4.3 (http://packages.ubuntu.com/search?suite=lucid§ion=all&arch=any&keywords=libstdc%2B%2B&searchon=names) +# - g++ version 5.3.1 (https://packages.ubuntu.com/search?keywords=g%2B%2B&searchon=names&suite=xenial§ion=all) +# - libc version 2.23.0 (https://packages.ubuntu.com/search?keywords=libc6&searchon=names&suite=xenial§ion=all) +# +# CentOS 7 EOL: 2024. https://wiki.centos.org/FAQ/General +# +# - g++ version 4.8.5 (http://mirror.centos.org/centos/7/os/x86_64/Packages/) +# - libc version 2.17 (http://mirror.centos.org/centos/7/os/x86_64/Packages/) # # Taking the minimum of these as our target. # -# According to GNU ABI document (http://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html) this corresponds to: -# GCC 4.4.0: GCC_4.4.0 -# GCC 4.4.2: GLIBCXX_3.4.13, CXXABI_1.3.3 -# (glibc) GLIBC_2_11 +# According to GNU ABI document (https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html) this corresponds to: +# GCC 4.8.5: GCC_4.8.0 +# (glibc) GLIBC_2_17 # MAX_VERSIONS = { -'GCC': (4,4,0), -'CXXABI': (1,3,3), -'GLIBCXX': (3,4,13), -'GLIBC': (2,11) +'GCC': (4,8,0), +'GLIBC': (2,17), +'LIBATOMIC': (1,0) } # See here for a description of _IO_stdin_used: # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=634261#109 # Ignore symbols that are exported as part of every executable IGNORE_EXPORTS = { -b'_edata', b'_end', b'_init', b'__bss_start', b'_fini', b'_IO_stdin_used' +'_edata', '_end', '__end__', '_init', '__bss_start', '__bss_start__', '_bss_end__', '__bss_end__', '_fini', '_IO_stdin_used', 'stdin', 'stdout', 'stderr', +'environ', '_environ', '__environ', } READELF_CMD = os.getenv('READELF', '/usr/bin/readelf') CPPFILT_CMD = os.getenv('CPPFILT', '/usr/bin/c++filt') +OBJDUMP_CMD = os.getenv('OBJDUMP', '/usr/bin/objdump') +OTOOL_CMD = os.getenv('OTOOL', '/usr/bin/otool') + # Allowed NEEDED libraries -ALLOWED_LIBRARIES = { +ELF_ALLOWED_LIBRARIES = { # bitcoind and bitcoin-qt -b'libgcc_s.so.1', # GCC base support -b'libc.so.6', # C library -b'libpthread.so.0', # threading -b'libanl.so.1', # DNS resolve -b'libm.so.6', # math library -b'librt.so.1', # real-time (clock) -b'ld-linux-x86-64.so.2', # 64-bit dynamic linker -b'ld-linux.so.2', # 32-bit dynamic linker +'libgcc_s.so.1', # GCC base support +'libc.so.6', # C library +'libpthread.so.0', # threading +'libm.so.6', # math library +'librt.so.1', # real-time (clock) +'libatomic.so.1', +'ld-linux-x86-64.so.2', # 64-bit dynamic linker +'ld-linux.so.2', # 32-bit dynamic linker +'ld-linux-aarch64.so.1', # 64-bit ARM dynamic linker +'ld-linux-armhf.so.3', # 32-bit ARM dynamic linker +'ld-linux-riscv64-lp64d.so.1', # 64-bit RISC-V dynamic linker +# bitcoin-qt only +'libxcb.so.1', # part of X11 +'libfontconfig.so.1', # font support +'libfreetype.so.6', # font parsing +'libdl.so.2' # programming interface to dynamic linker +} +ARCH_MIN_GLIBC_VER = { +'80386': (2,1), +'X86-64': (2,2,5), +'ARM': (2,4), +'AArch64':(2,17), +'RISC-V': (2,27) +} + +MACHO_ALLOWED_LIBRARIES = { +# bitcoind and bitcoin-qt +'libc++.1.dylib', # C++ Standard Library +'libSystem.B.dylib', # libc, libm, libpthread, libinfo +# bitcoin-qt only +'AppKit', # user interface +'ApplicationServices', # common application tasks. +'Carbon', # deprecated c back-compat API +'CoreFoundation', # low level func, data types +'CoreGraphics', # 2D rendering +'CoreServices', # operating system services +'CoreText', # interface for laying out text and handling fonts. +'Foundation', # base layer functionality for apps/frameworks +'ImageIO', # read and write image file formats. +'IOKit', # user-space access to hardware devices and drivers. +'libobjc.A.dylib', # Objective-C runtime library +} + +PE_ALLOWED_LIBRARIES = { +'ADVAPI32.dll', # security & registry +'IPHLPAPI.DLL', # IP helper API +'KERNEL32.dll', # win32 base APIs +'msvcrt.dll', # C standard library for MSVC +'SHELL32.dll', # shell API +'USER32.dll', # user interface +'WS2_32.dll', # sockets # bitcoin-qt only -b'libX11-xcb.so.1', # part of X11 -b'libX11.so.6', # part of X11 -b'libxcb.so.1', # part of X11 -b'libfontconfig.so.1', # font support -b'libfreetype.so.6', # font parsing -b'libdl.so.2' # programming interface to dynamic linker +'dwmapi.dll', # desktop window manager +'GDI32.dll', # graphics device interface +'IMM32.dll', # input method editor +'ole32.dll', # component object model +'OLEAUT32.dll', # OLE Automation API +'SHLWAPI.dll', # light weight shell API +'UxTheme.dll', +'VERSION.dll', # version checking +'WINMM.dll', # WinMM audio API } class CPPFilt(object): @@ -78,10 +128,10 @@ class CPPFilt(object): Use a pipe to the 'c++filt' command. ''' def __init__(self): - self.proc = subprocess.Popen(CPPFILT_CMD, stdin=subprocess.PIPE, stdout=subprocess.PIPE) + self.proc = subprocess.Popen(CPPFILT_CMD, stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True) def __call__(self, mangled): - self.proc.stdin.write(mangled + b'\n') + self.proc.stdin.write(mangled + '\n') self.proc.stdin.flush() return self.proc.stdout.readline().rstrip() @@ -90,75 +140,167 @@ def close(self): self.proc.stdout.close() self.proc.wait() -def read_symbols(executable, imports=True): +def read_symbols(executable, imports=True) -> List[Tuple[str, str, str]]: ''' - Parse an ELF executable and return a list of (symbol,version) tuples + Parse an ELF executable and return a list of (symbol,version, arch) tuples for dynamic, imported symbols. ''' - p = subprocess.Popen([READELF_CMD, '--dyn-syms', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) + p = subprocess.Popen([READELF_CMD, '--dyn-syms', '-W', '-h', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True) (stdout, stderr) = p.communicate() if p.returncode: - raise IOError('Could not read symbols for %s: %s' % (executable, stderr.strip())) + raise IOError('Could not read symbols for {}: {}'.format(executable, stderr.strip())) syms = [] - for line in stdout.split(b'\n'): + for line in stdout.splitlines(): line = line.split() - if len(line)>7 and re.match(b'[0-9]+:$', line[0]): - (sym, _, version) = line[7].partition(b'@') - is_import = line[6] == b'UND' - if version.startswith(b'@'): + if 'Machine:' in line: + arch = line[-1] + if len(line)>7 and re.match('[0-9]+:$', line[0]): + (sym, _, version) = line[7].partition('@') + is_import = line[6] == 'UND' + if version.startswith('@'): version = version[1:] if is_import == imports: - syms.append((sym, version)) + syms.append((sym, version, arch)) return syms -def check_version(max_versions, version): - if b'_' in version: - (lib, _, ver) = version.rpartition(b'_') +def check_version(max_versions, version, arch) -> bool: + if '_' in version: + (lib, _, ver) = version.rpartition('_') else: lib = version ver = '0' - ver = tuple([int(x) for x in ver.split(b'.')]) + ver = tuple([int(x) for x in ver.split('.')]) if not lib in max_versions: return False - return ver <= max_versions[lib] + return ver <= max_versions[lib] or lib == 'GLIBC' and ver <= ARCH_MIN_GLIBC_VER[arch] -def read_libraries(filename): - p = subprocess.Popen([READELF_CMD, '-d', '-W', filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) +def elf_read_libraries(filename) -> List[str]: + p = subprocess.Popen([READELF_CMD, '-d', '-W', filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True) (stdout, stderr) = p.communicate() if p.returncode: raise IOError('Error opening file') libraries = [] - for line in stdout.split(b'\n'): + for line in stdout.splitlines(): tokens = line.split() - if len(tokens)>2 and tokens[1] == b'(NEEDED)': - match = re.match(b'^Shared library: \[(.*)\]$', b' '.join(tokens[2:])) + if len(tokens)>2 and tokens[1] == '(NEEDED)': + match = re.match(r'^Shared library: \[(.*)\]$', ' '.join(tokens[2:])) if match: libraries.append(match.group(1)) else: raise ValueError('Unparseable (NEEDED) specification') return libraries -if __name__ == '__main__': +def check_imported_symbols(filename) -> bool: + cppfilt = CPPFilt() + ok = True + for sym, version, arch in read_symbols(filename, True): + if version and not check_version(MAX_VERSIONS, version, arch): + print('{}: symbol {} from unsupported version {}'.format(filename, cppfilt(sym), version)) + ok = False + return ok + +def check_exported_symbols(filename) -> bool: cppfilt = CPPFilt() + ok = True + for sym,version,arch in read_symbols(filename, False): + if arch == 'RISC-V' or sym in IGNORE_EXPORTS: + continue + print('{}: export of symbol {} not allowed'.format(filename, cppfilt(sym))) + ok = False + return ok + +def check_ELF_libraries(filename) -> bool: + ok = True + for library_name in elf_read_libraries(filename): + if library_name not in ELF_ALLOWED_LIBRARIES: + print('{}: NEEDED library {} is not allowed'.format(filename, library_name)) + ok = False + return ok + +def macho_read_libraries(filename) -> List[str]: + p = subprocess.Popen([OTOOL_CMD, '-L', filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True) + (stdout, stderr) = p.communicate() + if p.returncode: + raise IOError('Error opening file') + libraries = [] + for line in stdout.splitlines(): + tokens = line.split() + if len(tokens) == 1: # skip executable name + continue + libraries.append(tokens[0].split('/')[-1]) + return libraries + +def check_MACHO_libraries(filename) -> bool: + ok = True + for dylib in macho_read_libraries(filename): + if dylib not in MACHO_ALLOWED_LIBRARIES: + print('{} is not in ALLOWED_LIBRARIES!'.format(dylib)) + ok = False + return ok + +def pe_read_libraries(filename) -> List[str]: + p = subprocess.Popen([OBJDUMP_CMD, '-x', filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True) + (stdout, stderr) = p.communicate() + if p.returncode: + raise IOError('Error opening file') + libraries = [] + for line in stdout.splitlines(): + if 'DLL Name:' in line: + tokens = line.split(': ') + libraries.append(tokens[1]) + return libraries + +def check_PE_libraries(filename) -> bool: + ok = True + for dylib in pe_read_libraries(filename): + if dylib not in PE_ALLOWED_LIBRARIES: + print('{} is not in ALLOWED_LIBRARIES!'.format(dylib)) + ok = False + return ok + +CHECKS = { +'ELF': [ + ('IMPORTED_SYMBOLS', check_imported_symbols), + ('EXPORTED_SYMBOLS', check_exported_symbols), + ('LIBRARY_DEPENDENCIES', check_ELF_libraries) +], +'MACHO': [ + ('DYNAMIC_LIBRARIES', check_MACHO_libraries) +], +'PE' : [ + ('DYNAMIC_LIBRARIES', check_PE_libraries) +] +} + +def identify_executable(executable) -> Optional[str]: + with open(filename, 'rb') as f: + magic = f.read(4) + if magic.startswith(b'MZ'): + return 'PE' + elif magic.startswith(b'\x7fELF'): + return 'ELF' + elif magic.startswith(b'\xcf\xfa'): + return 'MACHO' + return None + +if __name__ == '__main__': retval = 0 for filename in sys.argv[1:]: - # Check imported symbols - for sym,version in read_symbols(filename, True): - if version and not check_version(MAX_VERSIONS, version): - print('%s: symbol %s from unsupported version %s' % (filename, cppfilt(sym).decode('utf-8'), version.decode('utf-8'))) + try: + etype = identify_executable(filename) + if etype is None: + print('{}: unknown format'.format(filename)) retval = 1 - # Check exported symbols - for sym,version in read_symbols(filename, False): - if sym in IGNORE_EXPORTS: continue - print('%s: export of symbol %s not allowed' % (filename, cppfilt(sym).decode('utf-8'))) - retval = 1 - # Check dependency libraries - for library_name in read_libraries(filename): - if library_name not in ALLOWED_LIBRARIES: - print('%s: NEEDED library %s is not allowed' % (filename, library_name.decode('utf-8'))) - retval = 1 - - exit(retval) - + failed = [] + for (name, func) in CHECKS[etype]: + if not func(filename): + failed.append(name) + if failed: + print('{}: failed {}'.format(filename, ' '.join(failed))) + retval = 1 + except IOError: + print('{}: cannot open'.format(filename)) + retval = 1 + sys.exit(retval) diff --git a/contrib/devtools/test_deterministic_coverage.sh b/contrib/devtools/test_deterministic_coverage.sh new file mode 100644 index 0000000000..8501c72f04 --- /dev/null +++ b/contrib/devtools/test_deterministic_coverage.sh @@ -0,0 +1,151 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2019-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. +# +# Test for deterministic coverage across unit test runs. + +export LC_ALL=C + +# Use GCOV_EXECUTABLE="gcov" if compiling with gcc. +# Use GCOV_EXECUTABLE="llvm-cov gcov" if compiling with clang. +GCOV_EXECUTABLE="gcov" + +# Disable tests known to cause non-deterministic behaviour and document the source or point of non-determinism. +NON_DETERMINISTIC_TESTS=( + "blockfilter_index_tests/blockfilter_index_initial_sync" # src/checkqueue.h: In CCheckQueue::Loop(): while (queue.empty()) { ... } + "coinselector_tests/knapsack_solver_test" # coinselector_tests.cpp: if (equal_sets(setCoinsRet, setCoinsRet2)) + "fs_tests/fsbridge_fstream" # deterministic test failure? + "miner_tests/CreateNewBlock_validity" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10) + "scheduler_tests/manythreads" # scheduler.cpp: CScheduler::serviceQueue() + "scheduler_tests/singlethreadedscheduler_ordered" # scheduler.cpp: CScheduler::serviceQueue() + "txvalidationcache_tests/checkinputs_test" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10) + "txvalidationcache_tests/tx_mempool_block_doublespend" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10) + "txindex_tests/txindex_initial_sync" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10) + "txvalidation_tests/tx_mempool_reject_coinbase" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10) + "validation_block_tests/processnewblock_signals_ordering" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10) + "wallet_tests/coin_mark_dirty_immature_credit" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10) + "wallet_tests/dummy_input_size_test" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10) + "wallet_tests/importmulti_rescan" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10) + "wallet_tests/importwallet_rescan" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10) + "wallet_tests/ListCoins" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10) + "wallet_tests/scan_for_wallet_transactions" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10) + "wallet_tests/wallet_disableprivkeys" # validation.cpp: if (GetMainSignals().CallbacksPending() > 10) +) + +TEST_BITCOIN_BINARY="src/test/test_bitcoin" + +print_usage() { + echo "Usage: $0 [custom test filter (default: all but known non-deterministic tests)] [number of test runs (default: 2)]" +} + +N_TEST_RUNS=2 +BOOST_TEST_RUN_FILTERS="" +if [[ $# != 0 ]]; then + if [[ $1 == "--help" ]]; then + print_usage + exit + fi + PARSED_ARGUMENTS=0 + if [[ $1 =~ [a-z] ]]; then + BOOST_TEST_RUN_FILTERS=$1 + PARSED_ARGUMENTS=$((PARSED_ARGUMENTS + 1)) + shift + fi + if [[ $1 =~ ^[0-9]+$ ]]; then + N_TEST_RUNS=$1 + PARSED_ARGUMENTS=$((PARSED_ARGUMENTS + 1)) + shift + fi + if [[ ${PARSED_ARGUMENTS} == 0 || $# -gt 2 || ${N_TEST_RUNS} -lt 2 ]]; then + print_usage + exit + fi +fi +if [[ ${BOOST_TEST_RUN_FILTERS} == "" ]]; then + BOOST_TEST_RUN_FILTERS="$(IFS=":"; echo "!${NON_DETERMINISTIC_TESTS[*]}" | sed 's/:/:!/g')" +else + echo "Using Boost test filter: ${BOOST_TEST_RUN_FILTERS}" + echo +fi + +if ! command -v gcov > /dev/null; then + echo "Error: gcov not installed. Exiting." + exit 1 +fi + +if ! command -v gcovr > /dev/null; then + echo "Error: gcovr not installed. Exiting." + exit 1 +fi + +if [[ ! -e ${TEST_BITCOIN_BINARY} ]]; then + echo "Error: Executable ${TEST_BITCOIN_BINARY} not found. Run \"./configure --enable-lcov\" and compile." + exit 1 +fi + +get_file_suffix_count() { + find src/ -type f -name "*.$1" | wc -l +} + +if [[ $(get_file_suffix_count gcno) == 0 ]]; then + echo "Error: Could not find any *.gcno files. The *.gcno files are generated by the compiler. Run \"./configure --enable-lcov\" and re-compile." + exit 1 +fi + +get_covr_filename() { + echo "gcovr.run-$1.txt" +} + +TEST_RUN_ID=0 +while [[ ${TEST_RUN_ID} -lt ${N_TEST_RUNS} ]]; do + TEST_RUN_ID=$((TEST_RUN_ID + 1)) + echo "[$(date +"%Y-%m-%d %H:%M:%S")] Measuring coverage, run #${TEST_RUN_ID} of ${N_TEST_RUNS}" + find src/ -type f -name "*.gcda" -exec rm {} \; + if [[ $(get_file_suffix_count gcda) != 0 ]]; then + echo "Error: Stale *.gcda files found. Exiting." + exit 1 + fi + TEST_OUTPUT_TEMPFILE=$(mktemp) + if ! BOOST_TEST_RUN_FILTERS="${BOOST_TEST_RUN_FILTERS}" ${TEST_BITCOIN_BINARY} > "${TEST_OUTPUT_TEMPFILE}" 2>&1; then + cat "${TEST_OUTPUT_TEMPFILE}" + rm "${TEST_OUTPUT_TEMPFILE}" + exit 1 + fi + rm "${TEST_OUTPUT_TEMPFILE}" + if [[ $(get_file_suffix_count gcda) == 0 ]]; then + echo "Error: Running the test suite did not create any *.gcda files. The gcda files are generated when the instrumented test programs are executed. Run \"./configure --enable-lcov\" and re-compile." + exit 1 + fi + GCOVR_TEMPFILE=$(mktemp) + if ! gcovr --gcov-executable "${GCOV_EXECUTABLE}" -r src/ > "${GCOVR_TEMPFILE}"; then + echo "Error: gcovr failed. Output written to ${GCOVR_TEMPFILE}. Exiting." + exit 1 + fi + GCOVR_FILENAME=$(get_covr_filename ${TEST_RUN_ID}) + mv "${GCOVR_TEMPFILE}" "${GCOVR_FILENAME}" + if grep -E "^TOTAL *0 *0 " "${GCOVR_FILENAME}"; then + echo "Error: Spurious gcovr output. Make sure the correct GCOV_EXECUTABLE variable is set in $0 (\"gcov\" for gcc, \"llvm-cov gcov\" for clang)." + exit 1 + fi + if [[ ${TEST_RUN_ID} != 1 ]]; then + COVERAGE_DIFF=$(diff -u "$(get_covr_filename 1)" "${GCOVR_FILENAME}") + if [[ ${COVERAGE_DIFF} != "" ]]; then + echo + echo "The line coverage is non-deterministic between runs. Exiting." + echo + echo "The test suite must be deterministic in the sense that the set of lines executed at least" + echo "once must be identical between runs. This is a necessary condition for meaningful" + echo "coverage measuring." + echo + echo "${COVERAGE_DIFF}" + exit 1 + fi + rm "${GCOVR_FILENAME}" + fi +done + +echo +echo "Coverage test passed: Deterministic coverage across ${N_TEST_RUNS} runs." +exit diff --git a/src/.clang-format b/src/.clang-format new file mode 100644 index 0000000000..ef7a0ef5c7 --- /dev/null +++ b/src/.clang-format @@ -0,0 +1,55 @@ +Language: Cpp +AccessModifierOffset: -4 +AlignAfterOpenBracket: true +AlignEscapedNewlinesLeft: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: false +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: true +BinPackParameters: false +BreakBeforeBinaryOperators: false +BreakBeforeBraces: Custom +BraceWrapping: + AfterClass: true + AfterFunction: true +BreakBeforeTernaryOperators: false +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 0 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +IndentCaseLabels: false +IndentFunctionDeclarationAfterType: false +IndentWidth: 4 +KeepEmptyLinesAtTheStartOfBlocks: false +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: None +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: false +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +Standard: Cpp11 +TabWidth: 8 +UseTab: Never diff --git a/test/lint/README.md b/test/lint/README.md new file mode 100644 index 0000000000..d15c061288 --- /dev/null +++ b/test/lint/README.md @@ -0,0 +1,38 @@ +This folder contains lint scripts. + +check-doc.py +============ +Check for missing documentation of command line options. + +commit-script-check.sh +====================== +Verification of [scripted diffs](/doc/developer-notes.md#scripted-diffs). +Scripted diffs are only assumed to run on the latest LTS release of Ubuntu. Running them on other operating systems +might require installing GNU tools, such as GNU sed. + +git-subtree-check.sh +==================== +Run this script from the root of the repository to verify that a subtree matches the contents of +the commit it claims to have been updated to. + +To use, make sure that you have fetched the upstream repository branch in which the subtree is +maintained: +* for `src/secp256k1`: https://github.com/bitcoin-core/secp256k1.git (branch master) +* for `src/leveldb`: https://github.com/bitcoin-core/leveldb.git (branch bitcoin-fork) +* for `src/univalue`: https://github.com/bitcoin-core/univalue.git (branch master) +* for `src/crypto/ctaes`: https://github.com/bitcoin-core/ctaes.git (branch master) +* for `src/crc32c`: https://github.com/google/crc32c.git (branch master) + +To do so, add the upstream repository as remote: + +``` +git remote add --fetch secp256k1 https://github.com/bitcoin-core/secp256k1.git +``` + +Usage: `git-subtree-check.sh DIR (COMMIT)` + +`COMMIT` may be omitted, in which case `HEAD` is used. + +lint-all.sh +=========== +Calls other scripts with the `lint-` prefix. diff --git a/test/lint/check-doc.py b/test/lint/check-doc.py new file mode 100644 index 0000000000..bd947d194c --- /dev/null +++ b/test/lint/check-doc.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-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 checks if all command line args are documented. +Return value is 0 to indicate no error. + +Author: @MarcoFalke +''' + +from subprocess import check_output +import re + +FOLDER_GREP = 'src' +FOLDER_TEST = 'src/test/' +REGEX_ARG = r'(?:ForceSet|SoftSet|Get|Is)(?:Bool)?Args?(?:Set)?\("(-[^"]+)"' +REGEX_DOC = r'AddArg\("(-[^"=]+?)(?:=|")' +CMD_ROOT_DIR = '$(git rev-parse --show-toplevel)/{}'.format(FOLDER_GREP) +CMD_GREP_ARGS = r"git grep --perl-regexp '{}' -- {} ':(exclude){}'".format(REGEX_ARG, CMD_ROOT_DIR, FOLDER_TEST) +CMD_GREP_WALLET_ARGS = r"git grep --function-context 'void WalletInit::AddWalletOptions' -- {} | grep AddArg".format(CMD_ROOT_DIR) +CMD_GREP_WALLET_HIDDEN_ARGS = r"git grep --function-context 'void DummyWalletInit::AddWalletOptions' -- {}".format(CMD_ROOT_DIR) +CMD_GREP_DOCS = r"git grep --perl-regexp '{}' {}".format(REGEX_DOC, CMD_ROOT_DIR) +# list unsupported, deprecated and duplicate args as they need no documentation +SET_DOC_OPTIONAL = set(['-h', '-help', '-dbcrashratio', '-forcecompactdb']) + + +def lint_missing_argument_documentation(): + used = check_output(CMD_GREP_ARGS, shell=True).decode('utf8').strip() + docd = check_output(CMD_GREP_DOCS, shell=True).decode('utf8').strip() + + args_used = set(re.findall(re.compile(REGEX_ARG), used)) + args_docd = set(re.findall(re.compile(REGEX_DOC), docd)).union(SET_DOC_OPTIONAL) + args_need_doc = args_used.difference(args_docd) + args_unknown = args_docd.difference(args_used) + + print("Args used : {}".format(len(args_used))) + print("Args documented : {}".format(len(args_docd))) + print("Args undocumented: {}".format(len(args_need_doc))) + print(args_need_doc) + print("Args unknown : {}".format(len(args_unknown))) + print(args_unknown) + + assert 0 == len(args_need_doc), "Please document the following arguments: {}".format(args_need_doc) + + +def lint_missing_hidden_wallet_args(): + wallet_args = check_output(CMD_GREP_WALLET_ARGS, shell=True).decode('utf8').strip() + wallet_hidden_args = check_output(CMD_GREP_WALLET_HIDDEN_ARGS, shell=True).decode('utf8').strip() + + wallet_args = set(re.findall(re.compile(REGEX_DOC), wallet_args)) + wallet_hidden_args = set(re.findall(re.compile(r' "([^"=]+)'), wallet_hidden_args)) + + hidden_missing = wallet_args.difference(wallet_hidden_args) + if hidden_missing: + assert 0, "Please add {} to the hidden args in DummyWalletInit::AddWalletOptions".format(hidden_missing) + + +def main(): + lint_missing_argument_documentation() + lint_missing_hidden_wallet_args() + + +if __name__ == "__main__": + main() diff --git a/test/lint/check-rpc-mappings.py b/test/lint/check-rpc-mappings.py new file mode 100644 index 0000000000..0a4cc875d0 --- /dev/null +++ b/test/lint/check-rpc-mappings.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python3 +# Copyright (c) 2017-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. +"""Check RPC argument consistency.""" + +from collections import defaultdict +import os +import re +import sys + +# Source files (relative to root) to scan for dispatch tables +SOURCES = [ + "src/rpc/server.cpp", + "src/rpc/blockchain.cpp", + "src/rpc/mining.cpp", + "src/rpc/misc.cpp", + "src/rpc/net.cpp", + "src/rpc/rawtransaction.cpp", + "src/wallet/rpcwallet.cpp", +] +# Source file (relative to root) containing conversion mapping +SOURCE_CLIENT = 'src/rpc/client.cpp' +# Argument names that should be ignored in consistency checks +IGNORE_DUMMY_ARGS = {'dummy', 'arg0', 'arg1', 'arg2', 'arg3', 'arg4', 'arg5', 'arg6', 'arg7', 'arg8', 'arg9'} + +class RPCCommand: + def __init__(self, name, args): + self.name = name + self.args = args + +class RPCArgument: + def __init__(self, names, idx): + self.names = names + self.idx = idx + self.convert = False + +def parse_string(s): + assert s[0] == '"' + assert s[-1] == '"' + return s[1:-1] + +def process_commands(fname): + """Find and parse dispatch table in implementation file `fname`.""" + cmds = [] + in_rpcs = False + with open(fname, "r", encoding="utf8") as f: + for line in f: + line = line.rstrip() + if not in_rpcs: + if re.match(r"static const CRPCCommand .*\[\] =", line): + in_rpcs = True + else: + if line.startswith('};'): + in_rpcs = False + elif '{' in line and '"' in line: + m = re.search(r'{ *("[^"]*"), *("[^"]*"), *&([^,]*), *{([^}]*)} *},', line) + assert m, 'No match to table expression: %s' % line + name = parse_string(m.group(2)) + args_str = m.group(4).strip() + if args_str: + args = [RPCArgument(parse_string(x.strip()).split('|'), idx) for idx, x in enumerate(args_str.split(','))] + else: + args = [] + cmds.append(RPCCommand(name, args)) + assert not in_rpcs and cmds, "Something went wrong with parsing the C++ file: update the regexps" + return cmds + +def process_mapping(fname): + """Find and parse conversion table in implementation file `fname`.""" + cmds = [] + in_rpcs = False + with open(fname, "r", encoding="utf8") as f: + for line in f: + line = line.rstrip() + if not in_rpcs: + if line == 'static const CRPCConvertParam vRPCConvertParams[] =': + in_rpcs = True + else: + if line.startswith('};'): + in_rpcs = False + elif '{' in line and '"' in line: + m = re.search(r'{ *("[^"]*"), *([0-9]+) *, *("[^"]*") *},', line) + assert m, 'No match to table expression: %s' % line + name = parse_string(m.group(1)) + idx = int(m.group(2)) + argname = parse_string(m.group(3)) + cmds.append((name, idx, argname)) + assert not in_rpcs and cmds + return cmds + +def main(): + if len(sys.argv) != 2: + print('Usage: {} ROOT-DIR'.format(sys.argv[0]), file=sys.stderr) + sys.exit(1) + + root = sys.argv[1] + + # Get all commands from dispatch tables + cmds = [] + for fname in SOURCES: + cmds += process_commands(os.path.join(root, fname)) + + cmds_by_name = {} + for cmd in cmds: + cmds_by_name[cmd.name] = cmd + + # Get current convert mapping for client + client = SOURCE_CLIENT + mapping = set(process_mapping(os.path.join(root, client))) + + print('* Checking consistency between dispatch tables and vRPCConvertParams') + + # Check mapping consistency + errors = 0 + for (cmdname, argidx, argname) in mapping: + try: + rargnames = cmds_by_name[cmdname].args[argidx].names + except IndexError: + print('ERROR: %s argument %i (named %s in vRPCConvertParams) is not defined in dispatch table' % (cmdname, argidx, argname)) + errors += 1 + continue + if argname not in rargnames: + print('ERROR: %s argument %i is named %s in vRPCConvertParams but %s in dispatch table' % (cmdname, argidx, argname, rargnames), file=sys.stderr) + errors += 1 + + # Check for conflicts in vRPCConvertParams conversion + # All aliases for an argument must either be present in the + # conversion table, or not. Anything in between means an oversight + # and some aliases won't work. + for cmd in cmds: + for arg in cmd.args: + convert = [((cmd.name, arg.idx, argname) in mapping) for argname in arg.names] + if any(convert) != all(convert): + print('ERROR: %s argument %s has conflicts in vRPCConvertParams conversion specifier %s' % (cmd.name, arg.names, convert)) + errors += 1 + arg.convert = all(convert) + + # Check for conversion difference by argument name. + # It is preferable for API consistency that arguments with the same name + # have the same conversion, so bin by argument name. + all_methods_by_argname = defaultdict(list) + converts_by_argname = defaultdict(list) + for cmd in cmds: + for arg in cmd.args: + for argname in arg.names: + all_methods_by_argname[argname].append(cmd.name) + converts_by_argname[argname].append(arg.convert) + + for argname, convert in converts_by_argname.items(): + if all(convert) != any(convert): + if argname in IGNORE_DUMMY_ARGS: + # these are testing or dummy, don't warn for them + continue + print('WARNING: conversion mismatch for argument named %s (%s)' % + (argname, list(zip(all_methods_by_argname[argname], converts_by_argname[argname])))) + + sys.exit(errors > 0) + + +if __name__ == '__main__': + main() diff --git a/test/lint/commit-script-check.sh b/test/lint/commit-script-check.sh new file mode 100644 index 0000000000..ff3f784437 --- /dev/null +++ b/test/lint/commit-script-check.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# Copyright (c) 2017-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 simple script checks for commits beginning with: scripted-diff: +# If found, looks for a script between the lines -BEGIN VERIFY SCRIPT- and +# -END VERIFY SCRIPT-. If no ending is found, it reads until the end of the +# commit message. + +# The resulting script should exactly transform the previous commit into the current +# one. Any remaining diff signals an error. + +export LC_ALL=C +if test "x$1" = "x"; then + echo "Usage: $0 ..." + exit 1 +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 + 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')" + if test "x$SCRIPT" = "x"; then + echo "Error: missing script for: $commit" + echo "Failed" + RET=1 + else + echo "Running script for: $commit" + echo "$SCRIPT" + (eval "$SCRIPT") + git --no-pager diff --exit-code $commit && echo "OK" || (echo "Failed"; false) || RET=1 + fi + git reset --quiet --hard HEAD + else + if git rev-list "--format=%b" -n1 $commit | grep -q '^-\(BEGIN\|END\)[ a-zA-Z]*-$'; then + echo "Error: script block marker but no scripted-diff in title" + echo "Failed" + RET=1 + fi + fi +done +git checkout --quiet $PREV_BRANCH 2>/dev/null || git checkout --quiet $PREV_HEAD +exit $RET diff --git a/test/lint/extended-lint-all.sh b/test/lint/extended-lint-all.sh new file mode 100644 index 0000000000..be5d9db4a9 --- /dev/null +++ b/test/lint/extended-lint-all.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2019-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. +# +# 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 100644 index 0000000000..20021d8605 --- /dev/null +++ b/test/lint/extended-lint-cppcheck.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2019-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. +# + +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/crc32c/" ":(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 -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/git-subtree-check.sh b/test/lint/git-subtree-check.sh new file mode 100644 index 0000000000..5a0500df25 --- /dev/null +++ b/test/lint/git-subtree-check.sh @@ -0,0 +1,96 @@ +#!/bin/sh +# Copyright (c) 2015-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 +# Strip trailing / from directory path (in case it was added by autocomplete) +DIR="${1%/}" +COMMIT="$2" +if [ -z "$COMMIT" ]; then + COMMIT=HEAD +fi + +# Taken from git-subtree (Copyright (C) 2009 Avery Pennarun ) +find_latest_squash() +{ + dir="$1" + sq= + main= + sub= + git log --grep="^git-subtree-dir: $dir/*\$" \ + --pretty=format:'START %H%n%s%n%n%b%nEND%n' "$COMMIT" | + while read a b _; do + case "$a" in + START) sq="$b" ;; + git-subtree-mainline:) main="$b" ;; + git-subtree-split:) sub="$b" ;; + END) + if [ -n "$sub" ]; then + if [ -n "$main" ]; then + # a rejoin commit? + # Pretend its sub was a squash. + sq="$sub" + fi + echo "$sq" "$sub" + break + fi + sq= + main= + sub= + ;; + esac + done +} + +# find latest subtree update +latest_squash="$(find_latest_squash "$DIR")" +if [ -z "$latest_squash" ]; then + echo "ERROR: $DIR is not a subtree" >&2 + exit 2 +fi +set $latest_squash +old=$1 +rev=$2 + +# get the tree in the current commit +tree_actual=$(git ls-tree -d "$COMMIT" "$DIR" | head -n 1) +if [ -z "$tree_actual" ]; then + echo "FAIL: subtree directory $DIR not found in $COMMIT" >&2 + exit 1 +fi +set $tree_actual +tree_actual_type=$2 +tree_actual_tree=$3 +echo "$DIR in $COMMIT currently refers to $tree_actual_type $tree_actual_tree" +if [ "d$tree_actual_type" != "dtree" ]; then + echo "FAIL: subtree directory $DIR is not a tree in $COMMIT" >&2 + exit 1 +fi + +# get the tree at the time of the last subtree update +tree_commit=$(git show -s --format="%T" $old) +echo "$DIR in $COMMIT was last updated in commit $old (tree $tree_commit)" + +# ... and compare the actual tree with it +if [ "$tree_actual_tree" != "$tree_commit" ]; then + git diff $tree_commit $tree_actual_tree >&2 + echo "FAIL: subtree directory was touched without subtree merge" >&2 + exit 1 +fi + +# get the tree in the subtree commit referred to +if [ "d$(git cat-file -t $rev 2>/dev/null)" != dcommit ]; then + echo "subtree commit $rev unavailable: cannot compare. Did you add and fetch the remote?" >&2 + exit +fi +tree_subtree=$(git show -s --format="%T" $rev) +echo "$DIR in $COMMIT was last updated to upstream commit $rev (tree $tree_subtree)" + +# ... and compare the actual tree with it +if [ "$tree_actual_tree" != "$tree_subtree" ]; then + echo "FAIL: subtree update commit differs from upstream tree!" >&2 + exit 1 +fi + +echo "GOOD" diff --git a/test/lint/lint-all.sh b/test/lint/lint-all.sh new file mode 100644 index 0000000000..fabc24c91b --- /dev/null +++ b/test/lint/lint-all.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2017-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/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]}") + +EXIT_CODE=0 + +for f in "${SCRIPTDIR}"/lint-*.sh; do + if [ "$(basename "$f")" != "$LINTALL" ]; then + if ! "$f"; then + echo "^---- failure generated from $f" + EXIT_CODE=1 + fi + fi +done + +exit ${EXIT_CODE} diff --git a/test/lint/lint-assertions.sh b/test/lint/lint-assertions.sh new file mode 100644 index 0000000000..d30a8ca231 --- /dev/null +++ b/test/lint/lint-assertions.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +# +# 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. +# +# Check for assertions with obvious side effects. + +export LC_ALL=C + +EXIT_CODE=0 + +# PRE31-C (SEI CERT C Coding Standard): +# "Assertions should not contain assignments, increment, or decrement operators." +OUTPUT=$(git grep -E '[^_]assert\(.*(\+\+|\-\-|[^=!<>]=[^=!<>]).*\);' -- "*.cpp" "*.h") +if [[ ${OUTPUT} != "" ]]; then + echo "Assertions should not have side effects:" + echo + echo "${OUTPUT}" + EXIT_CODE=1 +fi + +# Macro CHECK_NONFATAL(condition) should be used instead of assert for RPC code, where it +# is undesirable to crash the whole program. See: src/util/check.h +# src/rpc/server.cpp is excluded from this check since it's mostly meta-code. +OUTPUT=$(git grep -nE '\<(A|a)ssert *\(.*\);' -- "src/rpc/" "src/wallet/rpc*" ":(exclude)src/rpc/server.cpp") +if [[ ${OUTPUT} != "" ]]; then + echo "CHECK_NONFATAL(condition) should be used instead of assert for RPC code." + echo + echo "${OUTPUT}" + EXIT_CODE=1 +fi + +exit ${EXIT_CODE} diff --git a/test/lint/lint-circular-dependencies.sh b/test/lint/lint-circular-dependencies.sh new file mode 100644 index 0000000000..6bd02d45ac --- /dev/null +++ b/test/lint/lint-circular-dependencies.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2018-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. +# +# Check for circular dependencies + +export LC_ALL=C + +EXPECTED_CIRCULAR_DEPENDENCIES=( + "chainparamsbase -> util/system -> chainparamsbase" + "index/txindex -> validation -> index/txindex" + "policy/fees -> txmempool -> policy/fees" + "qt/addresstablemodel -> qt/walletmodel -> qt/addresstablemodel" + "qt/bitcoingui -> qt/walletframe -> qt/bitcoingui" + "qt/recentrequeststablemodel -> qt/walletmodel -> qt/recentrequeststablemodel" + "qt/sendcoinsdialog -> qt/walletmodel -> qt/sendcoinsdialog" + "qt/transactiontablemodel -> qt/walletmodel -> qt/transactiontablemodel" + "txmempool -> validation -> txmempool" + "wallet/fees -> wallet/wallet -> wallet/fees" + "wallet/wallet -> wallet/walletdb -> wallet/wallet" + "policy/fees -> txmempool -> validation -> policy/fees" +) + +EXIT_CODE=0 + +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" ) + IS_EXPECTED_CIRC=0 + for EXPECTED_CIRC in "${EXPECTED_CIRCULAR_DEPENDENCIES[@]}"; do + if [[ "${CIRC}" == "${EXPECTED_CIRC}" ]]; then + IS_EXPECTED_CIRC=1 + break + fi + done + if [[ ${IS_EXPECTED_CIRC} == 0 ]]; then + echo "A new circular dependency in the form of \"${CIRC}\" appears to have been introduced." + echo + EXIT_CODE=1 + fi +done + +for EXPECTED_CIRC in "${EXPECTED_CIRCULAR_DEPENDENCIES[@]}"; do + IS_PRESENT_EXPECTED_CIRC=0 + for CIRC in "${CIRCULAR_DEPENDENCIES[@]}"; do + if [[ "${CIRC}" == "${EXPECTED_CIRC}" ]]; then + IS_PRESENT_EXPECTED_CIRC=1 + break + fi + done + if [[ ${IS_PRESENT_EXPECTED_CIRC} == 0 ]]; then + echo "Good job! The circular dependency \"${EXPECTED_CIRC}\" is no longer present." + echo "Please remove it from EXPECTED_CIRCULAR_DEPENDENCIES in $0" + echo "to make sure this circular dependency is not accidentally reintroduced." + echo + EXIT_CODE=1 + fi +done + +exit ${EXIT_CODE} diff --git a/test/lint/lint-filenames.sh b/test/lint/lint-filenames.sh new file mode 100644 index 0000000000..3f7491cd2b --- /dev/null +++ b/test/lint/lint-filenames.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# +# 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. +# +# Make sure only lowercase alphanumerics (a-z0-9), underscores (_), +# hyphens (-) and dots (.) are used in source code filenames. + +export LC_ALL=C + +EXIT_CODE=0 +OUTPUT=$(git ls-files --full-name -- "*.[cC][pP][pP]" "*.[hH]" "*.[pP][yY]" "*.[sS][hH]" | \ + grep -vE '^[a-z0-9_./-]+$' | \ + grep -vE '^src/(secp256k1/|univalue/|test/fuzz/FuzzedDataProvider.h)') + +if [[ ${OUTPUT} != "" ]]; then + echo "Use only lowercase alphanumerics (a-z0-9), underscores (_), hyphens (-) and dots (.)" + echo "in source code filenames:" + echo + echo "${OUTPUT}" + EXIT_CODE=1 +fi +exit ${EXIT_CODE} diff --git a/test/lint/lint-format-strings.py b/test/lint/lint-format-strings.py new file mode 100644 index 0000000000..2870432bff --- /dev/null +++ b/test/lint/lint-format-strings.py @@ -0,0 +1,293 @@ +#!/usr/bin/env python3 +# +# 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. +# +# Lint format strings: This program checks that the number of arguments passed +# to a variadic format string function matches the number of format specifiers +# in the format string. + +import argparse +import re +import sys + +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).translated, COPYRIGHT_HOLDERS_SUBSTITUTION)"), + ("src/validationinterface.cpp", "LogPrint(BCLog::VALIDATION, fmt \"\\n\", __VA_ARGS__)"), + ("src/wallet/wallet.h", "WalletLogPrintf(std::string fmt, Params... parameters)"), + ("src/wallet/wallet.h", "LogPrintf((\"%s \" + fmt).c_str(), GetDisplayName(), parameters...)"), + ("src/wallet/scriptpubkeyman.h", "WalletLogPrintf(std::string fmt, Params... parameters)"), + ("src/wallet/scriptpubkeyman.h", "LogPrintf((\"%s \" + fmt).c_str(), m_storage.GetDisplayName(), parameters...)"), + ("src/logging.h", "LogPrintf(const char* fmt, const Args&... args)"), + ("src/wallet/scriptpubkeyman.h", "WalletLogPrintf(const std::string& fmt, const Params&... parameters)"), +] + + +def parse_function_calls(function_name, source_code): + """Return an array with all calls to function function_name in string source_code. + Preprocessor directives and C++ style comments ("//") in source_code are removed. + + >>> len(parse_function_calls("foo", "foo();bar();foo();bar();")) + 2 + >>> parse_function_calls("foo", "foo(1);bar(1);foo(2);bar(2);")[0].startswith("foo(1);") + True + >>> parse_function_calls("foo", "foo(1);bar(1);foo(2);bar(2);")[1].startswith("foo(2);") + True + >>> len(parse_function_calls("foo", "foo();bar();// foo();bar();")) + 1 + >>> len(parse_function_calls("foo", "#define FOO foo();")) + 0 + """ + assert type(function_name) is str and type(source_code) is str and function_name + lines = [re.sub("// .*", " ", line).strip() + for line in source_code.split("\n") + if not line.strip().startswith("#")] + return re.findall(r"[^a-zA-Z_](?=({}\(.*).*)".format(function_name), " " + " ".join(lines)) + + +def normalize(s): + """Return a normalized version of string s with newlines, tabs and C style comments ("/* ... */") + replaced with spaces. Multiple spaces are replaced with a single space. + + >>> normalize(" /* nothing */ foo\tfoo /* bar */ foo ") + 'foo foo foo' + """ + assert type(s) is str + s = s.replace("\n", " ") + s = s.replace("\t", " ") + s = re.sub(r"/\*.*?\*/", " ", s) + s = re.sub(" {2,}", " ", s) + return s.strip() + + +ESCAPE_MAP = { + r"\n": "[escaped-newline]", + r"\t": "[escaped-tab]", + r'\"': "[escaped-quote]", +} + + +def escape(s): + """Return the escaped version of string s with "\\\"", "\\n" and "\\t" escaped as + "[escaped-backslash]", "[escaped-newline]" and "[escaped-tab]". + + >>> unescape(escape("foo")) == "foo" + True + >>> escape(r'foo \\t foo \\n foo \\\\ foo \\ foo \\"bar\\"') + 'foo [escaped-tab] foo [escaped-newline] foo \\\\\\\\ foo \\\\ foo [escaped-quote]bar[escaped-quote]' + """ + assert type(s) is str + for raw_value, escaped_value in ESCAPE_MAP.items(): + s = s.replace(raw_value, escaped_value) + return s + + +def unescape(s): + """Return the unescaped version of escaped string s. + Reverses the replacements made in function escape(s). + + >>> unescape(escape("bar")) + 'bar' + >>> unescape("foo [escaped-tab] foo [escaped-newline] foo \\\\\\\\ foo \\\\ foo [escaped-quote]bar[escaped-quote]") + 'foo \\\\t foo \\\\n foo \\\\\\\\ foo \\\\ foo \\\\"bar\\\\"' + """ + assert type(s) is str + for raw_value, escaped_value in ESCAPE_MAP.items(): + s = s.replace(escaped_value, raw_value) + return s + + +def parse_function_call_and_arguments(function_name, function_call): + """Split string function_call into an array of strings consisting of: + * the string function_call followed by "(" + * the function call argument #1 + * ... + * the function call argument #n + * a trailing ");" + + The strings returned are in escaped form. See escape(...). + + >>> parse_function_call_and_arguments("foo", 'foo("%s", "foo");') + ['foo(', '"%s",', ' "foo"', ')'] + >>> parse_function_call_and_arguments("foo", 'foo("%s", "foo");') + ['foo(', '"%s",', ' "foo"', ')'] + >>> parse_function_call_and_arguments("foo", 'foo("%s %s", "foo", "bar");') + ['foo(', '"%s %s",', ' "foo",', ' "bar"', ')'] + >>> parse_function_call_and_arguments("fooprintf", 'fooprintf("%050d", i);') + ['fooprintf(', '"%050d",', ' i', ')'] + >>> parse_function_call_and_arguments("foo", 'foo(bar(foobar(barfoo("foo"))), foobar); barfoo') + ['foo(', 'bar(foobar(barfoo("foo"))),', ' foobar', ')'] + >>> parse_function_call_and_arguments("foo", "foo()") + ['foo(', '', ')'] + >>> parse_function_call_and_arguments("foo", "foo(123)") + ['foo(', '123', ')'] + >>> parse_function_call_and_arguments("foo", 'foo("foo")') + ['foo(', '"foo"', ')'] + >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", std::wstring_convert,wchar_t>().to_bytes(buf), err);') + ['strprintf(', '"%s (%d)",', ' std::wstring_convert,wchar_t>().to_bytes(buf),', ' err', ')'] + >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo().to_bytes(buf), err);') + ['strprintf(', '"%s (%d)",', ' foo().to_bytes(buf),', ' err', ')'] + >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo().to_bytes(buf), err);') + ['strprintf(', '"%s (%d)",', ' foo().to_bytes(buf),', ' err', ')'] + >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo << 1, err);') + ['strprintf(', '"%s (%d)",', ' foo << 1,', ' err', ')'] + >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo() >> 1, err);') + ['strprintf(', '"%s (%d)",', ' foo() >> 1,', ' err', ')'] + >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo < 1 ? bar : foobar, err);') + ['strprintf(', '"%s (%d)",', ' foo < 1 ? bar : foobar,', ' err', ')'] + >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo < 1, err);') + ['strprintf(', '"%s (%d)",', ' foo < 1,', ' err', ')'] + >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo > 1 ? bar : foobar, err);') + ['strprintf(', '"%s (%d)",', ' foo > 1 ? bar : foobar,', ' err', ')'] + >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo > 1, err);') + ['strprintf(', '"%s (%d)",', ' foo > 1,', ' err', ')'] + >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo <= 1, err);') + ['strprintf(', '"%s (%d)",', ' foo <= 1,', ' err', ')'] + >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo <= bar<1, 2>(1, 2), err);') + ['strprintf(', '"%s (%d)",', ' foo <= bar<1, 2>(1, 2),', ' err', ')'] + >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo>foo<1,2>(1,2)?bar:foobar,err)'); + ['strprintf(', '"%s (%d)",', ' foo>foo<1,2>(1,2)?bar:foobar,', 'err', ')'] + >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo>foo<1,2>(1,2),err)'); + ['strprintf(', '"%s (%d)",', ' foo>foo<1,2>(1,2),', 'err', ')'] + """ + assert type(function_name) is str and type(function_call) is str and function_name + remaining = normalize(escape(function_call)) + expected_function_call = "{}(".format(function_name) + assert remaining.startswith(expected_function_call) + parts = [expected_function_call] + remaining = remaining[len(expected_function_call):] + open_parentheses = 1 + open_template_arguments = 0 + in_string = False + parts.append("") + for i, char in enumerate(remaining): + parts.append(parts.pop() + char) + if char == "\"": + in_string = not in_string + continue + if in_string: + continue + if char == "(": + open_parentheses += 1 + continue + if char == ")": + open_parentheses -= 1 + if open_parentheses > 1: + continue + if open_parentheses == 0: + parts.append(parts.pop()[:-1]) + parts.append(char) + break + prev_char = remaining[i - 1] if i - 1 >= 0 else None + next_char = remaining[i + 1] if i + 1 <= len(remaining) - 1 else None + if char == "<" and next_char not in [" ", "<", "="] and prev_char not in [" ", "<"]: + open_template_arguments += 1 + continue + if char == ">" and next_char not in [" ", ">", "="] and prev_char not in [" ", ">"] and open_template_arguments > 0: + open_template_arguments -= 1 + if open_template_arguments > 0: + continue + if char == ",": + parts.append("") + return parts + + +def parse_string_content(argument): + """Return the text within quotes in string argument. + + >>> parse_string_content('1 "foo %d bar" 2') + 'foo %d bar' + >>> parse_string_content('1 foobar 2') + '' + >>> parse_string_content('1 "bar" 2') + 'bar' + >>> parse_string_content('1 "foo" 2 "bar" 3') + 'foobar' + >>> parse_string_content('1 "foo" 2 " " "bar" 3') + 'foo bar' + >>> parse_string_content('""') + '' + >>> parse_string_content('') + '' + >>> parse_string_content('1 2 3') + '' + """ + assert type(argument) is str + string_content = "" + in_string = False + for char in normalize(escape(argument)): + if char == "\"": + in_string = not in_string + elif in_string: + string_content += char + return string_content + + +def count_format_specifiers(format_string): + """Return the number of format specifiers in string format_string. + + >>> count_format_specifiers("foo bar foo") + 0 + >>> count_format_specifiers("foo %d bar foo") + 1 + >>> count_format_specifiers("foo %d bar %i foo") + 2 + >>> count_format_specifiers("foo %d bar %i foo %% foo") + 2 + >>> count_format_specifiers("foo %d bar %i foo %% foo %d foo") + 3 + >>> count_format_specifiers("foo %d bar %i foo %% foo %*d foo") + 4 + """ + assert type(format_string) is str + format_string = format_string.replace('%%', 'X') + n = 0 + in_specifier = False + for i, char in enumerate(format_string): + if char == "%": + in_specifier = True + n += 1 + elif char in "aAcdeEfFgGinopsuxX": + in_specifier = False + elif in_specifier and char == "*": + n += 1 + return n + + +def main(): + parser = argparse.ArgumentParser(description="This program checks that the number of arguments passed " + "to a variadic format string function matches the number of format " + "specifiers in the format string.") + parser.add_argument("--skip-arguments", type=int, help="number of arguments before the format string " + "argument (e.g. 1 in the case of fprintf)", default=0) + parser.add_argument("function_name", help="function name (e.g. fprintf)", default=None) + parser.add_argument("file", nargs="*", help="C++ source code file (e.g. foo.cpp)") + args = parser.parse_args() + exit_code = 0 + for filename in args.file: + with open(filename, "r", encoding="utf-8") as f: + for function_call_str in parse_function_calls(args.function_name, f.read()): + parts = parse_function_call_and_arguments(args.function_name, function_call_str) + relevant_function_call_str = unescape("".join(parts))[:512] + if (f.name, relevant_function_call_str) in FALSE_POSITIVES: + continue + if len(parts) < 3 + args.skip_arguments: + exit_code = 1 + print("{}: Could not parse function call string \"{}(...)\": {}".format(f.name, args.function_name, relevant_function_call_str)) + continue + argument_count = len(parts) - 3 - args.skip_arguments + format_str = parse_string_content(parts[1 + args.skip_arguments]) + format_specifier_count = count_format_specifiers(format_str) + if format_specifier_count != argument_count: + exit_code = 1 + print("{}: Expected {} argument(s) after format string but found {} argument(s): {}".format(f.name, format_specifier_count, argument_count, relevant_function_call_str)) + continue + sys.exit(exit_code) + + +if __name__ == "__main__": + main() diff --git a/test/lint/lint-format-strings.sh b/test/lint/lint-format-strings.sh new file mode 100644 index 0000000000..cb3ec09ae6 --- /dev/null +++ b/test/lint/lint-format-strings.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2018-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. +# +# Lint format strings: This program checks that the number of arguments passed +# to a variadic format string function matches the number of format specifiers +# in the format string. + +export LC_ALL=C + +FUNCTION_NAMES_AND_NUMBER_OF_LEADING_ARGUMENTS=( + "FatalError,0" + "fprintf,1" + "tfm::format,1" # Assuming tfm::::format(std::ostream&, ... + "LogConnectFailure,1" + "LogPrint,1" + "LogPrintf,0" + "printf,0" + "snprintf,2" + "sprintf,1" + "strprintf,0" + "vfprintf,1" + "vprintf,1" + "vsnprintf,1" + "vsprintf,1" + "WalletLogPrintf,0" +) + +EXIT_CODE=0 +if ! python3 -m doctest test/lint/lint-format-strings.py; then + EXIT_CODE=1 +fi +for S in "${FUNCTION_NAMES_AND_NUMBER_OF_LEADING_ARGUMENTS[@]}"; do + IFS="," read -r FUNCTION_NAME SKIP_ARGUMENTS <<< "${S}" + for MATCHING_FILE in $(git grep --full-name -l "${FUNCTION_NAME}" -- "*.c" "*.cpp" "*.h" | sort | grep -vE "^src/(leveldb|secp256k1|tinyformat|univalue|test/fuzz/strprintf.cpp)"); do + MATCHING_FILES+=("${MATCHING_FILE}") + done + if ! test/lint/lint-format-strings.py --skip-arguments "${SKIP_ARGUMENTS}" "${FUNCTION_NAME}" "${MATCHING_FILES[@]}"; then + EXIT_CODE=1 + fi +done +exit ${EXIT_CODE} diff --git a/test/lint/lint-git-commit-check.sh b/test/lint/lint-git-commit-check.sh new file mode 100644 index 0000000000..8947f67bf6 --- /dev/null +++ b/test/lint/lint-git-commit-check.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +# 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. +# +# Linter to check that commit messages have a new line before the body +# or no body at all + +export LC_ALL=C + +EXIT_CODE=0 + +while getopts "?" opt; do + case $opt in + ?) + echo "Usage: $0 [N]" + echo " COMMIT_RANGE='' $0" + echo " $0 -?" + echo "Checks unmerged commits, the previous N commits, or a commit range." + echo "COMMIT_RANGE='47ba2c3...ee50c9e' $0" + exit ${EXIT_CODE} + ;; + esac +done + +if [ -z "${COMMIT_RANGE}" ]; then + if [ -n "$1" ]; then + COMMIT_RANGE="HEAD~$1...HEAD" + else + MERGE_BASE=$(git merge-base HEAD master) + COMMIT_RANGE="$MERGE_BASE..HEAD" + fi +fi + +while IFS= read -r commit_hash || [[ -n "$commit_hash" ]]; do + n_line=0 + while IFS= read -r line || [[ -n "$line" ]]; do + n_line=$((n_line+1)) + length=${#line} + if [ $n_line -eq 2 ] && [ $length -ne 0 ]; then + echo "The subject line of commit hash ${commit_hash} is followed by a non-empty line. Subject lines should always be followed by a blank line." + EXIT_CODE=1 + fi + done < <(git log --format=%B -n 1 "$commit_hash") +done < <(git log "${COMMIT_RANGE}" --format=%H) + +exit ${EXIT_CODE} diff --git a/test/lint/lint-include-guards.sh b/test/lint/lint-include-guards.sh new file mode 100644 index 0000000000..5d5a150db8 --- /dev/null +++ b/test/lint/lint-include-guards.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# +# 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. +# +# Check include guards. + +export LC_ALL=C +HEADER_ID_PREFIX="BITCOIN_" +HEADER_ID_SUFFIX="_H" + +REGEXP_EXCLUDE_FILES_WITH_PREFIX="src/(crypto/ctaes/|leveldb/|crc32c/|secp256k1/|test/fuzz/FuzzedDataProvider.h|tinyformat.h|bench/nanobench.h|univalue/)" + +EXIT_CODE=0 +for HEADER_FILE in $(git ls-files -- "*.h" | grep -vE "^${REGEXP_EXCLUDE_FILES_WITH_PREFIX}") +do + HEADER_ID_BASE=$(cut -f2- -d/ <<< "${HEADER_FILE}" | sed "s/\.h$//g" | tr / _ | tr "[:lower:]" "[:upper:]") + HEADER_ID="${HEADER_ID_PREFIX}${HEADER_ID_BASE}${HEADER_ID_SUFFIX}" + if [[ $(grep -cE "^#(ifndef|define) ${HEADER_ID}" "${HEADER_FILE}") != 2 ]]; then + echo "${HEADER_FILE} seems to be missing the expected include guard:" + echo " #ifndef ${HEADER_ID}" + echo " #define ${HEADER_ID}" + echo " ..." + echo " #endif // ${HEADER_ID}" + echo + EXIT_CODE=1 + fi +done +exit ${EXIT_CODE} diff --git a/test/lint/lint-includes.sh b/test/lint/lint-includes.sh new file mode 100644 index 0000000000..fde77aea2d --- /dev/null +++ b/test/lint/lint-includes.sh @@ -0,0 +1,114 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2018-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. +# +# Check for duplicate includes. +# Guard against accidental introduction of new Boost dependencies. +# Check includes: Check for duplicate includes. Enforce bracket syntax includes. + +export LC_ALL=C +IGNORE_REGEXP="/(leveldb|secp256k1|univalue|crc32c)/" + +# cd to root folder of git repo for git ls-files to work properly +cd "$(dirname $0)/../.." || exit 1 + +filter_suffix() { + git ls-files | grep -E "^src/.*\.${1}"'$' | grep -Ev "${IGNORE_REGEXP}" +} + +EXIT_CODE=0 + +for HEADER_FILE in $(filter_suffix h); do + DUPLICATE_INCLUDES_IN_HEADER_FILE=$(grep -E "^#include " < "${HEADER_FILE}" | sort | uniq -d) + if [[ ${DUPLICATE_INCLUDES_IN_HEADER_FILE} != "" ]]; then + echo "Duplicate include(s) in ${HEADER_FILE}:" + echo "${DUPLICATE_INCLUDES_IN_HEADER_FILE}" + echo + EXIT_CODE=1 + fi +done + +for CPP_FILE in $(filter_suffix cpp); do + DUPLICATE_INCLUDES_IN_CPP_FILE=$(grep -E "^#include " < "${CPP_FILE}" | sort | uniq -d) + if [[ ${DUPLICATE_INCLUDES_IN_CPP_FILE} != "" ]]; then + echo "Duplicate include(s) in ${CPP_FILE}:" + echo "${DUPLICATE_INCLUDES_IN_CPP_FILE}" + echo + EXIT_CODE=1 + fi +done + +INCLUDED_CPP_FILES=$(git grep -E "^#include [<\"][^>\"]+\.cpp[>\"]" -- "*.cpp" "*.h") +if [[ ${INCLUDED_CPP_FILES} != "" ]]; then + echo "The following files #include .cpp files:" + echo "${INCLUDED_CPP_FILES}" + echo + EXIT_CODE=1 +fi + +EXPECTED_BOOST_INCLUDES=( + boost/algorithm/string.hpp + boost/algorithm/string/classification.hpp + boost/algorithm/string/replace.hpp + boost/algorithm/string/split.hpp + boost/date_time/posix_time/posix_time.hpp + boost/filesystem.hpp + boost/filesystem/fstream.hpp + boost/multi_index/hashed_index.hpp + boost/multi_index/ordered_index.hpp + boost/multi_index/sequenced_index.hpp + boost/multi_index_container.hpp + boost/optional.hpp + boost/preprocessor/cat.hpp + boost/preprocessor/stringize.hpp + boost/process.hpp + boost/signals2/connection.hpp + boost/signals2/optional_last_value.hpp + boost/signals2/signal.hpp + boost/test/unit_test.hpp + boost/thread/condition_variable.hpp + boost/thread/mutex.hpp + boost/thread/shared_mutex.hpp + boost/thread/thread.hpp + boost/variant.hpp + boost/variant/apply_visitor.hpp + boost/variant/static_visitor.hpp +) + +for BOOST_INCLUDE in $(git grep '^#include ' | sort -u); do + IS_EXPECTED_INCLUDE=0 + for EXPECTED_BOOST_INCLUDE in "${EXPECTED_BOOST_INCLUDES[@]}"; do + if [[ "${BOOST_INCLUDE}" == "${EXPECTED_BOOST_INCLUDE}" ]]; then + IS_EXPECTED_INCLUDE=1 + break + fi + done + if [[ ${IS_EXPECTED_INCLUDE} == 0 ]]; then + EXIT_CODE=1 + echo "A new Boost dependency in the form of \"${BOOST_INCLUDE}\" appears to have been introduced:" + git grep "${BOOST_INCLUDE}" -- "*.cpp" "*.h" + echo + fi +done + +for EXPECTED_BOOST_INCLUDE in "${EXPECTED_BOOST_INCLUDES[@]}"; do + if ! git grep -q "^#include <${EXPECTED_BOOST_INCLUDE}>" -- "*.cpp" "*.h"; then + echo "Good job! The Boost dependency \"${EXPECTED_BOOST_INCLUDE}\" is no longer used." + echo "Please remove it from EXPECTED_BOOST_INCLUDES in $0" + echo "to make sure this dependency is not accidentally reintroduced." + echo + EXIT_CODE=1 + fi +done + +QUOTE_SYNTAX_INCLUDES=$(git grep '^#include "' -- "*.cpp" "*.h" | grep -Ev "${IGNORE_REGEXP}") +if [[ ${QUOTE_SYNTAX_INCLUDES} != "" ]]; then + echo "Please use bracket syntax includes (\"#include \") instead of quote syntax includes:" + echo "${QUOTE_SYNTAX_INCLUDES}" + echo + EXIT_CODE=1 +fi + +exit ${EXIT_CODE} diff --git a/test/lint/lint-locale-dependence.sh b/test/lint/lint-locale-dependence.sh new file mode 100644 index 0000000000..2e5b801849 --- /dev/null +++ b/test/lint/lint-locale-dependence.sh @@ -0,0 +1,220 @@ +#!/usr/bin/env bash +# Copyright (c) 2018-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. + +export LC_ALL=C +KNOWN_VIOLATIONS=( + "src/bitcoin-tx.cpp.*stoul" + "src/bitcoin-tx.cpp.*trim_right" + "src/dbwrapper.cpp.*stoul" + "src/dbwrapper.cpp:.*vsnprintf" + "src/httprpc.cpp.*trim" + "src/init.cpp:.*atoi" + "src/qt/rpcconsole.cpp:.*atoi" + "src/rest.cpp:.*strtol" + "src/test/dbwrapper_tests.cpp:.*snprintf" + "src/test/fuzz/locale.cpp" + "src/test/fuzz/parse_numbers.cpp:.*atoi" + "src/torcontrol.cpp:.*atoi" + "src/torcontrol.cpp:.*strtol" + "src/util/strencodings.cpp:.*atoi" + "src/util/strencodings.cpp:.*strtol" + "src/util/strencodings.cpp:.*strtoul" + "src/util/strencodings.h:.*atoi" + "src/util/system.cpp:.*atoi" +) + +REGEXP_IGNORE_EXTERNAL_DEPENDENCIES="^src/(crypto/ctaes/|leveldb/|secp256k1/|tinyformat.h|univalue/)" + +LOCALE_DEPENDENT_FUNCTIONS=( + alphasort # LC_COLLATE (via strcoll) + asctime # LC_TIME (directly) + asprintf # (via vasprintf) + atof # LC_NUMERIC (via strtod) + atoi # LC_NUMERIC (via strtol) + atol # LC_NUMERIC (via strtol) + atoll # (via strtoll) + atoq + btowc # LC_CTYPE (directly) + ctime # (via asctime or localtime) + dprintf # (via vdprintf) + fgetwc + fgetws + fold_case # boost::locale::fold_case + fprintf # (via vfprintf) + fputwc + fputws + fscanf # (via __vfscanf) + fwprintf # (via __vfwprintf) + getdate # via __getdate_r => isspace // __localtime_r + getwc + getwchar + is_digit # boost::algorithm::is_digit + is_space # boost::algorithm::is_space + isalnum # LC_CTYPE + isalpha # LC_CTYPE + isblank # LC_CTYPE + iscntrl # LC_CTYPE + isctype # LC_CTYPE + isdigit # LC_CTYPE + isgraph # LC_CTYPE + islower # LC_CTYPE + isprint # LC_CTYPE + ispunct # LC_CTYPE + isspace # LC_CTYPE + isupper # LC_CTYPE + iswalnum # LC_CTYPE + iswalpha # LC_CTYPE + iswblank # LC_CTYPE + iswcntrl # LC_CTYPE + iswctype # LC_CTYPE + iswdigit # LC_CTYPE + iswgraph # LC_CTYPE + iswlower # LC_CTYPE + iswprint # LC_CTYPE + iswpunct # LC_CTYPE + iswspace # LC_CTYPE + iswupper # LC_CTYPE + iswxdigit # LC_CTYPE + isxdigit # LC_CTYPE + localeconv # LC_NUMERIC + LC_MONETARY + mblen # LC_CTYPE + mbrlen + mbrtowc + mbsinit + mbsnrtowcs + mbsrtowcs + mbstowcs # LC_CTYPE + mbtowc # LC_CTYPE + mktime + normalize # boost::locale::normalize + printf # LC_NUMERIC + putwc + putwchar + scanf # LC_NUMERIC + setlocale + snprintf + sprintf + sscanf + std::locale::global + std::to_string + stod + stof + stoi + stol + stold + stoll + stoul + stoull + strcasecmp + strcasestr + strcoll # LC_COLLATE +# strerror + strfmon + strftime # LC_TIME + strncasecmp + strptime + strtod # LC_NUMERIC + strtof + strtoimax + strtol # LC_NUMERIC + strtold + strtoll + strtoq + strtoul # LC_NUMERIC + strtoull + strtoumax + strtouq + strxfrm # LC_COLLATE + swprintf + to_lower # boost::locale::to_lower + to_title # boost::locale::to_title + to_upper # boost::locale::to_upper + tolower # LC_CTYPE + toupper # LC_CTYPE + towctrans + towlower # LC_CTYPE + towupper # LC_CTYPE + trim # boost::algorithm::trim + trim_left # boost::algorithm::trim_left + trim_right # boost::algorithm::trim_right + ungetwc + vasprintf + vdprintf + versionsort + vfprintf + vfscanf + vfwprintf + vprintf + vscanf + vsnprintf + vsprintf + vsscanf + vswprintf + vwprintf + wcrtomb + wcscasecmp + wcscoll # LC_COLLATE + wcsftime # LC_TIME + wcsncasecmp + wcsnrtombs + wcsrtombs + wcstod # LC_NUMERIC + wcstof + wcstoimax + wcstol # LC_NUMERIC + wcstold + wcstoll + wcstombs # LC_CTYPE + wcstoul # LC_NUMERIC + wcstoull + wcstoumax + wcswidth + wcsxfrm # LC_COLLATE + wctob + wctomb # LC_CTYPE + wctrans + wctype + wcwidth + wprintf +) + +function join_array { + local IFS="$1" + shift + echo "$*" +} + +REGEXP_IGNORE_KNOWN_VIOLATIONS=$(join_array "|" "${KNOWN_VIOLATIONS[@]}") + +# Invoke "git grep" only once in order to minimize run-time +REGEXP_LOCALE_DEPENDENT_FUNCTIONS=$(join_array "|" "${LOCALE_DEPENDENT_FUNCTIONS[@]}") +GIT_GREP_OUTPUT=$(git grep -E "[^a-zA-Z0-9_\`'\"<>](${REGEXP_LOCALE_DEPENDENT_FUNCTIONS}(_r|_s)?)[^a-zA-Z0-9_\`'\"<>]" -- "*.cpp" "*.h") + +EXIT_CODE=0 +for LOCALE_DEPENDENT_FUNCTION in "${LOCALE_DEPENDENT_FUNCTIONS[@]}"; do + MATCHES=$(grep -E "[^a-zA-Z0-9_\`'\"<>]${LOCALE_DEPENDENT_FUNCTION}(_r|_s)?[^a-zA-Z0-9_\`'\"<>]" <<< "${GIT_GREP_OUTPUT}" | \ + grep -vE "\.(c|cpp|h):\s*(//|\*|/\*|\").*${LOCALE_DEPENDENT_FUNCTION}") + if [[ ${REGEXP_IGNORE_EXTERNAL_DEPENDENCIES} != "" ]]; then + MATCHES=$(grep -vE "${REGEXP_IGNORE_EXTERNAL_DEPENDENCIES}" <<< "${MATCHES}") + fi + if [[ ${REGEXP_IGNORE_KNOWN_VIOLATIONS} != "" ]]; then + MATCHES=$(grep -vE "${REGEXP_IGNORE_KNOWN_VIOLATIONS}" <<< "${MATCHES}") + fi + if [[ ${MATCHES} != "" ]]; then + echo "The locale dependent function ${LOCALE_DEPENDENT_FUNCTION}(...) appears to be used:" + echo "${MATCHES}" + echo + EXIT_CODE=1 + fi +done +if [[ ${EXIT_CODE} != 0 ]]; then + echo "Unnecessary locale dependence can cause bugs that are very" + echo "tricky to isolate and fix. Please avoid using locale dependent" + echo "functions if possible." + echo + echo "Advice not applicable in this specific case? Add an exception" + echo "by updating the ignore list in $0" +fi +exit ${EXIT_CODE} diff --git a/test/lint/lint-logs.sh b/test/lint/lint-logs.sh new file mode 100644 index 0000000000..2fbb4a38e7 --- /dev/null +++ b/test/lint/lint-logs.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# +# 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. +# +# Check that all logs are terminated with '\n' +# +# Some logs are continued over multiple lines. They should be explicitly +# commented with \* Continued *\ +# +# There are some instances of LogPrintf() in comments. Those can be +# ignored + +export LC_ALL=C +UNTERMINATED_LOGS=$(git grep --extended-regexp "LogPrintf?\(" -- "*.cpp" | \ + grep -v '\\n"' | \ + grep -v '\.\.\.' | \ + grep -v "/\* Continued \*/" | \ + 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}" + exit 1 +fi diff --git a/test/lint/lint-python-mutable-default-parameters.sh b/test/lint/lint-python-mutable-default-parameters.sh new file mode 100644 index 0000000000..1f9f035d30 --- /dev/null +++ b/test/lint/lint-python-mutable-default-parameters.sh @@ -0,0 +1,52 @@ +#!/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. +# +# Detect when a mutable list or dict is used as a default parameter value in a Python function. + +export LC_ALL=C +EXIT_CODE=0 +OUTPUT=$(git grep -E '^\s*def [a-zA-Z0-9_]+\(.*=\s*(\[|\{)' -- "*.py") +if [[ ${OUTPUT} != "" ]]; then + echo "A mutable list or dict seems to be used as default parameter value:" + echo + echo "${OUTPUT}" + echo + cat << EXAMPLE +This is how mutable list and dict default parameter values behave: + +>>> def f(i, j=[], k={}): +... j.append(i) +... k[i] = True +... return j, k +... +>>> f(1) +([1], {1: True}) +>>> f(1) +([1, 1], {1: True}) +>>> f(2) +([1, 1, 2], {1: True, 2: True}) + +The intended behaviour was likely: + +>>> def f(i, j=None, k=None): +... if j is None: +... j = [] +... if k is None: +... k = {} +... j.append(i) +... k[i] = True +... return j, k +... +>>> f(1) +([1], {1: True}) +>>> f(1) +([1], {1: True}) +>>> f(2) +([2], {2: True}) +EXAMPLE + EXIT_CODE=1 +fi +exit ${EXIT_CODE} diff --git a/test/lint/lint-python-utf8-encoding.sh b/test/lint/lint-python-utf8-encoding.sh new file mode 100644 index 0000000000..7257919c98 --- /dev/null +++ b/test/lint/lint-python-utf8-encoding.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# +# 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. +# +# Make sure we explicitly open all text files using UTF-8 (or ASCII) encoding to +# avoid potential issues on the BSDs where the locale is not always set. + +export LC_ALL=C +EXIT_CODE=0 +OUTPUT=$(git grep " open(" -- "*.py" ":(exclude)src/crc32c/" | grep -vE "encoding=.(ascii|utf8|utf-8)." | grep -vE "open\([^,]*, ['\"][^'\"]*b[^'\"]*['\"]") +if [[ ${OUTPUT} != "" ]]; then + echo "Python's open(...) seems to be used to open text files without explicitly" + echo "specifying encoding=\"utf8\":" + echo + echo "${OUTPUT}" + EXIT_CODE=1 +fi +OUTPUT=$(git grep "check_output(" -- "*.py" ":(exclude)src/crc32c/"| grep "universal_newlines=True" | grep -vE "encoding=.(ascii|utf8|utf-8).") +if [[ ${OUTPUT} != "" ]]; then + echo "Python's check_output(...) seems to be used to get program outputs without explicitly" + echo "specifying encoding=\"utf8\":" + echo + echo "${OUTPUT}" + EXIT_CODE=1 +fi +exit ${EXIT_CODE} diff --git a/test/lint/lint-python.sh b/test/lint/lint-python.sh new file mode 100644 index 0000000000..72e8ef7c7d --- /dev/null +++ b/test/lint/lint-python.sh @@ -0,0 +1,108 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2017-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. +# +# Check for specified flake8 warnings in python files. + +export LC_ALL=C +export MYPY_CACHE_DIR="${BASE_ROOT_DIR}/test/.mypy_cache" + +enabled=( + E101 # indentation contains mixed spaces and tabs + E112 # expected an indented block + E113 # unexpected indentation + E115 # expected an indented block (comment) + E116 # unexpected indentation (comment) + E125 # continuation line with same indent as next logical line + E129 # visually indented line with same indent as next logical line + E131 # continuation line unaligned for hanging indent + E133 # closing bracket is missing indentation + E223 # tab before operator + E224 # tab after operator + E242 # tab after ',' + E266 # too many leading '#' for block comment + E271 # multiple spaces after keyword + E272 # multiple spaces before keyword + E273 # tab after keyword + E274 # tab before keyword + E275 # missing whitespace after keyword + E304 # blank lines found after function decorator + E306 # expected 1 blank line before a nested definition + E401 # multiple imports on one line + E402 # module level import not at top of file + E502 # the backslash is redundant between brackets + E701 # multiple statements on one line (colon) + E702 # multiple statements on one line (semicolon) + E703 # statement ends with a semicolon + E711 # comparison to None should be 'if cond is None:' + E714 # test for object identity should be "is not" + E721 # do not compare types, use "isinstance()" + E742 # do not define classes named "l", "O", or "I" + E743 # do not define functions named "l", "O", or "I" + E901 # SyntaxError: invalid syntax + E902 # TokenError: EOF in multi-line string + F401 # module imported but unused + F402 # import module from line N shadowed by loop variable + F403 # 'from foo_module import *' used; unable to detect undefined names + F404 # future import(s) name after other statements + F405 # foo_function may be undefined, or defined from star imports: bar_module + F406 # "from module import *" only allowed at module level + F407 # an undefined __future__ feature name was imported + F601 # dictionary key name repeated with different values + F602 # dictionary key variable name repeated with different values + F621 # too many expressions in an assignment with star-unpacking + F622 # two or more starred expressions in an assignment (a, *b, *c = d) + F631 # assertion test is a tuple, which are always True + F701 # a break statement outside of a while or for loop + F702 # a continue statement outside of a while or for loop + F703 # a continue statement in a finally block in a loop + F704 # a yield or yield from statement outside of a function + F705 # a return statement with arguments inside a generator + F706 # a return statement outside of a function/method + F707 # an except: block as not the last exception handler + F811 # redefinition of unused name from line N + F812 # list comprehension redefines 'foo' from line N + F821 # undefined name 'Foo' + F822 # undefined name name in __all__ + F823 # local variable name … referenced before assignment + F831 # duplicate argument name in function definition + F841 # local variable 'foo' is assigned to but never used + W191 # indentation contains tabs + W291 # trailing whitespace + W292 # no newline at end of file + W293 # blank line contains whitespace + W601 # .has_key() is deprecated, use "in" + W602 # deprecated form of raising exception + W603 # "<>" is deprecated, use "!=" + W604 # backticks are deprecated, use "repr()" + W605 # invalid escape sequence "x" + W606 # 'async' and 'await' are reserved keywords starting with Python 3.7 +) + +if ! command -v flake8 > /dev/null; then + echo "Skipping Python linting since flake8 is not installed." + exit 0 +elif PYTHONWARNINGS="ignore" flake8 --version | grep -q "Python 2"; then + echo "Skipping Python linting since flake8 is running under Python 2. Install the Python 3 version of flake8." + exit 0 +fi + +EXIT_CODE=0 + +if ! PYTHONWARNINGS="ignore" flake8 --ignore=B,C,E,F,I,N,W --select=$(IFS=","; echo "${enabled[*]}") $( + if [[ $# == 0 ]]; then + git ls-files "*.py" + else + echo "$@" + fi +); then + EXIT_CODE=1 +fi + +if ! mypy --ignore-missing-imports $(git ls-files "test/functional/*.py"); then + EXIT_CODE=1 +fi + +exit $EXIT_CODE diff --git a/test/lint/lint-qt.sh b/test/lint/lint-qt.sh new file mode 100644 index 0000000000..2e77682aa2 --- /dev/null +++ b/test/lint/lint-qt.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# +# Check for SIGNAL/SLOT connect style, removed since Qt4 support drop. + +export LC_ALL=C + +EXIT_CODE=0 + +OUTPUT=$(git grep -E '(SIGNAL|, ?SLOT)\(' -- src/qt) +if [[ ${OUTPUT} != "" ]]; then + echo "Use Qt5 connect style in:" + echo "$OUTPUT" + EXIT_CODE=1 +fi + +exit ${EXIT_CODE} diff --git a/test/lint/lint-rpc-help.sh b/test/lint/lint-rpc-help.sh new file mode 100644 index 0000000000..faac5d43e2 --- /dev/null +++ b/test/lint/lint-rpc-help.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# +# Check that all RPC help texts are generated by RPCHelpMan. + +export LC_ALL=C + +EXIT_CODE=0 + +# Assume that all multiline strings passed into a runtime_error are help texts. +# This is potentially fragile, but the linter is only temporary and can safely +# be removed early 2019. + +non_autogenerated_help=$(grep --perl-regexp --null-data --only-matching 'runtime_error\(\n\s*".*\\n"\n' $(git ls-files -- "*.cpp")) +if [[ ${non_autogenerated_help} != "" ]]; then + echo "Must use RPCHelpMan to generate the help for the following RPC methods:" + echo "${non_autogenerated_help}" + echo + EXIT_CODE=1 +fi +exit ${EXIT_CODE} diff --git a/test/lint/lint-shebang.sh b/test/lint/lint-shebang.sh new file mode 100644 index 0000000000..a5c8aa42b2 --- /dev/null +++ b/test/lint/lint-shebang.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# 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. + +# Assert expected shebang lines + +export LC_ALL=C +EXIT_CODE=0 +for PYTHON_FILE in $(git ls-files -- "*.py"); do + if [[ $(head -c 2 "${PYTHON_FILE}") == "#!" && + $(head -n 1 "${PYTHON_FILE}") != "#!/usr/bin/env python3" ]]; then + echo "Missing shebang \"#!/usr/bin/env python3\" in ${PYTHON_FILE} (do not use python or python2)" + EXIT_CODE=1 + fi +done +for SHELL_FILE in $(git ls-files -- "*.sh"); do + if [[ $(head -n 1 "${SHELL_FILE}") != "#!/usr/bin/env bash" && + $(head -n 1 "${SHELL_FILE}") != "#!/bin/sh" ]]; then + echo "Missing expected shebang \"#!/usr/bin/env bash\" or \"#!/bin/sh\" in ${SHELL_FILE}" + EXIT_CODE=1 + fi +done +exit ${EXIT_CODE} diff --git a/test/lint/lint-shell-locale.sh b/test/lint/lint-shell-locale.sh new file mode 100644 index 0000000000..084dc93f76 --- /dev/null +++ b/test/lint/lint-shell-locale.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# +# Make sure all shell scripts: +# a.) explicitly opt out of locale dependence using +# "export LC_ALL=C" or "export LC_ALL=C.UTF-8", or +# b.) explicitly opt in to locale dependence using the annotation below. + +export LC_ALL=C + +EXIT_CODE=0 +for SHELL_SCRIPT in $(git ls-files -- "*.sh" | grep -vE "src/(secp256k1|univalue)/"); do + if grep -q "# This script is intentionally locale dependent by not setting \"export LC_ALL=C\"" "${SHELL_SCRIPT}"; then + continue + fi + FIRST_NON_COMMENT_LINE=$(grep -vE '^(#.*)?$' "${SHELL_SCRIPT}" | head -1) + if [[ ${FIRST_NON_COMMENT_LINE} != "export LC_ALL=C" && ${FIRST_NON_COMMENT_LINE} != "export LC_ALL=C.UTF-8" ]]; then + echo "Missing \"export LC_ALL=C\" (to avoid locale dependence) as first non-comment non-empty line in ${SHELL_SCRIPT}" + EXIT_CODE=1 + fi +done +exit ${EXIT_CODE} diff --git a/test/lint/lint-shell.sh b/test/lint/lint-shell.sh new file mode 100644 index 0000000000..9a26cd9c02 --- /dev/null +++ b/test/lint/lint-shell.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2018-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. +# +# Check for shellcheck warnings in shell scripts. + +export LC_ALL=C + +# The shellcheck binary segfault/coredumps in Travis with LC_ALL=C +# It does not do so in Ubuntu 14.04, 16.04, 18.04 in versions 0.3.3, 0.3.7, 0.4.6 +# respectively. So export LC_ALL=C is set as required by lint-shell-locale.sh +# but unset here in case of running in Travis. +if [ "$TRAVIS" = "true" ]; then + unset LC_ALL +fi + +# Disabled warnings: +disabled=( + SC2046 # Quote this to prevent word splitting. + SC2086 # Double quote to prevent globbing and word splitting. + SC2162 # read without -r will mangle backslashes. +) +disabled_gitian=( + SC2094 # Make sure not to read and write the same file in the same pipeline. + SC2129 # Consider using { cmd1; cmd2; } >> file instead of individual redirects. +) + +EXIT_CODE=0 + +if ! command -v shellcheck > /dev/null; then + echo "Skipping shell linting since shellcheck is not installed." + exit $EXIT_CODE +fi + +SHELLCHECK_CMD=(shellcheck --external-sources --check-sourced) +EXCLUDE="--exclude=$(IFS=','; echo "${disabled[*]}")" +if ! "${SHELLCHECK_CMD[@]}" "$EXCLUDE" $(git ls-files -- '*.sh' | grep -vE 'src/(leveldb|secp256k1|univalue)/'); then + EXIT_CODE=1 +fi + +if ! command -v yq > /dev/null; then + echo "Skipping Gitian descriptor scripts checking since yq is not installed." + exit $EXIT_CODE +fi + +EXCLUDE_GITIAN=${EXCLUDE}",$(IFS=','; echo "${disabled_gitian[*]}")" +for descriptor in $(git ls-files -- 'contrib/gitian-descriptors/*.yml') +do + script=$(basename "$descriptor") + # Use #!/bin/bash as gitian-builder/bin/gbuild does to complete a script. + echo "#!/bin/bash" > $script + yq -r .script "$descriptor" >> $script + if ! "${SHELLCHECK_CMD[@]}" "$EXCLUDE_GITIAN" $script; then + EXIT_CODE=1 + fi + rm $script +done + +exit $EXIT_CODE diff --git a/test/lint/lint-spelling.ignore-words.txt b/test/lint/lint-spelling.ignore-words.txt new file mode 100644 index 0000000000..34f54325b3 --- /dev/null +++ b/test/lint/lint-spelling.ignore-words.txt @@ -0,0 +1,17 @@ +hights +mor +mut +objext +useable +wit +unparseable +copyable +cachable +errorstring +keyserver +homogenous +setban +hist +ser +unselect +lowercased diff --git a/test/lint/lint-spelling.sh b/test/lint/lint-spelling.sh new file mode 100644 index 0000000000..cb84727ba5 --- /dev/null +++ b/test/lint/lint-spelling.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# +# 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. +# +# Warn in case of spelling errors. +# Note: Will exit successfully regardless of spelling errors. + +export LC_ALL=C + +if ! command -v codespell > /dev/null; then + echo "Skipping spell check linting since codespell is not installed." + exit 0 +fi + +IGNORE_WORDS_FILE=test/lint/lint-spelling.ignore-words.txt +if ! codespell --check-filenames --disable-colors --quiet-level=7 --ignore-words=${IGNORE_WORDS_FILE} $(git ls-files -- ":(exclude)build-aux/m4/" ":(exclude)contrib/seeds/*.txt" ":(exclude)depends/" ":(exclude)doc/release-notes/" ":(exclude)src/leveldb/" ":(exclude)src/crc32c/" ":(exclude)src/qt/locale/" ":(exclude)src/qt/*.qrc" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/"); then + echo "^ Warning: codespell identified likely spelling errors. Any false positives? Add them to the list of ignored words in ${IGNORE_WORDS_FILE}" +fi diff --git a/test/lint/lint-submodule.sh b/test/lint/lint-submodule.sh new file mode 100644 index 0000000000..d9aa021df7 --- /dev/null +++ b/test/lint/lint-submodule.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# +# 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. +# +# This script checks for git modules +export LC_ALL=C +EXIT_CODE=0 + +CMD=$(git submodule status --recursive) +if test -n "$CMD"; +then + echo These submodules were found, delete them: + echo "$CMD" + EXIT_CODE=1 +fi + +exit $EXIT_CODE + diff --git a/test/lint/lint-tests.sh b/test/lint/lint-tests.sh new file mode 100644 index 0000000000..35d11023eb --- /dev/null +++ b/test/lint/lint-tests.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# +# Check the test suite naming conventions + +export LC_ALL=C +EXIT_CODE=0 + +NAMING_INCONSISTENCIES=$(git grep -E '^BOOST_FIXTURE_TEST_SUITE\(' -- \ + "src/test/**.cpp" "src/wallet/test/**.cpp" | \ + grep -vE '/(.*?)\.cpp:BOOST_FIXTURE_TEST_SUITE\(\1, .*\)$') +if [[ ${NAMING_INCONSISTENCIES} != "" ]]; then + echo "The test suite in file src/test/foo_tests.cpp should be named" + echo "\"foo_tests\". Please make sure the following test suites follow" + echo "that convention:" + echo + echo "${NAMING_INCONSISTENCIES}" + EXIT_CODE=1 +fi + +TEST_SUITE_NAME_COLLISSIONS=$(git grep -E '^BOOST_FIXTURE_TEST_SUITE\(' -- \ + "src/test/**.cpp" "src/wallet/test/**.cpp" | cut -f2 -d'(' | cut -f1 -d, | \ + sort | uniq -d) +if [[ ${TEST_SUITE_NAME_COLLISSIONS} != "" ]]; then + echo "Test suite names must be unique. The following test suite names" + echo "appear to be used more than once:" + echo + echo "${TEST_SUITE_NAME_COLLISSIONS}" + EXIT_CODE=1 +fi + +exit ${EXIT_CODE} diff --git a/test/lint/lint-whitespace.sh b/test/lint/lint-whitespace.sh new file mode 100644 index 0000000000..d8bdb0a8d7 --- /dev/null +++ b/test/lint/lint-whitespace.sh @@ -0,0 +1,113 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2017-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. +# +# Check for new lines in diff that introduce trailing whitespace. + +# We can't run this check unless we know the commit range for the PR. + +export LC_ALL=C +while getopts "?" opt; do + case $opt in + ?) + echo "Usage: $0 [N]" + echo " TRAVIS_COMMIT_RANGE='' $0" + echo " $0 -?" + echo "Checks unstaged changes, the previous N commits, or a commit range." + echo "TRAVIS_COMMIT_RANGE='47ba2c3...ee50c9e' $0" + exit 0 + ;; + esac +done + +if [ -z "${TRAVIS_COMMIT_RANGE}" ]; then + if [ -n "$1" ]; then + TRAVIS_COMMIT_RANGE="HEAD~$1...HEAD" + else + TRAVIS_COMMIT_RANGE="HEAD" + fi +fi + +showdiff() { + if ! git diff -U0 "${TRAVIS_COMMIT_RANGE}" -- "." ":(exclude)depends/patches/" ":(exclude)src/leveldb/" ":(exclude)src/crc32c/" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/" ":(exclude)doc/release-notes/" ":(exclude)src/qt/locale/"; then + echo "Failed to get a diff" + exit 1 + fi +} + +showcodediff() { + if ! git diff -U0 "${TRAVIS_COMMIT_RANGE}" -- *.cpp *.h *.md *.py *.sh ":(exclude)src/leveldb/" ":(exclude)src/crc32c/" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/" ":(exclude)doc/release-notes/" ":(exclude)src/qt/locale/"; then + echo "Failed to get a diff" + exit 1 + fi +} + +RET=0 + +# Check if trailing whitespace was found in the diff. +if showdiff | grep -E -q '^\+.*\s+$'; then + echo "This diff appears to have added new lines with trailing whitespace." + echo "The following changes were suspected:" + FILENAME="" + SEEN=0 + SEENLN=0 + while read -r line; do + if [[ "$line" =~ ^diff ]]; then + FILENAME="$line" + SEEN=0 + elif [[ "$line" =~ ^@@ ]]; then + LINENUMBER="$line" + SEENLN=0 + else + if [ "$SEEN" -eq 0 ]; then + # The first time a file is seen with trailing whitespace, we print the + # filename (preceded by a newline). + echo + echo "$FILENAME" + SEEN=1 + fi + if [ "$SEENLN" -eq 0 ]; then + echo "$LINENUMBER" + SEENLN=1 + fi + echo "$line" + fi + done < <(showdiff | grep -E '^(diff --git |@@|\+.*\s+$)') + RET=1 +fi + +# Check if tab characters were found in the diff. +if showcodediff | perl -nle '$MATCH++ if m{^\+.*\t}; END{exit 1 unless $MATCH>0}' > /dev/null; then + echo "This diff appears to have added new lines with tab characters instead of spaces." + echo "The following changes were suspected:" + FILENAME="" + SEEN=0 + SEENLN=0 + while read -r line; do + if [[ "$line" =~ ^diff ]]; then + FILENAME="$line" + SEEN=0 + elif [[ "$line" =~ ^@@ ]]; then + LINENUMBER="$line" + SEENLN=0 + else + if [ "$SEEN" -eq 0 ]; then + # The first time a file is seen with a tab character, we print the + # filename (preceded by a newline). + echo + echo "$FILENAME" + SEEN=1 + fi + if [ "$SEENLN" -eq 0 ]; then + echo "$LINENUMBER" + SEENLN=1 + fi + echo "$line" + fi + done < <(showcodediff | perl -nle 'print if m{^(diff --git |@@|\+.*\t)}') + RET=1 +fi + +exit $RET From 02e58719a82d8699e0eb7dfd0f334a3a9737ec80 Mon Sep 17 00:00:00 2001 From: div72 <60045611+div72@users.noreply.github.com> Date: Wed, 12 Aug 2020 12:04:35 +0300 Subject: [PATCH 02/16] Enable lint job in Travis --- .travis.yml | 13 +++++++++++++ ci/lint/04_install.sh | 0 ci/lint/05_before_script.sh | 0 ci/lint/06_script.sh | 0 ci/test/00_setup_env.sh | 0 ci/test/00_setup_env_arm.sh | 0 ci/test/00_setup_env_linux_i386.sh | 0 ci/test/00_setup_env_mac.sh | 0 ci/test/00_setup_env_mac_host.sh | 0 ci/test/00_setup_env_native.sh | 0 ci/test/00_setup_env_win32.sh | 0 ci/test/00_setup_env_win64.sh | 0 ci/test/03_before_install.sh | 0 ci/test/04_install.sh | 0 ci/test/05_before_script.sh | 0 ci/test/06_script_a.sh | 0 ci/test/06_script_b.sh | 0 ci/test_run_all.sh | 0 contrib/bitrpc/bitrpc.py | 0 contrib/devtools/circular-dependencies.py | 0 contrib/devtools/clang-format-diff.py | 0 contrib/devtools/copyright_header.py | 0 contrib/devtools/symbol-check.py | 0 contrib/devtools/test_deterministic_coverage.sh | 0 contrib/gitian-build.sh | 0 contrib/qt_translations.py | 0 contrib/wallettools/walletchangepass.py | 0 contrib/wallettools/walletunlock.py | 0 share/qt/extract_strings_qt.py | 0 share/qt/make_spinner.py | 0 share/qt/make_windows_icon.sh | 0 test/lint/check-doc.py | 0 test/lint/check-rpc-mappings.py | 0 test/lint/commit-script-check.sh | 0 test/lint/extended-lint-all.sh | 0 test/lint/extended-lint-cppcheck.sh | 0 test/lint/git-subtree-check.sh | 0 test/lint/lint-all.sh | 0 test/lint/lint-assertions.sh | 0 test/lint/lint-circular-dependencies.sh | 0 test/lint/lint-filenames.sh | 0 test/lint/lint-format-strings.py | 0 test/lint/lint-format-strings.sh | 0 test/lint/lint-git-commit-check.sh | 0 test/lint/lint-include-guards.sh | 0 test/lint/lint-includes.sh | 0 test/lint/lint-locale-dependence.sh | 0 test/lint/lint-logs.sh | 0 test/lint/lint-python-mutable-default-parameters.sh | 0 test/lint/lint-python-utf8-encoding.sh | 0 test/lint/lint-python.sh | 0 test/lint/lint-qt.sh | 0 test/lint/lint-rpc-help.sh | 0 test/lint/lint-shebang.sh | 0 test/lint/lint-shell-locale.sh | 0 test/lint/lint-shell.sh | 0 test/lint/lint-spelling.sh | 0 test/lint/lint-submodule.sh | 0 test/lint/lint-tests.sh | 0 test/lint/lint-whitespace.sh | 0 60 files changed, 13 insertions(+) mode change 100644 => 100755 ci/lint/04_install.sh mode change 100644 => 100755 ci/lint/05_before_script.sh mode change 100644 => 100755 ci/lint/06_script.sh mode change 100644 => 100755 ci/test/00_setup_env.sh mode change 100644 => 100755 ci/test/00_setup_env_arm.sh mode change 100644 => 100755 ci/test/00_setup_env_linux_i386.sh mode change 100644 => 100755 ci/test/00_setup_env_mac.sh mode change 100644 => 100755 ci/test/00_setup_env_mac_host.sh mode change 100644 => 100755 ci/test/00_setup_env_native.sh mode change 100644 => 100755 ci/test/00_setup_env_win32.sh mode change 100644 => 100755 ci/test/00_setup_env_win64.sh mode change 100644 => 100755 ci/test/03_before_install.sh mode change 100644 => 100755 ci/test/04_install.sh mode change 100644 => 100755 ci/test/05_before_script.sh mode change 100644 => 100755 ci/test/06_script_a.sh mode change 100644 => 100755 ci/test/06_script_b.sh mode change 100644 => 100755 ci/test_run_all.sh mode change 100644 => 100755 contrib/bitrpc/bitrpc.py mode change 100644 => 100755 contrib/devtools/circular-dependencies.py mode change 100644 => 100755 contrib/devtools/clang-format-diff.py mode change 100644 => 100755 contrib/devtools/copyright_header.py mode change 100644 => 100755 contrib/devtools/symbol-check.py mode change 100644 => 100755 contrib/devtools/test_deterministic_coverage.sh mode change 100644 => 100755 contrib/gitian-build.sh mode change 100644 => 100755 contrib/qt_translations.py mode change 100644 => 100755 contrib/wallettools/walletchangepass.py mode change 100644 => 100755 contrib/wallettools/walletunlock.py mode change 100644 => 100755 share/qt/extract_strings_qt.py mode change 100644 => 100755 share/qt/make_spinner.py mode change 100644 => 100755 share/qt/make_windows_icon.sh mode change 100644 => 100755 test/lint/check-doc.py mode change 100644 => 100755 test/lint/check-rpc-mappings.py mode change 100644 => 100755 test/lint/commit-script-check.sh mode change 100644 => 100755 test/lint/extended-lint-all.sh mode change 100644 => 100755 test/lint/extended-lint-cppcheck.sh mode change 100644 => 100755 test/lint/git-subtree-check.sh mode change 100644 => 100755 test/lint/lint-all.sh mode change 100644 => 100755 test/lint/lint-assertions.sh mode change 100644 => 100755 test/lint/lint-circular-dependencies.sh mode change 100644 => 100755 test/lint/lint-filenames.sh mode change 100644 => 100755 test/lint/lint-format-strings.py mode change 100644 => 100755 test/lint/lint-format-strings.sh mode change 100644 => 100755 test/lint/lint-git-commit-check.sh mode change 100644 => 100755 test/lint/lint-include-guards.sh mode change 100644 => 100755 test/lint/lint-includes.sh mode change 100644 => 100755 test/lint/lint-locale-dependence.sh mode change 100644 => 100755 test/lint/lint-logs.sh mode change 100644 => 100755 test/lint/lint-python-mutable-default-parameters.sh mode change 100644 => 100755 test/lint/lint-python-utf8-encoding.sh mode change 100644 => 100755 test/lint/lint-python.sh mode change 100644 => 100755 test/lint/lint-qt.sh mode change 100644 => 100755 test/lint/lint-rpc-help.sh mode change 100644 => 100755 test/lint/lint-shebang.sh mode change 100644 => 100755 test/lint/lint-shell-locale.sh mode change 100644 => 100755 test/lint/lint-shell.sh mode change 100644 => 100755 test/lint/lint-spelling.sh mode change 100644 => 100755 test/lint/lint-submodule.sh mode change 100644 => 100755 test/lint/lint-tests.sh mode change 100644 => 100755 test/lint/lint-whitespace.sh diff --git a/.travis.yml b/.travis.yml index e894e7c4f6..27ce7cf260 100644 --- a/.travis.yml +++ b/.travis.yml @@ -49,6 +49,19 @@ after_script: - echo $TRAVIS_COMMIT_RANGE jobs: include: + - stage: lint + name: 'lint' + env: + cache: pip + language: python + python: '3.5' + install: + - set -o errexit; source ./ci/lint/04_install.sh + before_script: + - set -o errexit; source ./ci/lint/05_before_script.sh + script: + - set -o errexit; source ./ci/lint/06_script.sh + - stage: test name: 'ARM [GOAL: install] [buster]' arch: arm64 # Can disable QEMU_USER_CMD and run the tests natively without qemu diff --git a/ci/lint/04_install.sh b/ci/lint/04_install.sh old mode 100644 new mode 100755 diff --git a/ci/lint/05_before_script.sh b/ci/lint/05_before_script.sh old mode 100644 new mode 100755 diff --git a/ci/lint/06_script.sh b/ci/lint/06_script.sh old mode 100644 new mode 100755 diff --git a/ci/test/00_setup_env.sh b/ci/test/00_setup_env.sh old mode 100644 new mode 100755 diff --git a/ci/test/00_setup_env_arm.sh b/ci/test/00_setup_env_arm.sh old mode 100644 new mode 100755 diff --git a/ci/test/00_setup_env_linux_i386.sh b/ci/test/00_setup_env_linux_i386.sh old mode 100644 new mode 100755 diff --git a/ci/test/00_setup_env_mac.sh b/ci/test/00_setup_env_mac.sh old mode 100644 new mode 100755 diff --git a/ci/test/00_setup_env_mac_host.sh b/ci/test/00_setup_env_mac_host.sh old mode 100644 new mode 100755 diff --git a/ci/test/00_setup_env_native.sh b/ci/test/00_setup_env_native.sh old mode 100644 new mode 100755 diff --git a/ci/test/00_setup_env_win32.sh b/ci/test/00_setup_env_win32.sh old mode 100644 new mode 100755 diff --git a/ci/test/00_setup_env_win64.sh b/ci/test/00_setup_env_win64.sh old mode 100644 new mode 100755 diff --git a/ci/test/03_before_install.sh b/ci/test/03_before_install.sh old mode 100644 new mode 100755 diff --git a/ci/test/04_install.sh b/ci/test/04_install.sh old mode 100644 new mode 100755 diff --git a/ci/test/05_before_script.sh b/ci/test/05_before_script.sh old mode 100644 new mode 100755 diff --git a/ci/test/06_script_a.sh b/ci/test/06_script_a.sh old mode 100644 new mode 100755 diff --git a/ci/test/06_script_b.sh b/ci/test/06_script_b.sh old mode 100644 new mode 100755 diff --git a/ci/test_run_all.sh b/ci/test_run_all.sh old mode 100644 new mode 100755 diff --git a/contrib/bitrpc/bitrpc.py b/contrib/bitrpc/bitrpc.py old mode 100644 new mode 100755 diff --git a/contrib/devtools/circular-dependencies.py b/contrib/devtools/circular-dependencies.py old mode 100644 new mode 100755 diff --git a/contrib/devtools/clang-format-diff.py b/contrib/devtools/clang-format-diff.py old mode 100644 new mode 100755 diff --git a/contrib/devtools/copyright_header.py b/contrib/devtools/copyright_header.py old mode 100644 new mode 100755 diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py old mode 100644 new mode 100755 diff --git a/contrib/devtools/test_deterministic_coverage.sh b/contrib/devtools/test_deterministic_coverage.sh old mode 100644 new mode 100755 diff --git a/contrib/gitian-build.sh b/contrib/gitian-build.sh old mode 100644 new mode 100755 diff --git a/contrib/qt_translations.py b/contrib/qt_translations.py old mode 100644 new mode 100755 diff --git a/contrib/wallettools/walletchangepass.py b/contrib/wallettools/walletchangepass.py old mode 100644 new mode 100755 diff --git a/contrib/wallettools/walletunlock.py b/contrib/wallettools/walletunlock.py old mode 100644 new mode 100755 diff --git a/share/qt/extract_strings_qt.py b/share/qt/extract_strings_qt.py old mode 100644 new mode 100755 diff --git a/share/qt/make_spinner.py b/share/qt/make_spinner.py old mode 100644 new mode 100755 diff --git a/share/qt/make_windows_icon.sh b/share/qt/make_windows_icon.sh old mode 100644 new mode 100755 diff --git a/test/lint/check-doc.py b/test/lint/check-doc.py old mode 100644 new mode 100755 diff --git a/test/lint/check-rpc-mappings.py b/test/lint/check-rpc-mappings.py old mode 100644 new mode 100755 diff --git a/test/lint/commit-script-check.sh b/test/lint/commit-script-check.sh old mode 100644 new mode 100755 diff --git a/test/lint/extended-lint-all.sh b/test/lint/extended-lint-all.sh old mode 100644 new mode 100755 diff --git a/test/lint/extended-lint-cppcheck.sh b/test/lint/extended-lint-cppcheck.sh old mode 100644 new mode 100755 diff --git a/test/lint/git-subtree-check.sh b/test/lint/git-subtree-check.sh old mode 100644 new mode 100755 diff --git a/test/lint/lint-all.sh b/test/lint/lint-all.sh old mode 100644 new mode 100755 diff --git a/test/lint/lint-assertions.sh b/test/lint/lint-assertions.sh old mode 100644 new mode 100755 diff --git a/test/lint/lint-circular-dependencies.sh b/test/lint/lint-circular-dependencies.sh old mode 100644 new mode 100755 diff --git a/test/lint/lint-filenames.sh b/test/lint/lint-filenames.sh old mode 100644 new mode 100755 diff --git a/test/lint/lint-format-strings.py b/test/lint/lint-format-strings.py old mode 100644 new mode 100755 diff --git a/test/lint/lint-format-strings.sh b/test/lint/lint-format-strings.sh old mode 100644 new mode 100755 diff --git a/test/lint/lint-git-commit-check.sh b/test/lint/lint-git-commit-check.sh old mode 100644 new mode 100755 diff --git a/test/lint/lint-include-guards.sh b/test/lint/lint-include-guards.sh old mode 100644 new mode 100755 diff --git a/test/lint/lint-includes.sh b/test/lint/lint-includes.sh old mode 100644 new mode 100755 diff --git a/test/lint/lint-locale-dependence.sh b/test/lint/lint-locale-dependence.sh old mode 100644 new mode 100755 diff --git a/test/lint/lint-logs.sh b/test/lint/lint-logs.sh old mode 100644 new mode 100755 diff --git a/test/lint/lint-python-mutable-default-parameters.sh b/test/lint/lint-python-mutable-default-parameters.sh old mode 100644 new mode 100755 diff --git a/test/lint/lint-python-utf8-encoding.sh b/test/lint/lint-python-utf8-encoding.sh old mode 100644 new mode 100755 diff --git a/test/lint/lint-python.sh b/test/lint/lint-python.sh old mode 100644 new mode 100755 diff --git a/test/lint/lint-qt.sh b/test/lint/lint-qt.sh old mode 100644 new mode 100755 diff --git a/test/lint/lint-rpc-help.sh b/test/lint/lint-rpc-help.sh old mode 100644 new mode 100755 diff --git a/test/lint/lint-shebang.sh b/test/lint/lint-shebang.sh old mode 100644 new mode 100755 diff --git a/test/lint/lint-shell-locale.sh b/test/lint/lint-shell-locale.sh old mode 100644 new mode 100755 diff --git a/test/lint/lint-shell.sh b/test/lint/lint-shell.sh old mode 100644 new mode 100755 diff --git a/test/lint/lint-spelling.sh b/test/lint/lint-spelling.sh old mode 100644 new mode 100755 diff --git a/test/lint/lint-submodule.sh b/test/lint/lint-submodule.sh old mode 100644 new mode 100755 diff --git a/test/lint/lint-tests.sh b/test/lint/lint-tests.sh old mode 100644 new mode 100755 diff --git a/test/lint/lint-whitespace.sh b/test/lint/lint-whitespace.sh old mode 100644 new mode 100755 From 52abbace0d07804f66b4dd869301d5b2f32fbdba Mon Sep 17 00:00:00 2001 From: div72 <60045611+div72@users.noreply.github.com> Date: Wed, 12 Aug 2020 20:27:10 +0300 Subject: [PATCH 03/16] Disable some checks --- ci/lint/06_script.sh | 10 +++++----- test/lint/lint-all.sh | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/ci/lint/06_script.sh b/ci/lint/06_script.sh index c55ead31da..b0897d07e5 100755 --- a/ci/lint/06_script.sh +++ b/ci/lint/06_script.sh @@ -10,13 +10,13 @@ if [ "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then test/lint/commit-script-check.sh $TRAVIS_COMMIT_RANGE fi -test/lint/git-subtree-check.sh src/crypto/ctaes +#test/lint/git-subtree-check.sh src/crypto/ctaes #test/lint/git-subtree-check.sh src/secp256k1 -test/lint/git-subtree-check.sh src/univalue -test/lint/git-subtree-check.sh src/leveldb +#test/lint/git-subtree-check.sh src/univalue +#test/lint/git-subtree-check.sh src/leveldb #test/lint/git-subtree-check.sh src/crc32c -test/lint/check-doc.py -test/lint/check-rpc-mappings.py . +#test/lint/check-doc.py +#test/lint/check-rpc-mappings.py . test/lint/lint-all.sh #if [ "$TRAVIS_REPO_SLUG" = "gridcoin-community/Gridcoin-Research" ] && [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then diff --git a/test/lint/lint-all.sh b/test/lint/lint-all.sh index fabc24c91b..737ead4b6e 100755 --- a/test/lint/lint-all.sh +++ b/test/lint/lint-all.sh @@ -19,6 +19,7 @@ LINTALL=$(basename "${BASH_SOURCE[0]}") EXIT_CODE=0 for f in "${SCRIPTDIR}"/lint-*.sh; do + echo $f if [ "$(basename "$f")" != "$LINTALL" ]; then if ! "$f"; then echo "^---- failure generated from $f" From 3292f8ce8ab97d614bd6483a8f5a922593536e59 Mon Sep 17 00:00:00 2001 From: div72 <60045611+div72@users.noreply.github.com> Date: Wed, 12 Aug 2020 21:06:14 +0300 Subject: [PATCH 04/16] Fix typos --- CHANGELOG.md | 10 +++++----- doc/README.md | 2 +- doc/README_osx.md | 4 ++-- doc/build-unix.md | 2 +- doc/gridcoinresearch.conf.md | 4 ++-- doc/readme-qt.rst | 2 +- src/gridcoinresearchd.cpp | 2 +- src/init.cpp | 4 ++-- src/kernel.cpp | 4 ++-- src/main.cpp | 8 ++++---- src/main.h | 4 ++-- src/miner.cpp | 4 ++-- src/neuralnet/account.h | 2 +- src/neuralnet/accrual/newbie.h | 2 +- src/neuralnet/accrual/research_age.h | 2 +- src/neuralnet/accrual/snapshot.h | 4 ++-- src/neuralnet/claim.cpp | 2 +- src/neuralnet/claim.h | 6 +++--- src/neuralnet/project.h | 2 +- src/neuralnet/quorum.cpp | 8 ++++---- src/neuralnet/quorum.h | 2 +- src/neuralnet/superblock.h | 2 +- src/neuralnet/tally.cpp | 4 ++-- src/neuralnet/voting/result.cpp | 2 +- src/qt/bitcoingui.cpp | 4 ++-- src/qt/diagnosticsdialog.cpp | 4 ++-- .../researcher/researcherwizardprojectspage.cpp | 2 +- src/qt/transactionrecord.cpp | 2 +- src/qt/upgradeqt.cpp | 4 ++-- src/rpcblockchain.cpp | 2 +- src/rpcdataacq.cpp | 4 ++-- src/rpcrawtransaction.cpp | 16 ++++++++-------- src/scraper/http.cpp | 2 +- src/scraper/http.h | 4 ++-- src/scraper/scraper.cpp | 8 ++++---- src/scraper/scraper.h | 4 ++-- src/scraper_net.cpp | 4 ++-- src/scraper_net.h | 2 +- src/script.cpp | 2 +- src/test/neuralnet/contract_tests.cpp | 4 ++-- src/test/neuralnet/researcher_tests.cpp | 2 +- src/test/script_tests.cpp | 2 +- src/upgrade.cpp | 2 +- src/upgrade.h | 2 +- src/util.h | 2 +- src/version.h | 2 +- src/wallet/rpcwallet.cpp | 2 +- src/wallet/wallet.cpp | 4 ++-- src/wallet/wallet.h | 2 +- test/lint/lint-all.sh | 1 - test/lint/lint-circular-dependencies.sh | 12 ------------ test/lint/lint-spelling.ignore-words.txt | 6 ++++++ test/lint/lint-spelling.sh | 2 +- 53 files changed, 95 insertions(+), 102 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a74298a96..a0cd38cc1a 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,7 +56,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - improved statistics and SB contract core caching based on a bClean flag in the cache global - new SB format and packing for bv11 - new SB contract hashing (native) for bv11 - - changes to accomodate new beacon approach + - changes to accommodate new beacon approach - Implement in memory versioning for team file ETags - Implement local dynamic team requirement removal and whitelist #1502 (@cyrossignol) @@ -253,7 +253,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Clean-up beacon manipulation (@Foggyx420) ### Fixed - - Building errors on Mac releated to SVG framework (@thecharlatan) + - Building errors on Mac related to SVG framework (@thecharlatan) - neural data response - neural network fixes (@Foggyx420) - investor cpid's appearing as zeros in block index (@tomasbrod) @@ -335,7 +335,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - Move context sensitive DPoR block checks to ConnectBlock #922 (@tomasbrod). - Check incoming blocks for malformed DPoR signature #922. - - Corect tally height on init #917 (@denravonska). + - Correct tally height on init #917 (@denravonska). - Prevent staking of a block with a failed signature #948 (@Foggyx420). - Fix UI and RPC slowdown regression #961 (@denravonska). - Fix Debian lint errors #886 #885 #884 #883 (@caraka). @@ -475,7 +475,7 @@ Internal test version used to sort out the forks. (@Foggyx420). - Fix stake modifier mismatch which caused nodes to get stuck on first V8 block #581 (@tomasbrod). - - Fix beacon auto advertisment issue when done automatically #580 (@Foggyx420). + - Fix beacon auto advertisement issue when done automatically #580 (@Foggyx420). - Fix for loss of PoR rewards due to reorganize #578 (@tomasbrod). - Fix upgrader compile error on Linux #541 (@theMarix). - Fix duplicate poll entries #539 (@denravonska). @@ -554,7 +554,7 @@ Internal test version used to sort out the forks. to broken function #362 (@skcin). - Replace translations which were just question marks with new files from the Bitcoin source tree: Arabic, Belarusian, Bulgarian, Greek, Persian, - Hebrew, Hindi, Japanese, Georgian, Kirghiz, Serbian, Thai, Ukranian, + Hebrew, Hindi, Japanese, Georgian, Kirghiz, Serbian, Thai, Ukrainian, Urdu and Chinese. - Don't print the "Bootup" and "Signing block" messages unless fDebug (@tomasbrod). - Print beacons as they are loaded and debug3=true (@tomasbrod). diff --git a/doc/README.md b/doc/README.md index 075b3d7005..930eb3bbbd 100644 --- a/doc/README.md +++ b/doc/README.md @@ -31,7 +31,7 @@ The following are developer notes on how to build Gridcoin on your native platfo Running ------- -To create a secure environment for runnning Gridcoin see: +To create a secure environment for running Gridcoin see: - [Running Gridcoin](running.md) diff --git a/doc/README_osx.md b/doc/README_osx.md index 12cd34273c..8ed2f57108 100644 --- a/doc/README_osx.md +++ b/doc/README_osx.md @@ -1,4 +1,4 @@ -Cross Plattform and Deterministic OS X Dmg Notes. +Cross Platform and Deterministic OS X Dmg Notes. ================================================ Working OS X DMGs are created in Linux by combining a recent clang, @@ -30,7 +30,7 @@ To complicate things further, all builds must target an Apple SDK. These SDKs are free to download, but not redistributable. To obtain it, register for a developer account, then download the [Xcode 7.3.1 dmg](https://developer.apple.com/devcenter/download.action?path=/Developer_Tools/Xcode_7.3.1/Xcode_7.3.1.dmg). -Cross Plattform building +Cross Platform building ------------------------ Download and extract the SDK to depends/SDKs. Then build the dependencies from the depends directory and deploy the .dmg: ``` diff --git a/doc/build-unix.md b/doc/build-unix.md index d3107b1807..9b6afca274 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -26,7 +26,7 @@ Clone the repository and cd into it: git clone https://github.com/gridcoin-community/Gridcoin-Research cd Gridcoin-Research ``` -Go to platform specific instructions for the required depencies below. +Go to platform specific instructions for the required dependencies below. To Build --------------------- diff --git a/doc/gridcoinresearch.conf.md b/doc/gridcoinresearch.conf.md index 675bab9bfa..aab08c35df 100644 --- a/doc/gridcoinresearch.conf.md +++ b/doc/gridcoinresearch.conf.md @@ -163,10 +163,10 @@ difficulty swings. **sidestake=
,** You can specify multiple sidetake entries, just like addnode or connect. -Note that the total number of ouputs for the coinstake is limited +Note that the total number of outputs for the coinstake is limited to 8 in block version 10+, and vout[0] must be empty, so that gives 7 usable outputs. One must always be reserved for the actual coinstake -output (return), so that leaves up to 6 usuable outputs for rewards +output (return), so that leaves up to 6 usable outputs for rewards distribution. You can specify more than six entries for sidestaking. If more than six are specified, six entries per stake are randomly chosen from the list. diff --git a/doc/readme-qt.rst b/doc/readme-qt.rst index 00a324e1ae..338ee98d25 100644 --- a/doc/readme-qt.rst +++ b/doc/readme-qt.rst @@ -69,7 +69,7 @@ Alternatively - An executable named gridcoinresearch will be built in the /src/Qt directory. -- If you have used Homebrew to install dependancies earlier, no need to install MacPorts as above. +- If you have used Homebrew to install dependencies earlier, no need to install MacPorts as above. Build configuration options diff --git a/src/gridcoinresearchd.cpp b/src/gridcoinresearchd.cpp index e6d12c4696..ea25bb1517 100644 --- a/src/gridcoinresearchd.cpp +++ b/src/gridcoinresearchd.cpp @@ -94,7 +94,7 @@ bool AppInit(int argc, char* argv[]) Shutdown(NULL); } - /** Check here config file incase TestNet is set there and not in mapArgs **/ + /** Check here config file in case TestNet is set there and not in mapArgs **/ ReadConfigFile(mapArgs, mapMultiArgs); // Command-line RPC - Test this - ensure single commands execute and exit please. diff --git a/src/init.cpp b/src/init.cpp index bb550f841a..7665ffcc2d 100755 --- a/src/init.cpp +++ b/src/init.cpp @@ -776,7 +776,7 @@ bool AppInit2(ThreadHandlerPtr threads) if (GetBoolArg("-salvagewallet")) { - // Recover readable keypairs: + // Recover readable key pairs: if (!CWalletDB::Recover(bitdb, walletFileName.string(), true)) return false; } @@ -1194,7 +1194,7 @@ bool AppInit2(ThreadHandlerPtr threads) g_banman->DumpBanlist(); }, DUMP_BANS_INTERVAL * 1000); - // Primitive, but this is what the scraper does in the scraper houskeeping loop. It checks to see if the logs need to be archived + // Primitive, but this is what the scraper does in the scraper housekeeping loop. It checks to see if the logs need to be archived // by default every 5 mins. Note that passing false to the archive function means that if we have not crossed over the day boundary, // it does nothing, so this is a very inexpensive call. Also if -logarchivedaily is set to false, then this will be a no-op. scheduler.scheduleEvery([]{ diff --git a/src/kernel.cpp b/src/kernel.cpp index 78a29e6bad..cb56cdbb53 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -494,9 +494,9 @@ bool CalculateLegacyV3HashProof( // Plug proof-of-work exploit. // TODO: Stake modifier is included without much understanding. // Without the modifier, attacker can create transactions which output will -// stake at desired time. In other words attacker can check wheter transaction +// stake at desired time. In other words attacker can check whether transaction // output will stake in the future and create transactions accordingly. -// Thus including modifier, even not completly researched, increases security. +// Thus including modifier, even not completely researched, increases security. // Note: Rsa or Magnitude weight not included due to multiplication issue. // Note: Payment age and magnitude restrictions not included as they are not // important in my view and are too restrictive for honest users. diff --git a/src/main.cpp b/src/main.cpp index 85d59244cd..4cb4526db5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -773,7 +773,7 @@ std::string DefaultWalletAddress() } } - //Cant Find + //Can't Find for (auto const& item : pwalletMain->mapAddressBook) { const CBitcoinAddress& address = item.first; @@ -2358,7 +2358,7 @@ class ClaimValidator } // Blocks version 10 and below represented rewards as floating-point - // values and needed to accomodate floating-point errors so we'll do + // values and needed to accommodate floating-point errors so we'll do // the same rounding on the floating-point representations: // double subsidy = ((double)research_owed / COIN) * 1.25; @@ -3002,7 +3002,7 @@ bool ReorganizeChain(CTxDB& txdb, unsigned &cnt_dis, unsigned &cnt_con, CBlock & //assert(!pindexBest->pnext); assert(pindexNew->GetBlockHash()==blockNew.GetHash(true)); /* note: it was already determined that this chain is better than current best */ - /* assert(pindexNew->nChainTrust > nBestChainTrust); but may be overriden by command */ + /* assert(pindexNew->nChainTrust > nBestChainTrust); but may be overridden by command */ assert( !pindexGenesisBlock == !pindexBest ); list vResurrect; @@ -3365,7 +3365,7 @@ bool CBlock::CheckBlock(int height1, bool fCheckPOW, bool fCheckMerkleRoot, bool if (fCheckPOW && IsProofOfWork() && !CheckProofOfWork(GetHash(true), nBits)) return DoS(50, error("CheckBlock[] : proof of work failed")); - //Reject blocks with diff that has grown to an extrordinary level (should never happen) + //Reject blocks with diff that has grown to an extraordinary level (should never happen) double blockdiff = GetBlockDifficulty(nBits); if (height1 > nGrandfather && blockdiff > 10000000000000000) { diff --git a/src/main.h b/src/main.h index 208637059a..4d1a1306f2 100644 --- a/src/main.h +++ b/src/main.h @@ -1450,7 +1450,7 @@ class CBlockIndex }; uint64_t nStakeModifier; // hash modifier for proof-of-stake - unsigned int nStakeModifierChecksum; // checksum of index; in-memeory only + unsigned int nStakeModifierChecksum; // checksum of index; in-memory only // proof-of-stake specific fields COutPoint prevoutStake; @@ -1739,7 +1739,7 @@ class CDiskBlockIndex : public CBlockIndex READWRITE(nNonce); READWRITE(blockHash); - //7-11-2015 - Gridcoin - New Accrual Fields (Note, Removing the determinstic block number to make this happen all the time): + //7-11-2015 - Gridcoin - New Accrual Fields (Note, Removing the deterministic block number to make this happen all the time): std::string cpid_hex = GetMiningId().ToString(); double research_subsidy_grc = nResearchSubsidy / (double)COIN; double interest_subsidy_grc = nInterestSubsidy / (double)COIN; diff --git a/src/miner.cpp b/src/miner.cpp index 09a2b95b8c..da72fc3b0d 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -227,7 +227,7 @@ bool CreateRestOfTheBlock(CBlock &block, CBlockIndex* pindexPrev) // Largest block you're willing to create: unsigned int nBlockMaxSize = GetArg("-blockmaxsize", MAX_BLOCK_SIZE_GEN/2); - // Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity: + // Limit to between 1K and MAX_BLOCK_SIZE-1K for sanity: nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize)); // How much of the block should be dedicated to high-priority transactions, @@ -703,7 +703,7 @@ void SplitCoinStakeOutput(CBlock &blocknew, int64_t &nReward, bool &fEnableStake // The maximum number of outputs allowed on the coinstake txn is 3 for block version 9 and below and // 8 for 10 and above. The first one must be empty, so that gives 2 and 7 usable ones, respectively. unsigned int nMaxOutputs = (blocknew.nVersion >= 10) ? 8 : 3; - // Set the maximum number of sidestake ouputs to two less than the maximum allowable coinstake outputs + // Set the maximum number of sidestake outputs to two less than the maximum allowable coinstake outputs // to ensure outputs are reserved for the coinstake output itself and the empty one. Any sidestake // addresses and percentages in excess of this number will be ignored. unsigned int nMaxSideStakeOutputs = nMaxOutputs - 2; diff --git a/src/neuralnet/account.h b/src/neuralnet/account.h index dfa48dd686..28e5e8dea5 100644 --- a/src/neuralnet/account.h +++ b/src/neuralnet/account.h @@ -260,7 +260,7 @@ class ResearchAccountRange typedef StorageType::size_type size_type; //! - //! \brief Initialze the wrapper. + //! \brief Initialize the wrapper. //! //! \param accounts Points to the accounts stored in the tally. //! diff --git a/src/neuralnet/accrual/newbie.h b/src/neuralnet/accrual/newbie.h index 721e812fae..a343a1caa8 100644 --- a/src/neuralnet/accrual/newbie.h +++ b/src/neuralnet/accrual/newbie.h @@ -16,7 +16,7 @@ class NewbieAccrualComputer : public IAccrualComputer public: //! - //! \brief Initialze an accrual calculator for a CPID that never earned + //! \brief Initialize an accrual calculator for a CPID that never earned //! a research reward before. //! //! \param cpid CPID to calculate research accrual for. diff --git a/src/neuralnet/accrual/research_age.h b/src/neuralnet/accrual/research_age.h index a60f32482e..8b40cd0362 100644 --- a/src/neuralnet/accrual/research_age.h +++ b/src/neuralnet/accrual/research_age.h @@ -44,7 +44,7 @@ class ResearchAgeComputer : public IAccrualComputer { public: //! - //! \brief Initialze a research age accrual calculator. + //! \brief Initialize a research age accrual calculator. //! //! \param cpid CPID to calculate research accrual for. //! \param account CPID's historical accrual context. diff --git a/src/neuralnet/accrual/snapshot.h b/src/neuralnet/accrual/snapshot.h index 399408a191..e92806238d 100644 --- a/src/neuralnet/accrual/snapshot.h +++ b/src/neuralnet/accrual/snapshot.h @@ -219,7 +219,7 @@ class SnapshotAccrualComputer : public IAccrualComputer, SnapshotCalculator public: //! - //! \brief Initialze a delta snapshot accrual calculator. + //! \brief Initialize a delta snapshot accrual calculator. //! //! \param cpid CPID to calculate research accrual for. //! \param account CPID's historical accrual context. @@ -244,7 +244,7 @@ class SnapshotAccrualComputer : public IAccrualComputer, SnapshotCalculator { // The maximum accrual that a CPID can claim in one block is limited to // the amount of accrual that a CPID can collect over two days when the - // CPID acheives the maximum magnitude value supported in a superblock. + // CPID achieves the maximum magnitude value supported in a superblock. // // Where... // diff --git a/src/neuralnet/claim.cpp b/src/neuralnet/claim.cpp index e67c962b7b..f5954f156a 100644 --- a/src/neuralnet/claim.cpp +++ b/src/neuralnet/claim.cpp @@ -29,7 +29,7 @@ std::string BlockHashToString(const uint256& block_hash) //! input to sign or verify a research reward claim. //! //! \param claim Claim to generate a hash for. -//! \param last_block_hash Hash of the block that preceeds the block that +//! \param last_block_hash Hash of the block that precedes the block that //! contains the claim. //! \param coinstake_tx Coinstake transaction of the block that contains //! the claim. diff --git a/src/neuralnet/claim.h b/src/neuralnet/claim.h index 812619dd8b..a070cea74e 100644 --- a/src/neuralnet/claim.h +++ b/src/neuralnet/claim.h @@ -115,7 +115,7 @@ class Claim : public IContractPayload //! //! \brief Hash of the block below the block containing this claim. //! - //! Nodes check that this hash matches the hash of block that preceeds the + //! Nodes check that this hash matches the hash of block that precedes the //! block that contains the claim. This hash is signed along with the CPID //! to prevent replay of the research reward subsidy. //! @@ -311,7 +311,7 @@ class Claim : public IContractPayload //! //! \param private_key The private key of the beacon to sign the claim //! with. - //! \param last_block_hash Hash of the block that preceeds the block that + //! \param last_block_hash Hash of the block that precedes the block that //! contains the claim. //! \param coinstake_tx Coinstake transaction of the block that contains //! the claim. @@ -330,7 +330,7 @@ class Claim : public IContractPayload //! //! \param public_key The public key of the beacon that signed the //! claim. - //! \param last_block_hash Hash of the block that preceeds the block that + //! \param last_block_hash Hash of the block that precedes the block that //! contains the claim. //! \param coinstake_tx Coinstake transaction of the block that contains //! the claim. diff --git a/src/neuralnet/project.h b/src/neuralnet/project.h index fb11ee6fdb..3d68d8e756 100644 --- a/src/neuralnet/project.h +++ b/src/neuralnet/project.h @@ -204,7 +204,7 @@ class WhitelistSnapshot size_type size() const; //! - //! \brief Deteremine whether the whitelist contains any projects. + //! \brief Determine whether the whitelist contains any projects. //! //! This does not guarantee that the whitelist is up-to-date. The caller is //! responsible for verifiying the block height. diff --git a/src/neuralnet/quorum.cpp b/src/neuralnet/quorum.cpp index 8f1052db3e..4179795848 100644 --- a/src/neuralnet/quorum.cpp +++ b/src/neuralnet/quorum.cpp @@ -270,7 +270,7 @@ class QuorumVote //! by embedding the hash of that superblock in the claim section of blocks //! that it generates. Another node stakes the final superblock if the hash //! of the local pending superblock matches the most popular hash by weight -//! of the preceeding votes. +//! of the preceding votes. //! //! For better security, superblock staking and validation using data from //! scraper convergence replaces the problematic quorum mechanism in block @@ -646,7 +646,7 @@ class SuperblockValidator //! //! \brief Maps candidate project part hashes to a set of scrapers. //! - //! Each set must hold at least the mininum number of scraper IDs for a + //! Each set must hold at least the minimum number of scraper IDs for a //! supermajority for a project part to be considered for convergence. //! typedef std::map> CandidatePartHashMap; @@ -685,7 +685,7 @@ class SuperblockValidator //! The \c ProjectResolver will attempt to match these hashes to a part //! contained in a manifest for each scraper to find a supermajority. //! - //! Each set must hold at least the mininum number of scraper IDs for a + //! Each set must hold at least the minimum number of scraper IDs for a //! supermajority for each project or the superblock validation fails. //! CandidatePartHashMap m_candidate_hashes; @@ -856,7 +856,7 @@ class SuperblockValidator } //! - //! \brief Initialze a project combiner that produces no results. + //! \brief Initialize a project combiner that produces no results. //! ProjectCombiner() : m_total_combinations(0) diff --git a/src/neuralnet/quorum.h b/src/neuralnet/quorum.h index d177f4f17e..56983cf29b 100644 --- a/src/neuralnet/quorum.h +++ b/src/neuralnet/quorum.h @@ -199,7 +199,7 @@ class Quorum static bool SuperblockNeeded(const int64_t now); //! - //! \brief Initialze the tally's superblock context. + //! \brief Initialize the tally's superblock context. //! //! \param pindexLast The most recent block to begin loading backward from. //! diff --git a/src/neuralnet/superblock.h b/src/neuralnet/superblock.h index fac5e4ff6f..ccdb122d3f 100644 --- a/src/neuralnet/superblock.h +++ b/src/neuralnet/superblock.h @@ -1328,7 +1328,7 @@ class Superblock //! \param regenerate If \c true, skip selection of any cached hash value //! and recompute the hash. //! - //! \return A quorum hash object that contiains a SHA256 hash for version + //! \return A quorum hash object that contains a SHA256 hash for version //! 2+ superblocks or an MD5 hash for legacy version 1 superblocks. //! QuorumHash GetHash(const bool regenerate = false) const; diff --git a/src/neuralnet/tally.cpp b/src/neuralnet/tally.cpp index dd9041d067..9ddc1c6e65 100644 --- a/src/neuralnet/tally.cpp +++ b/src/neuralnet/tally.cpp @@ -306,7 +306,7 @@ class ResearcherTally //! //! \param superblock Refers to the current active superblock. //! - //! \return \c false if an IO error occured while processing the superblock. + //! \return \c false if an IO error occurred while processing the superblock. //! bool ApplySuperblock(SuperblockPtr superblock) { @@ -332,7 +332,7 @@ class ResearcherTally //! \param superblock Refers to the current active superblock (before the //! reverted superblock). //! - //! \return \c false if an IO error occured while processing the superblock. + //! \return \c false if an IO error occurred while processing the superblock. //! bool RevertSuperblock(SuperblockPtr superblock) { diff --git a/src/neuralnet/voting/result.cpp b/src/neuralnet/voting/result.cpp index e6cacce944..7f0aa9cf29 100644 --- a/src/neuralnet/voting/result.cpp +++ b/src/neuralnet/voting/result.cpp @@ -596,7 +596,7 @@ class VoteResolver } //! - //! \brief Get a file handle to the block file that contains the specifed + //! \brief Get a file handle to the block file that contains the specified //! transaction position. //! static FILE* OpenBlockFile(const CDiskTxPos& pos) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index feb8c79ff9..2d95a40a98 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1435,14 +1435,14 @@ void BitcoinGUI::updateStakingIcon() else if (!staking && !able_to_stake) { labelStakingIcon->setPixmap(QIcon(":/icons/staking_unable").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); - //Part of this string wont be translated :( + //Part of this string won't be translated :( labelStakingIcon->setToolTip(tr("Unable to stake: %1") .arg(QString(ReasonNotStaking.c_str()))); } else //if (miner_first_pass_complete) { labelStakingIcon->setPixmap(QIcon(":/icons/staking_off").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); - //Part of this string wont be translated :( + //Part of this string won't be translated :( labelStakingIcon->setToolTip(tr("Not staking currently: %1, Estimated staking frequency is %2.") .arg(QString(ReasonNotStaking.c_str())) .arg(estimated_staking_freq)); diff --git a/src/qt/diagnosticsdialog.cpp b/src/qt/diagnosticsdialog.cpp index 32e47d8aec..d5c5e4c209 100644 --- a/src/qt/diagnosticsdialog.cpp +++ b/src/qt/diagnosticsdialog.cpp @@ -83,7 +83,7 @@ void DiagnosticsDialog::UpdateOverallDiagnosticResult(DiagnosticResult diagnosti { LOCK(cs_diagnostictests); - // Set diagnostic_result_status to completed. This is under lock, so noone can snoop. + // Set diagnostic_result_status to completed. This is under lock, so no one can snoop. diagnostic_result_status = completed; // If the total number of registered tests is less than the initialized number, then @@ -713,7 +713,7 @@ void DiagnosticsDialog::clkFinished() } else // The other state here is a socket or other indeterminate error such as a timeout (coming from clkSocketError). { - // This is needed to "cancel" the timout timer. Essentially if the test was marked completed via the normal exits + // This is needed to "cancel" the timeout timer. Essentially if the test was marked completed via the normal exits // above, then when the timer calls clkFinished again, it will hit this conditional and be a no-op. if (GetTestStatus("verifyClockResult") != completed) { diff --git a/src/qt/researcher/researcherwizardprojectspage.cpp b/src/qt/researcher/researcherwizardprojectspage.cpp index df00f9f090..af1f4914c7 100644 --- a/src/qt/researcher/researcherwizardprojectspage.cpp +++ b/src/qt/researcher/researcherwizardprojectspage.cpp @@ -56,7 +56,7 @@ void ResearcherWizardProjectsPage::initializePage() QMessageBox::warning( this, windowTitle(), - tr("An error occured while saving the email address to the " + tr("An error occurred while saving the email address to the " "configuration file. Please see debug.log for details."), QMessageBox::Ok, QMessageBox::Ok); diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 8f287999b2..569f71c750 100755 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -260,7 +260,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet * // We will simply select the first and only one. Note that we are // looping through the outputs one by one in the for loop above this, // So if we get here, we are not a coinbase or coinstake, and we are on - // an ouput that isn't ours. The worst that can happen from this + // an output that isn't ours. The worst that can happen from this // simple approach is to label more than one output with the // first found contract type. For right now, this is sufficient, because // the contracts that are sent right now only contain two outputs, diff --git a/src/qt/upgradeqt.cpp b/src/qt/upgradeqt.cpp index 6c65f1c22f..3a30291635 100644 --- a/src/qt/upgradeqt.cpp +++ b/src/qt/upgradeqt.cpp @@ -18,7 +18,7 @@ QString UpgradeQt::ToQString(const std::string& string) bool UpgradeQt::SnapshotMain() { - // Keep this seperate from the main application + // Keep this separate from the main application int xargc = 1; char *xargv[] = {(char*)"gridcoinresearch"}; @@ -228,7 +228,7 @@ bool UpgradeQt::SnapshotMain() { ErrorMsg(_("Snapshot extraction failed! Cleaning up any extracted data"), _("The wallet will now shutdown.")); - // Do this without checking on sucess, If it passed in stage 3 it will pass here. + // Do this without checking on success, If it passed in stage 3 it will pass here. UpgradeMain.CleanupBlockchainData(); return false; diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 28a3e48aa8..bbda58e725 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -477,7 +477,7 @@ UniValue rainbymagnitude(const UniValue& params, bool fHelp) for (const auto& entry : mScraperConvergedStats) { - // Only consider entries along the specfied dimension + // Only consider entries along the specified dimension if (entry.first.objecttype == rainbymagmode) { NN::Cpid CPIDKey; diff --git a/src/rpcdataacq.cpp b/src/rpcdataacq.cpp index 7e51bece9d..13555dab43 100644 --- a/src/rpcdataacq.cpp +++ b/src/rpcdataacq.cpp @@ -432,7 +432,7 @@ UniValue rpc_exportstats(const UniValue& params, bool fHelp) { if(fHelp) throw runtime_error( - "exportstats1 [maxblocks agregate [endblock]] \n"); + "exportstats1 [maxblocks aggregate [endblock]] \n"); /* count, high */ long endblock= INT_MAX; long maxblocks= 805; @@ -605,7 +605,7 @@ UniValue rpc_exportstats(const UniValue& params, bool fHelp) cnt_neuralcurr = 0; cnt_contract = 0; } - /* This is wery important */ + /* This is very important */ cur = cur->pprev; } diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 80dff86421..276e70da91 100755 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -713,7 +713,7 @@ UniValue consolidatemsunspent(const UniValue& params, bool fHelp) int64_t nRedeemScriptSize = 0; if (nReqSigsType < 1 || nReqSigsType > 4) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid type of multi-signature address choosen"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid type of multi-signature address chosen"); else if (nReqSigsType == 1) { @@ -792,7 +792,7 @@ UniValue consolidatemsunspent(const UniValue& params, bool fHelp) hash = block.vtx[i].GetHash(); - // Incase a fail here we can just continue thou it shouldn't happen + // In case a fail here we can just continue thou it shouldn't happen if (!tx.ReadFromDisk(txdb, COutPoint(hash, 0), txindex)) continue; @@ -812,7 +812,7 @@ UniValue consolidatemsunspent(const UniValue& params, bool fHelp) // If we found a match to multisig address do our work if (CBitcoinAddress(txaddress) == Address) { - // Check if this output is alread spent + // Check if this output is already spent COutPoint dummy = COutPoint(tx.GetHash(), j); // This is spent so move along @@ -896,10 +896,10 @@ UniValue consolidatemsunspent(const UniValue& params, bool fHelp) * Total vin signatures size will calculate as follows: * SIGHEXSIZE H = (R + (S * 148)) * N * - * Padding for vins will be calulated as follows: + * Padding for vins will be calculated as follows: * VINP = (8 + 8 + 10) * N (To Shorten we will assume 26 * N) * - * Total vout size we will assume is 70 since thats the biggest it appears to be able to be as a base size with max money + * Total vout size we will assume is 70 since that's the biggest it appears to be able to be as a base size with max money * VOUTP = 2 + 10 (To Shorten we will assume 12) * * So in esscense the formula for all this will be: @@ -909,7 +909,7 @@ UniValue consolidatemsunspent(const UniValue& params, bool fHelp) * Potentialbytesuze PBS = PHS / 2 * * Note: this will keep the size pretty close to the real size. - * This also leaves buffer room incase and this should always be an overestimation of the actual sizes + * This also leaves buffer room in case and this should always be an overestimation of the actual sizes * Sizes vary by the behaviour of the hex/serialization of the hex as well. * */ @@ -1054,7 +1054,7 @@ UniValue scanforunspent(const UniValue& params, bool fHelp) hash = block.vtx[i].GetHash(); - // Incase a fail here we can just continue thou it shouldn't happen + // In case a fail here we can just continue thou it shouldn't happen if (!tx.ReadFromDisk(txdb, COutPoint(hash, 0), txindex)) continue; @@ -1071,7 +1071,7 @@ UniValue scanforunspent(const UniValue& params, bool fHelp) // If we found a match to multisig address do our work if (CBitcoinAddress(txaddress) == Address) { - // Check if this output is alread spent + // Check if this output is already spent COutPoint dummy = COutPoint(tx.GetHash(), j); // This is spent so move along diff --git a/src/scraper/http.cpp b/src/scraper/http.cpp index c4433769f0..cbbcf3d8f1 100644 --- a/src/scraper/http.cpp +++ b/src/scraper/http.cpp @@ -282,7 +282,7 @@ std::string Http::GetLatestVersionResponse() CURLcode res = curl_easy_perform(curl.get()); if (res > 0) - throw std::runtime_error(tfm::format("Failed to get version reponse from URL %s: %s", url, curl_easy_strerror(res))); + throw std::runtime_error(tfm::format("Failed to get version response from URL %s: %s", url, curl_easy_strerror(res))); curl_slist_free_all(headers); diff --git a/src/scraper/http.h b/src/scraper/http.h index 1a6d95ebae..9d7028c3f1 100644 --- a/src/scraper/http.h +++ b/src/scraper/http.h @@ -60,7 +60,7 @@ class Http //! //! \brief Fetch ETag for URL. //! - //! Downlaods the headers for \p url and attempts to find the ETag. + //! Downloads the headers for \p url and attempts to find the ETag. //! //! \param url URL to fetch ETag from. //! \param userpass Optional HTTP credentials. @@ -110,7 +110,7 @@ class Http }; //! - //! \brief Manages the libcurl lifecycle by invoking initailization and + //! \brief Manages the libcurl lifecycle by invoking initialization and //! cleanup functions. //! //! The static lifetime of this object ensures that curl_global_init() is diff --git a/src/scraper/scraper.cpp b/src/scraper/scraper.cpp index 1dec2a5a4f..b2f1001206 100755 --- a/src/scraper/scraper.cpp +++ b/src/scraper/scraper.cpp @@ -2458,7 +2458,7 @@ uint256 GetmScraperFileManifestHash() } /*********************** -* Persistance * +* Persistence * ************************/ bool LoadBeaconList(const fs::path& file, ScraperBeaconMap& mBeaconMap) @@ -2750,7 +2750,7 @@ bool InsertScraperFileManifestEntry(ScraperFileManifestEntry& entry) } } - // True if insert was sucessful, false if entry with key (hash) already exists in map. + // True if insert was successful, false if entry with key (hash) already exists in map. return ret.second; } @@ -4268,7 +4268,7 @@ bool ScraperConstructConvergedManifest(ConvergedManifest& StructConvergedManifes // iter_inner.second.second is the manifest CONTENT hash. mManifestsBinnedByTime.insert(std::make_pair(iter_inner.first, iter_inner.second.second)); - // Even though this is a multimap on purpose because we are going to count occurances of the same key, + // Even though this is a multimap on purpose because we are going to count occurrences of the same key, // We need to prevent the insertion of a second entry with the same content from the same scraper. This // could otherwise happen if a scraper is shutdown and restarted, and it publishes a new manifest // before it receives manifests from the other nodes (including its own prior manifests). @@ -4568,7 +4568,7 @@ bool ScraperConstructConvergedManifestByProject(const NN::WhitelistSnapshot& pro // Insert into mManifestsBinnedByTime multimap. mProjectObjectsBinnedByTime.insert(std::make_pair(nProjectObjectTime, std::make_tuple(nProjectObjectHash, manifest.ConsensusBlock, *manifest.phash))); - // Even though this is a multimap on purpose because we are going to count occurances of the same key, + // Even though this is a multimap on purpose because we are going to count occurrences of the same key, // We need to prevent the insertion of a second entry with the same content from the same scraper. This is // even more true here at the part level than at the manifest level, because if both SCRAPER_CMANIFEST_RETAIN_NONCURRENT // and SCRAPER_CMANIFEST_INCLUDE_NONCURRENT_PROJ_FILES are true, then there can be many references diff --git a/src/scraper/scraper.h b/src/scraper/scraper.h index c8c513d9b2..068e2051bc 100644 --- a/src/scraper/scraper.h +++ b/src/scraper/scraper.h @@ -30,7 +30,7 @@ #include "neuralnet/superblock.h" /********************* -* Scraper Namepsace * +* Scraper Namespace * *********************/ namespace fs = boost::filesystem; @@ -74,7 +74,7 @@ double CPID_MAG_LIMIT = NN::Magnitude::MAX; // that must be available to form a convergence. Above this minimum, the ratio // is followed. For example, if there are 4 scrapers, a ratio of 0.6 would require // CEILING(0.6 * 4) = 3. See NumScrapersForSupermajority below. -// If there is only 1 scraper available, and the mininum is 2, then a convergence +// If there is only 1 scraper available, and the minimum is 2, then a convergence // will not happen. Setting this below 2 will allow convergence to happen without // cross checking, and is undesirable, because the scrapers are not supposed to be // trusted entities. diff --git a/src/scraper_net.cpp b/src/scraper_net.cpp index d3e0836912..2381d30399 100644 --- a/src/scraper_net.cpp +++ b/src/scraper_net.cpp @@ -40,7 +40,7 @@ extern bool IsScraperMaximumManifestPublishingRateExceeded(int64_t& nTime, CPubK bool CSplitBlob::RecvPart(CNode* pfrom, CDataStream& vRecv) { /* Part of larger hashed blob. Currently only used for scraper data sharing. - * retrive parent object from mapBlobParts + * retrieve parent object from mapBlobParts * notify object or ignore if no object found * erase from mapAlreadyAskedFor */ @@ -503,7 +503,7 @@ void CScraperManifest::UnserializeCheck(CDataStream& ss, unsigned int& banscore_ if (!OutOfSyncByAge() && projects.size() > nMaxProjects) { - // Immmediately ban the node from which the manifest was received. + // Immediately ban the node from which the manifest was received. banscore_out = GetArg("-banscore", 100); throw error("CScraperManifest::UnserializeCheck: Too many projects in the manifest."); diff --git a/src/scraper_net.h b/src/scraper_net.h index 2e4e1075e9..eab672d38b 100755 --- a/src/scraper_net.h +++ b/src/scraper_net.h @@ -110,7 +110,7 @@ class CScraperManifest /** Add new manifest object into list of known manifests */ static bool addManifest(std::unique_ptr&& m, CKey& keySign); - /** Validate whether recieved manifest is authorized */ + /** Validate whether received manifest is authorized */ static bool IsManifestAuthorized(int64_t& nTime, CPubKey& PubKey, unsigned int& banscore_out); /** Delete Manifest (key version) **/ diff --git a/src/script.cpp b/src/script.cpp index d51ccccdcb..e75bf8264d 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1503,7 +1503,7 @@ int ScriptSigArgsExpected(txnouttype t, const std::vector UTXO) @@ -1612,7 +1612,7 @@ bool CWallet::SelectCoinsForStaking(unsigned int nSpendTime, std::vector(GetAdjustedTime()); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 150687dfce..6aa1dd3916 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -36,7 +36,7 @@ enum WalletFeature FEATURE_LATEST = 60000 }; -/** (POS/POR) enums for CoinStake Transactions -- We should never get unknown but just incase!*/ +/** (POS/POR) enums for CoinStake Transactions -- We should never get unknown but just in case!*/ enum MinedType { UNKNOWN = 0, diff --git a/test/lint/lint-all.sh b/test/lint/lint-all.sh index 737ead4b6e..fabc24c91b 100755 --- a/test/lint/lint-all.sh +++ b/test/lint/lint-all.sh @@ -19,7 +19,6 @@ LINTALL=$(basename "${BASH_SOURCE[0]}") EXIT_CODE=0 for f in "${SCRIPTDIR}"/lint-*.sh; do - echo $f if [ "$(basename "$f")" != "$LINTALL" ]; then if ! "$f"; then echo "^---- failure generated from $f" diff --git a/test/lint/lint-circular-dependencies.sh b/test/lint/lint-circular-dependencies.sh index 6bd02d45ac..64ae407ab1 100755 --- a/test/lint/lint-circular-dependencies.sh +++ b/test/lint/lint-circular-dependencies.sh @@ -9,18 +9,6 @@ export LC_ALL=C EXPECTED_CIRCULAR_DEPENDENCIES=( - "chainparamsbase -> util/system -> chainparamsbase" - "index/txindex -> validation -> index/txindex" - "policy/fees -> txmempool -> policy/fees" - "qt/addresstablemodel -> qt/walletmodel -> qt/addresstablemodel" - "qt/bitcoingui -> qt/walletframe -> qt/bitcoingui" - "qt/recentrequeststablemodel -> qt/walletmodel -> qt/recentrequeststablemodel" - "qt/sendcoinsdialog -> qt/walletmodel -> qt/sendcoinsdialog" - "qt/transactiontablemodel -> qt/walletmodel -> qt/transactiontablemodel" - "txmempool -> validation -> txmempool" - "wallet/fees -> wallet/wallet -> wallet/fees" - "wallet/wallet -> wallet/walletdb -> wallet/wallet" - "policy/fees -> txmempool -> validation -> policy/fees" ) EXIT_CODE=0 diff --git a/test/lint/lint-spelling.ignore-words.txt b/test/lint/lint-spelling.ignore-words.txt index 34f54325b3..2fd77afa25 100644 --- a/test/lint/lint-spelling.ignore-words.txt +++ b/test/lint/lint-spelling.ignore-words.txt @@ -15,3 +15,9 @@ hist ser unselect lowercased +unser +nnumber +keypair +fo +inout +dout diff --git a/test/lint/lint-spelling.sh b/test/lint/lint-spelling.sh index cb84727ba5..07eac6a7df 100755 --- a/test/lint/lint-spelling.sh +++ b/test/lint/lint-spelling.sh @@ -15,6 +15,6 @@ if ! command -v codespell > /dev/null; then fi IGNORE_WORDS_FILE=test/lint/lint-spelling.ignore-words.txt -if ! codespell --check-filenames --disable-colors --quiet-level=7 --ignore-words=${IGNORE_WORDS_FILE} $(git ls-files -- ":(exclude)build-aux/m4/" ":(exclude)contrib/seeds/*.txt" ":(exclude)depends/" ":(exclude)doc/release-notes/" ":(exclude)src/leveldb/" ":(exclude)src/crc32c/" ":(exclude)src/qt/locale/" ":(exclude)src/qt/*.qrc" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/"); then +if ! codespell --check-filenames --disable-colors --quiet-level=7 --ignore-words=${IGNORE_WORDS_FILE} $(git ls-files -- ":(exclude)build-aux/m4/" ":(exclude)contrib/seeds/*.txt" ":(exclude)depends/" ":(exclude)doc/release-notes/" ":(exclude)src/leveldb/" ":(exclude)src/crc32c/" ":(exclude)src/qt/locale/" ":(exclude)src/qt/*.qrc" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/" ":(exclude)contrib/**/*" ":(exclude)contrib/*" ":(exclude)**/*.png"); then echo "^ Warning: codespell identified likely spelling errors. Any false positives? Add them to the list of ignored words in ${IGNORE_WORDS_FILE}" fi From 90768dd5f67f0de33d146f2563d96429c83b600f Mon Sep 17 00:00:00 2001 From: div72 <60045611+div72@users.noreply.github.com> Date: Thu, 13 Aug 2020 20:11:09 +0300 Subject: [PATCH 05/16] Remove newline check --- test/lint/lint-logs.sh | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100755 test/lint/lint-logs.sh diff --git a/test/lint/lint-logs.sh b/test/lint/lint-logs.sh deleted file mode 100755 index 2fbb4a38e7..0000000000 --- a/test/lint/lint-logs.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash -# -# 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. -# -# Check that all logs are terminated with '\n' -# -# Some logs are continued over multiple lines. They should be explicitly -# commented with \* Continued *\ -# -# There are some instances of LogPrintf() in comments. Those can be -# ignored - -export LC_ALL=C -UNTERMINATED_LOGS=$(git grep --extended-regexp "LogPrintf?\(" -- "*.cpp" | \ - grep -v '\\n"' | \ - grep -v '\.\.\.' | \ - grep -v "/\* Continued \*/" | \ - 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}" - exit 1 -fi From a6f5e607212d03206f7d07467d94a1f144131610 Mon Sep 17 00:00:00 2001 From: div72 <60045611+div72@users.noreply.github.com> Date: Thu, 13 Aug 2020 20:15:00 +0300 Subject: [PATCH 06/16] Fix assertion --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 4cb4526db5..865827f155 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2998,7 +2998,7 @@ bool ReorganizeChain(CTxDB& txdb, unsigned &cnt_dis, unsigned &cnt_con, CBlock & assert(pindexNew); //assert(!pindexNew->pnext); //assert(pindexBest || hashBestChain == pindexBest->GetBlockHash()); - //assert(nBestHeight = pindexBest->nHeight && nBestChainTrust == pindexBest->nChainTrust); + //assert(nBestHeight == pindexBest->nHeight && nBestChainTrust == pindexBest->nChainTrust); //assert(!pindexBest->pnext); assert(pindexNew->GetBlockHash()==blockNew.GetHash(true)); /* note: it was already determined that this chain is better than current best */ From a36678b0b29e9af5f2a8b725c3d5a025ca44920c Mon Sep 17 00:00:00 2001 From: div72 <60045611+div72@users.noreply.github.com> Date: Thu, 13 Aug 2020 20:28:23 +0300 Subject: [PATCH 07/16] Disable some include checks --- test/lint/lint-includes.sh | 56 ++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/test/lint/lint-includes.sh b/test/lint/lint-includes.sh index fde77aea2d..4c872564a9 100755 --- a/test/lint/lint-includes.sh +++ b/test/lint/lint-includes.sh @@ -77,38 +77,30 @@ EXPECTED_BOOST_INCLUDES=( boost/variant/static_visitor.hpp ) -for BOOST_INCLUDE in $(git grep '^#include ' | sort -u); do - IS_EXPECTED_INCLUDE=0 - for EXPECTED_BOOST_INCLUDE in "${EXPECTED_BOOST_INCLUDES[@]}"; do - if [[ "${BOOST_INCLUDE}" == "${EXPECTED_BOOST_INCLUDE}" ]]; then - IS_EXPECTED_INCLUDE=1 - break - fi - done - if [[ ${IS_EXPECTED_INCLUDE} == 0 ]]; then - EXIT_CODE=1 - echo "A new Boost dependency in the form of \"${BOOST_INCLUDE}\" appears to have been introduced:" - git grep "${BOOST_INCLUDE}" -- "*.cpp" "*.h" - echo - fi -done - -for EXPECTED_BOOST_INCLUDE in "${EXPECTED_BOOST_INCLUDES[@]}"; do - if ! git grep -q "^#include <${EXPECTED_BOOST_INCLUDE}>" -- "*.cpp" "*.h"; then - echo "Good job! The Boost dependency \"${EXPECTED_BOOST_INCLUDE}\" is no longer used." - echo "Please remove it from EXPECTED_BOOST_INCLUDES in $0" - echo "to make sure this dependency is not accidentally reintroduced." - echo - EXIT_CODE=1 - fi -done +#for BOOST_INCLUDE in $(git grep '^#include ' | sort -u); do +# IS_EXPECTED_INCLUDE=0 +# for EXPECTED_BOOST_INCLUDE in "${EXPECTED_BOOST_INCLUDES[@]}"; do +# if [[ "${BOOST_INCLUDE}" == "${EXPECTED_BOOST_INCLUDE}" ]]; then +# IS_EXPECTED_INCLUDE=1 +# break +# fi +# done +# if [[ ${IS_EXPECTED_INCLUDE} == 0 ]]; then +# EXIT_CODE=1 +# echo "A new Boost dependency in the form of \"${BOOST_INCLUDE}\" appears to have been introduced:" +# git grep "${BOOST_INCLUDE}" -- "*.cpp" "*.h" +# echo +# fi +#done -QUOTE_SYNTAX_INCLUDES=$(git grep '^#include "' -- "*.cpp" "*.h" | grep -Ev "${IGNORE_REGEXP}") -if [[ ${QUOTE_SYNTAX_INCLUDES} != "" ]]; then - echo "Please use bracket syntax includes (\"#include \") instead of quote syntax includes:" - echo "${QUOTE_SYNTAX_INCLUDES}" - echo - EXIT_CODE=1 -fi +#for EXPECTED_BOOST_INCLUDE in "${EXPECTED_BOOST_INCLUDES[@]}"; do +# if ! git grep -q "^#include <${EXPECTED_BOOST_INCLUDE}>" -- "*.cpp" "*.h"; then +# echo "Good job! The Boost dependency \"${EXPECTED_BOOST_INCLUDE}\" is no longer used." +# echo "Please remove it from EXPECTED_BOOST_INCLUDES in $0" +# echo "to make sure this dependency is not accidentally reintroduced." +# echo +# EXIT_CODE=1 +# fi +#done exit ${EXIT_CODE} From 3aaacf1767a88b62f2ebec2fcdf0741de7056c00 Mon Sep 17 00:00:00 2001 From: div72 <60045611+div72@users.noreply.github.com> Date: Thu, 13 Aug 2020 20:39:14 +0300 Subject: [PATCH 08/16] Rename tests --- src/Makefile.test.include | 6 +++--- src/test/{Checkpoints_tests.cpp => checkpoints_tests.cpp} | 0 src/test/{DoS_tests.cpp => dos_tests.cpp} | 0 src/test/{script_P2SH_tests.cpp => script_p2sh_tests.cpp} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename src/test/{Checkpoints_tests.cpp => checkpoints_tests.cpp} (100%) rename src/test/{DoS_tests.cpp => dos_tests.cpp} (100%) rename src/test/{script_P2SH_tests.cpp => script_p2sh_tests.cpp} (100%) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 36dcc8c891..e31de7450a 100755 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -24,8 +24,8 @@ OTHER_TEST_FILES = \ # test_n binary # GRIDCOIN_TESTS =\ test/appcache_tests.cpp \ - test/Checkpoints_tests.cpp \ - test/DoS_tests.cpp \ + test/checkpoints_tests.cpp \ + test/dos_tests.cpp \ test/accounting_tests.cpp \ test/allocator_tests.cpp \ test/base32_tests.cpp \ @@ -50,7 +50,7 @@ GRIDCOIN_TESTS =\ test/neuralnet/researcher_tests.cpp \ test/neuralnet/superblock_tests.cpp \ test/rpc_tests.cpp \ - test/script_P2SH_tests.cpp \ + test/script_p2sh_tests.cpp \ test/script_tests.cpp \ test/serialize_tests.cpp \ test/sigopcount_tests.cpp \ diff --git a/src/test/Checkpoints_tests.cpp b/src/test/checkpoints_tests.cpp similarity index 100% rename from src/test/Checkpoints_tests.cpp rename to src/test/checkpoints_tests.cpp diff --git a/src/test/DoS_tests.cpp b/src/test/dos_tests.cpp similarity index 100% rename from src/test/DoS_tests.cpp rename to src/test/dos_tests.cpp diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_p2sh_tests.cpp similarity index 100% rename from src/test/script_P2SH_tests.cpp rename to src/test/script_p2sh_tests.cpp From 905fe154edbc76f6bfc251514aba3761b12e2b74 Mon Sep 17 00:00:00 2001 From: div72 <60045611+div72@users.noreply.github.com> Date: Thu, 13 Aug 2020 20:42:34 +0300 Subject: [PATCH 09/16] Disable rpc help check --- test/lint/{lint-rpc-help.sh => 0lint-rpc-help.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/lint/{lint-rpc-help.sh => 0lint-rpc-help.sh} (100%) diff --git a/test/lint/lint-rpc-help.sh b/test/lint/0lint-rpc-help.sh similarity index 100% rename from test/lint/lint-rpc-help.sh rename to test/lint/0lint-rpc-help.sh From 55e77610cec8577f41a90dde494d65878d8955f4 Mon Sep 17 00:00:00 2001 From: div72 <60045611+div72@users.noreply.github.com> Date: Thu, 13 Aug 2020 20:51:29 +0300 Subject: [PATCH 10/16] Remove bitrpc --- contrib/bitrpc/bitrpc.py | 324 --------------------------------------- 1 file changed, 324 deletions(-) delete mode 100755 contrib/bitrpc/bitrpc.py diff --git a/contrib/bitrpc/bitrpc.py b/contrib/bitrpc/bitrpc.py deleted file mode 100755 index b02b299177..0000000000 --- a/contrib/bitrpc/bitrpc.py +++ /dev/null @@ -1,324 +0,0 @@ -from jsonrpc import ServiceProxy -import sys -import string - -# ===== BEGIN USER SETTINGS ===== -# if you do not set these you will be prompted for a password for every command -rpcuser = "" -rpcpass = "" -# ====== END USER SETTINGS ====== - - -if rpcpass == "": - access = ServiceProxy("http://127.0.0.1:8332") -else: - access = ServiceProxy("http://"+rpcuser+":"+rpcpass+"@127.0.0.1:8332") -cmd = sys.argv[1].lower() - -if cmd == "backupwallet": - try: - path = raw_input("Enter destination path/filename: ") - print access.backupwallet(path) - except: - print "\n---An error occurred---\n" - -elif cmd == "getaccount": - try: - addr = raw_input("Enter a Bitcoin address: ") - print access.getaccount(addr) - except: - print "\n---An error occurred---\n" - -elif cmd == "getaccountaddress": - try: - acct = raw_input("Enter an account name: ") - print access.getaccountaddress(acct) - except: - print "\n---An error occurred---\n" - -elif cmd == "getaddressesbyaccount": - try: - acct = raw_input("Enter an account name: ") - print access.getaddressesbyaccount(acct) - except: - print "\n---An error occurred---\n" - -elif cmd == "getbalance": - try: - acct = raw_input("Enter an account (optional): ") - mc = raw_input("Minimum confirmations (optional): ") - try: - print access.getbalance(acct, mc) - except: - print access.getbalance() - except: - print "\n---An error occurred---\n" - -elif cmd == "getblockbycount": - try: - height = raw_input("Height: ") - print access.getblockbycount(height) - except: - print "\n---An error occurred---\n" - -elif cmd == "getblockcount": - try: - print access.getblockcount() - except: - print "\n---An error occurred---\n" - -elif cmd == "getblocknumber": - try: - print access.getblocknumber() - except: - print "\n---An error occurred---\n" - -elif cmd == "getconnectioncount": - try: - print access.getconnectioncount() - except: - print "\n---An error occurred---\n" - -elif cmd == "getdifficulty": - try: - print access.getdifficulty() - except: - print "\n---An error occurred---\n" - -elif cmd == "getgenerate": - try: - print access.getgenerate() - except: - print "\n---An error occurred---\n" - -elif cmd == "gethashespersec": - try: - print access.gethashespersec() - except: - print "\n---An error occurred---\n" - -elif cmd == "getinfo": - try: - print access.getinfo() - except: - print "\n---An error occurred---\n" - -elif cmd == "getnewaddress": - try: - acct = raw_input("Enter an account name: ") - try: - print access.getnewaddress(acct) - except: - print access.getnewaddress() - except: - print "\n---An error occurred---\n" - -elif cmd == "getreceivedbyaccount": - try: - acct = raw_input("Enter an account (optional): ") - mc = raw_input("Minimum confirmations (optional): ") - try: - print access.getreceivedbyaccount(acct, mc) - except: - print access.getreceivedbyaccount() - except: - print "\n---An error occurred---\n" - -elif cmd == "getreceivedbyaddress": - try: - addr = raw_input("Enter a Bitcoin address (optional): ") - mc = raw_input("Minimum confirmations (optional): ") - try: - print access.getreceivedbyaddress(addr, mc) - except: - print access.getreceivedbyaddress() - except: - print "\n---An error occurred---\n" - -elif cmd == "gettransaction": - try: - txid = raw_input("Enter a transaction ID: ") - print access.gettransaction(txid) - except: - print "\n---An error occurred---\n" - -elif cmd == "getwork": - try: - data = raw_input("Data (optional): ") - try: - print access.gettransaction(data) - except: - print access.gettransaction() - except: - print "\n---An error occurred---\n" - -elif cmd == "help": - try: - cmd = raw_input("Command (optional): ") - try: - print access.help(cmd) - except: - print access.help() - except: - print "\n---An error occurred---\n" - -elif cmd == "listaccounts": - try: - mc = raw_input("Minimum confirmations (optional): ") - try: - print access.listaccounts(mc) - except: - print access.listaccounts() - except: - print "\n---An error occurred---\n" - -elif cmd == "listreceivedbyaccount": - try: - mc = raw_input("Minimum confirmations (optional): ") - incemp = raw_input("Include empty? (true/false, optional): ") - try: - print access.listreceivedbyaccount(mc, incemp) - except: - print access.listreceivedbyaccount() - except: - print "\n---An error occurred---\n" - -elif cmd == "listreceivedbyaddress": - try: - mc = raw_input("Minimum confirmations (optional): ") - incemp = raw_input("Include empty? (true/false, optional): ") - try: - print access.listreceivedbyaddress(mc, incemp) - except: - print access.listreceivedbyaddress() - except: - print "\n---An error occurred---\n" - -elif cmd == "listtransactions": - try: - acct = raw_input("Account (optional): ") - count = raw_input("Number of transactions (optional): ") - frm = raw_input("Skip (optional):") - try: - print access.listtransactions(acct, count, frm) - except: - print access.listtransactions() - except: - print "\n---An error occurred---\n" - -elif cmd == "move": - try: - frm = raw_input("From: ") - to = raw_input("To: ") - amt = raw_input("Amount:") - mc = raw_input("Minimum confirmations (optional): ") - comment = raw_input("Comment (optional): ") - try: - print access.move(frm, to, amt, mc, comment) - except: - print access.move(frm, to, amt) - except: - print "\n---An error occurred---\n" - -elif cmd == "sendfrom": - try: - frm = raw_input("From: ") - to = raw_input("To: ") - amt = raw_input("Amount:") - mc = raw_input("Minimum confirmations (optional): ") - comment = raw_input("Comment (optional): ") - commentto = raw_input("Comment-to (optional): ") - try: - print access.sendfrom(frm, to, amt, mc, comment, commentto) - except: - print access.sendfrom(frm, to, amt) - except: - print "\n---An error occurred---\n" - -elif cmd == "sendmany": - try: - frm = raw_input("From: ") - to = raw_input("To (in format address1:amount1,address2:amount2,...): ") - mc = raw_input("Minimum confirmations (optional): ") - comment = raw_input("Comment (optional): ") - try: - print access.sendmany(frm,to,mc,comment) - except: - print access.sendmany(frm,to) - except: - print "\n---An error occurred---\n" - -elif cmd == "sendtoaddress": - try: - to = raw_input("To (in format address1:amount1,address2:amount2,...): ") - amt = raw_input("Amount:") - comment = raw_input("Comment (optional): ") - commentto = raw_input("Comment-to (optional): ") - try: - print access.sendtoaddress(to,amt,comment,commentto) - except: - print access.sendtoaddress(to,amt) - except: - print "\n---An error occurred---\n" - -elif cmd == "setaccount": - try: - addr = raw_input("Address: ") - acct = raw_input("Account:") - print access.setaccount(addr,acct) - except: - print "\n---An error occurred---\n" - -elif cmd == "setgenerate": - try: - gen= raw_input("Generate? (true/false): ") - cpus = raw_input("Max processors/cores (-1 for unlimited, optional):") - try: - print access.setgenerate(gen, cpus) - except: - print access.setgenerate(gen) - except: - print "\n---An error occurred---\n" - -elif cmd == "settxfee": - try: - amt = raw_input("Amount:") - print access.settxfee(amt) - except: - print "\n---An error occurred---\n" - -elif cmd == "stop": - try: - print access.stop() - except: - print "\n---An error occurred---\n" - -elif cmd == "validateaddress": - try: - addr = raw_input("Address: ") - print access.validateaddress(addr) - except: - print "\n---An error occurred---\n" - -elif cmd == "walletpassphrase": - try: - pwd = raw_input("Enter wallet passphrase: ") - access.walletpassphrase(pwd, 60) - print "\n---Wallet unlocked---\n" - except: - print "\n---An error occurred---\n" - -elif cmd == "walletpassphrasechange": - try: - pwd = raw_input("Enter old wallet passphrase: ") - pwd2 = raw_input("Enter new wallet passphrase: ") - access.walletpassphrasechange(pwd, pwd2) - print - print "\n---Passphrase changed---\n" - except: - print - print "\n---An error occurred---\n" - print - -else: - print "Command not found or not supported" \ No newline at end of file From c61d073991152773b27829d47c64868033e08b13 Mon Sep 17 00:00:00 2001 From: div72 <60045611+div72@users.noreply.github.com> Date: Thu, 13 Aug 2020 20:58:40 +0300 Subject: [PATCH 11/16] Fix shell files and shebangs --- contrib/gitian-build.sh | 1 + contrib/macdeploy/custom_dsstore.py | 2 +- contrib/macdeploy/detached-sig-apply.sh | 2 ++ contrib/macdeploy/detached-sig-create.sh | 2 ++ contrib/qt_translations.py | 4 ++-- contrib/rpcstresstest/rpc_stress_test.sh | 4 +++- share/genbuild.sh | 2 ++ share/qt/extract_strings_qt.py | 2 +- share/qt/make_spinner.py | 6 ++---- share/qt/make_windows_icon.sh | 3 ++- 10 files changed, 18 insertions(+), 10 deletions(-) diff --git a/contrib/gitian-build.sh b/contrib/gitian-build.sh index 47a8604845..93b7d35af6 100755 --- a/contrib/gitian-build.sh +++ b/contrib/gitian-build.sh @@ -1,3 +1,4 @@ +#!/usr/bin/env bash # Copyright (c) 2016 The gridcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/contrib/macdeploy/custom_dsstore.py b/contrib/macdeploy/custom_dsstore.py index e6ecabace1..686160234c 100755 --- a/contrib/macdeploy/custom_dsstore.py +++ b/contrib/macdeploy/custom_dsstore.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2013-2016 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/contrib/macdeploy/detached-sig-apply.sh b/contrib/macdeploy/detached-sig-apply.sh index 91674a92e6..4325de1765 100755 --- a/contrib/macdeploy/detached-sig-apply.sh +++ b/contrib/macdeploy/detached-sig-apply.sh @@ -3,6 +3,8 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. +export LC_ALL=C + set -e UNSIGNED="$1" diff --git a/contrib/macdeploy/detached-sig-create.sh b/contrib/macdeploy/detached-sig-create.sh index 5022ea88bc..0667f214dc 100755 --- a/contrib/macdeploy/detached-sig-create.sh +++ b/contrib/macdeploy/detached-sig-create.sh @@ -3,6 +3,8 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. +export LC_ALL=C + set -e ROOTDIR=dist diff --git a/contrib/qt_translations.py b/contrib/qt_translations.py index fd8a8b7129..aa044c56c7 100755 --- a/contrib/qt_translations.py +++ b/contrib/qt_translations.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Helpful little script that spits out a comma-separated list of # language codes for Qt icons that should be included @@ -18,5 +18,5 @@ l1 = set([ re.search(r'qt_(.*).qm', f).group(1) for f in glob.glob(os.path.join(d1, 'qt_*.qm')) ]) l2 = set([ re.search(r'bitcoin_(.*).qm', f).group(1) for f in glob.glob(os.path.join(d2, 'bitcoin_*.qm')) ]) -print ",".join(sorted(l1.intersection(l2))) +print(",".join(sorted(l1.intersection(l2)))) diff --git a/contrib/rpcstresstest/rpc_stress_test.sh b/contrib/rpcstresstest/rpc_stress_test.sh index aecf3f6595..707c1207eb 100755 --- a/contrib/rpcstresstest/rpc_stress_test.sh +++ b/contrib/rpcstresstest/rpc_stress_test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Author James C. Owens # Version 2.5 - includes datetime stamps in UTC and also puts in output log and debug.log @@ -6,6 +6,8 @@ # Version 3.5 - includes parallelism counter (j) and parallelism limiter # Version 4.0 - Parameterize rpc_test_output.log and debug.log locations +export LC_ALL=C + timestamp() { date --utc +"%m/%d/%Y %H:%M:%S.%N" } diff --git a/share/genbuild.sh b/share/genbuild.sh index 73d5cd883a..bba299a5d4 100755 --- a/share/genbuild.sh +++ b/share/genbuild.sh @@ -1,5 +1,7 @@ #!/bin/sh +export LC_ALL=C + if [ $# -gt 0 ]; then FILE="$1" shift diff --git a/share/qt/extract_strings_qt.py b/share/qt/extract_strings_qt.py index 5492fdb8c5..672993b35d 100755 --- a/share/qt/extract_strings_qt.py +++ b/share/qt/extract_strings_qt.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2012-2016 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/share/qt/make_spinner.py b/share/qt/make_spinner.py index 136aff3cb7..5b66d3096a 100755 --- a/share/qt/make_spinner.py +++ b/share/qt/make_spinner.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # W.J. van der Laan, 2011 # Make spinning .mng animation from a .png # Requires imagemagick 6.7+ @@ -26,7 +26,7 @@ def frame_to_filename(frame): return path.join(TMPDIR, TMPNAME % frame) frame_files = [] -for frame in xrange(NUMFRAMES): +for frame in range(NUMFRAMES): rotation = (frame + 0.5) / NUMFRAMES * 360.0 if CLOCKWISE: rotation = -rotation @@ -39,5 +39,3 @@ def frame_to_filename(frame): p = Popen([CONVERT, "-delay", str(FRAMERATE), "-dispose", "2"] + frame_files + [DST]) p.communicate() - - diff --git a/share/qt/make_windows_icon.sh b/share/qt/make_windows_icon.sh index f775a30580..97f795d30e 100755 --- a/share/qt/make_windows_icon.sh +++ b/share/qt/make_windows_icon.sh @@ -1,5 +1,6 @@ -#!/bin/bash +#!/usr/bin/env bash # create multiresolution windows icon +export LC_ALL=C ICON_DST=../../src/qt/res/icons/novacoin.ico convert ../../src/qt/res/icons/novacoin-16.png ../../src/qt/res/icons/novacoin-32.png ../../src/qt/res/icons/novacoin-48.png ${ICON_DST} From 5759295aaab35d9a33f68cddf2ce35f0661dcf1f Mon Sep 17 00:00:00 2001 From: div72 <60045611+div72@users.noreply.github.com> Date: Thu, 13 Aug 2020 21:02:15 +0300 Subject: [PATCH 12/16] Update autogen.sh --- autogen.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/autogen.sh b/autogen.sh index 27417daf76..de16260b56 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,15 +1,16 @@ #!/bin/sh -# Copyright (c) 2013-2016 The Bitcoin Core developers +# Copyright (c) 2013-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 set -e -srcdir="$(dirname $0)" +srcdir="$(dirname "$0")" cd "$srcdir" -if [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE="`which glibtoolize 2>/dev/null`"; then +if [ -z "${LIBTOOLIZE}" ] && GLIBTOOLIZE="$(command -v glibtoolize)"; then LIBTOOLIZE="${GLIBTOOLIZE}" export LIBTOOLIZE fi -which autoreconf >/dev/null || \ +command -v autoreconf >/dev/null || \ (echo "configuration failed, please install autoconf first" && exit 1) autoreconf --install --force --warnings=all From 7181af4941c5f4ffada498c3a5651aac68196fac Mon Sep 17 00:00:00 2001 From: Cy Rossignol Date: Fri, 14 Aug 2020 21:10:21 -0500 Subject: [PATCH 13/16] Allow use of "#pragma once" as an include guard for lint Most Gridcoin-specific headers use "#pragma once" as an include guard. This changes the lint rules to allow "#pragma once" in addition to the standard "#ifndef"/"#define" macro guards. --- test/lint/lint-include-guards.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/lint/lint-include-guards.sh b/test/lint/lint-include-guards.sh index 5d5a150db8..98cfd93f43 100755 --- a/test/lint/lint-include-guards.sh +++ b/test/lint/lint-include-guards.sh @@ -10,11 +10,16 @@ export LC_ALL=C HEADER_ID_PREFIX="BITCOIN_" HEADER_ID_SUFFIX="_H" -REGEXP_EXCLUDE_FILES_WITH_PREFIX="src/(crypto/ctaes/|leveldb/|crc32c/|secp256k1/|test/fuzz/FuzzedDataProvider.h|tinyformat.h|bench/nanobench.h|univalue/)" +REGEXP_EXCLUDE_FILES_WITH_PREFIX="src/(crypto/ctaes/|leveldb/|crc32c/|secp256k1/|test/(data|fuzz/FuzzedDataProvider.h)|tinyformat.h|bench/nanobench.h|univalue/)" EXIT_CODE=0 for HEADER_FILE in $(git ls-files -- "*.h" | grep -vE "^${REGEXP_EXCLUDE_FILES_WITH_PREFIX}") do + # Gridcoin: allow use of the #pragma once directive as an include guard: + if grep -cE "^#pragma once" "${HEADER_FILE}" > /dev/null; then + continue + fi + HEADER_ID_BASE=$(cut -f2- -d/ <<< "${HEADER_FILE}" | sed "s/\.h$//g" | tr / _ | tr "[:lower:]" "[:upper:]") HEADER_ID="${HEADER_ID_PREFIX}${HEADER_ID_BASE}${HEADER_ID_SUFFIX}" if [[ $(grep -cE "^#(ifndef|define) ${HEADER_ID}" "${HEADER_FILE}") != 2 ]]; then From a82f8f51f923519407640eb8c5e540d1c101302a Mon Sep 17 00:00:00 2001 From: Cy Rossignol Date: Fri, 14 Aug 2020 21:43:05 -0500 Subject: [PATCH 14/16] Allow CI failures for lint job temporarily This allows the lint job to fail without invalidating a build so that we can address unfinished lint violations incrementally. --- .travis.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 27ce7cf260..dc3fb3c3c6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,7 +48,8 @@ script: after_script: - echo $TRAVIS_COMMIT_RANGE jobs: - include: + fast_finish: true + allow_failures: - stage: lint name: 'lint' env: @@ -62,13 +63,14 @@ jobs: script: - set -o errexit; source ./ci/lint/06_script.sh + include: - stage: test name: 'ARM [GOAL: install] [buster]' arch: arm64 # Can disable QEMU_USER_CMD and run the tests natively without qemu env: >- FILE_ENV="./ci/test/00_setup_env_arm.sh" QEMU_USER_CMD="" - + - stage: test name: 'Win32' env: >- From b820633c52785df0319850c17e59706374fa0ec5 Mon Sep 17 00:00:00 2001 From: div72 <60045611+div72@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:24:33 +0300 Subject: [PATCH 15/16] Re-enable lint job --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index dc3fb3c3c6..38901feddb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,6 +51,9 @@ jobs: fast_finish: true allow_failures: - stage: lint + + include: + - stage: lint name: 'lint' env: cache: pip @@ -63,7 +66,6 @@ jobs: script: - set -o errexit; source ./ci/lint/06_script.sh - include: - stage: test name: 'ARM [GOAL: install] [buster]' arch: arm64 # Can disable QEMU_USER_CMD and run the tests natively without qemu From 857d1e04090bac778bccb1c16bc2508adea0119d Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Wed, 19 Aug 2020 21:02:34 -0400 Subject: [PATCH 16/16] Update test/lint/lint-spelling.ignore-words.txt Co-authored-by: Cy Rossignol --- test/lint/lint-spelling.ignore-words.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/lint/lint-spelling.ignore-words.txt b/test/lint/lint-spelling.ignore-words.txt index 2fd77afa25..8a5bee56b0 100644 --- a/test/lint/lint-spelling.ignore-words.txt +++ b/test/lint/lint-spelling.ignore-words.txt @@ -17,7 +17,5 @@ unselect lowercased unser nnumber -keypair fo -inout dout