diff --git a/.arclint b/.arclint
index d7a858295..3d5f09f0f 100644
--- a/.arclint
+++ b/.arclint
@@ -1,292 +1,292 @@
 {
     "linters": {
         "generated": {
             "type": "generated"
         },
         "clang-format": {
             "type": "clang-format",
-            "version": ">=10.0",
-            "bin": ["clang-format-10", "clang-format"],
+            "version": ">=11.0",
+            "bin": ["clang-format-11", "clang-format"],
             "include": "(^src/.*\\.(h|c|cpp|mm)$)",
             "exclude": [
                 "(^src/(secp256k1|univalue|leveldb)/)",
                 "(^src/bench/nanobench.h$)"
             ]
         },
         "autopep8": {
             "type": "autopep8",
             "version": ">=1.3.4",
             "include": "(\\.py$)",
             "exclude": [
                 "(^contrib/gitian-builder/)",
                 "(^contrib/apple-sdk-tools/)"
             ],
             "flags": [
                 "--aggressive",
                 "--ignore=W503,W504"
             ]
         },
         "flake8": {
             "type": "flake8",
             "version": ">=3.0",
             "include": "(\\.py$)",
             "exclude": [
                 "(^contrib/gitian-builder/)",
                 "(^contrib/apple-sdk-tools/)"
             ],
             "flags": [
                 "--ignore=E303,E305,E501,E704,W503,W504"
             ]
         },
         "lint-format-strings": {
             "type": "lint-format-strings",
             "include": "(^src/.*\\.(h|c|cpp)$)",
             "exclude": [
                 "(^src/(secp256k1|univalue|leveldb)/)",
                 "(^src/bench/nanobench.h$)",
                 "(^src/test/fuzz/strprintf.cpp$)"
             ]
         },
         "check-doc": {
             "type": "check-doc",
             "include": "(^src/.*\\.(h|c|cpp)$)"
         },
         "lint-tests": {
             "type": "lint-tests",
             "include": "(^src/(seeder/|rpc/|wallet/)?test/.*\\.(cpp)$)"
         },
         "lint-python-format": {
             "type": "lint-python-format",
             "include": "(\\.py$)",
             "exclude": [
                 "(^test/lint/lint-python-format\\.py$)",
                 "(^contrib/gitian-builder/)",
                 "(^contrib/apple-sdk-tools/)"
             ]
         },
         "phpcs": {
             "type": "phpcs",
             "include": "(\\.php$)",
             "exclude": [
                 "(^arcanist/__phutil_library_.+\\.php$)"
             ],
             "phpcs.standard": "arcanist/phpcs.xml"
         },
         "lint-locale-dependence": {
             "type": "lint-locale-dependence",
             "include": "(^src/.*\\.(h|cpp)$)",
             "exclude": [
                 "(^src/(crypto/ctaes/|leveldb/|secp256k1/|tinyformat.h|univalue/))",
                 "(^src/bench/nanobench.h$)"
             ]
         },
         "lint-cheader": {
             "type": "lint-cheader",
             "include": "(^src/.*\\.(h|cpp)$)",
             "exclude": [
                 "(^src/(crypto/ctaes|secp256k1|univalue|leveldb)/)",
                 "(^src/bench/nanobench.h$)"
             ]
         },
         "spelling": {
             "type": "spelling",
             "exclude": [
                 "(^build-aux/m4/)",
                 "(^depends/)",
                 "(^doc/release-notes/)",
                 "(^contrib/gitian-builder/)",
                 "(^src/(qt/locale|secp256k1|univalue|leveldb)/)",
                 "(^test/lint/dictionary/)"
             ],
             "spelling.dictionaries": [
                 "test/lint/dictionary/english.json"
             ]
         },
         "lint-assert-with-side-effects": {
             "type": "lint-assert-with-side-effects",
             "include": "(^src/.*\\.(h|cpp)$)",
             "exclude": [
                 "(^src/(secp256k1|univalue|leveldb)/)",
                 "(^src/bench/nanobench.h$)"
             ]
         },
         "lint-include-quotes": {
             "type": "lint-include-quotes",
             "include": "(^src/.*\\.(h|cpp)$)",
             "exclude": [
                 "(^src/(secp256k1|univalue|leveldb)/)",
                 "(^src/bench/nanobench.h$)"
             ]
         },
         "lint-include-guard": {
             "type": "lint-include-guard",
             "include": "(^src/.*\\.h$)",
             "exclude": [
                 "(^src/(crypto/ctaes|secp256k1|univalue|leveldb)/)",
                 "(^src/bench/nanobench.h$)",
                 "(^src/tinyformat.h$)"
             ]
         },
         "lint-include-source": {
             "type": "lint-include-source",
             "include": "(^src/.*\\.(h|c|cpp)$)",
             "exclude": [
                 "(^src/(secp256k1|univalue|leveldb)/)",
                 "(^src/bench/nanobench.h$)"
             ]
         },
         "lint-stdint": {
             "type": "lint-stdint",
             "include": "(^src/.*\\.(h|c|cpp)$)",
             "exclude": [
                 "(^src/(secp256k1|univalue|leveldb)/)",
                 "(^src/bench/nanobench.h$)",
                 "(^src/compat/assumptions.h$)"
             ]
         },
         "lint-source-filename": {
             "type": "lint-source-filename",
             "include": "(^src/.*\\.(h|c|cpp)$)",
             "exclude": [
                 "(^src/(secp256k1|univalue|leveldb)/)",
                 "(^src/bench/nanobench.h$)"
             ]
         },
         "lint-boost-dependencies": {
             "type": "lint-boost-dependencies",
             "include": "(^src/.*\\.(h|cpp)$)"
         },
         "lint-python-encoding": {
             "type": "lint-python-encoding",
             "include": "(\\.py$)",
             "exclude": [
                 "(^contrib/gitian-builder/)",
                 "(^contrib/apple-sdk-tools/)"
             ]
         },
         "lint-python-shebang": {
             "type": "lint-python-shebang",
             "include": "(\\.py$)",
             "exclude": [
                 "(__init__\\.py$)",
                 "(^contrib/gitian-builder/)",
                 "(^contrib/apple-sdk-tools/)"
             ]
         },
         "lint-bash-shebang": {
             "type": "lint-bash-shebang",
             "include": "(\\.sh$)",
             "exclude": [
                 "(^contrib/gitian-builder/)"
             ]
         },
         "shellcheck": {
             "type": "shellcheck",
             "version": ">=0.7.0",
             "flags": [
                 "--external-sources",
                 "--source-path=SCRIPTDIR"
             ],
             "include": "(\\.sh$)",
             "exclude": [
                 "(^contrib/gitian-builder/)",
                 "(^src/(secp256k1|univalue)/)"
             ]
         },
         "lint-shell-locale": {
             "type": "lint-shell-locale",
             "include": "(\\.sh$)",
             "exclude": [
                 "(^contrib/gitian-builder/)",
                 "(^src/(secp256k1|univalue)/)",
                 "(^cmake/utils/log-and-print-on-failure.sh)"
             ]
         },
         "lint-cpp-void-parameters": {
             "type": "lint-cpp-void-parameters",
             "include": "(^src/.*\\.(h|cpp)$)",
             "exclude": [
                 "(^src/(crypto/ctaes|secp256k1|univalue|leveldb)/)",
                 "(^src/bench/nanobench.h$)",
                 "(^src/compat/glibc_compat.cpp$)"
             ]
         },
         "lint-logs": {
             "type": "lint-logs",
             "include": "(^src/.*\\.(h|cpp)$)"
         },
         "lint-qt": {
             "type": "lint-qt",
             "include": "(^src/qt/.*\\.(h|cpp)$)",
             "exclude": [
                 "(^src/qt/(locale|forms|res)/)"
             ]
         },
         "lint-doxygen": {
             "type": "lint-doxygen",
             "include": "(^src/.*\\.(h|c|cpp)$)",
             "exclude": [
                 "(^src/(crypto/ctaes|secp256k1|univalue|leveldb)/)",
                 "(^src/bench/nanobench.h$)"
             ]
         },
         "lint-whitespace": {
             "type": "lint-whitespace",
             "include": "(\\.(ac|am|cmake|conf|in|include|json|m4|md|openrc|php|pl|sh|txt|yml)$)",
             "exclude": [
                 "(^contrib/gitian-builder/)",
                 "(^src/(secp256k1|univalue|leveldb)/)",
                 "(^src/bench/nanobench.h$)"
             ]
         },
         "yamllint": {
             "type": "yamllint",
             "include": "(\\.(yml|yaml)$)",
             "exclude": "(^src/(secp256k1|univalue|leveldb)/)"
         },
         "lint-check-nonfatal": {
             "type": "lint-check-nonfatal",
             "include": [
                 "(^src/rpc/.*\\.(h|c|cpp)$)",
                 "(^src/wallet/rpc*.*\\.(h|c|cpp)$)"
             ],
             "exclude": "(^src/rpc/server.cpp)"
         },
         "lint-markdown": {
             "type": "lint-markdown",
             "include": [
                 "(\\.md$)"
             ],
             "exclude": "(^contrib/gitian-builder/)"
         },
         "lint-python-mypy": {
             "type": "lint-python-mypy",
             "version": ">=0.780",
             "include": "(\\.py$)",
             "exclude": "(^contrib/)",
             "flags": [
                 "--ignore-missing-imports"
             ]
         },
         "lint-python-mutable-default": {
             "type": "lint-python-mutable-default",
             "include": "(\\.py$)",
             "exclude": [
                 "(^contrib/gitian-builder/)",
                 "(^contrib/apple-sdk-tools/)"
             ]
         },
         "prettier": {
             "type": "prettier",
             "version":">=2.4.1",
             "include": "(^web/.*\\.(css|html|js|json|jsx|md|scss|ts|tsx)$)",
             "exclude": "(^web/.*/translations/.*\\.json$)"
         },
         "lint-python-isort": {
             "type": "lint-python-isort",
             "version": ">=5.6.4",
             "include": "(\\.py$)",
             "exclude": "(^contrib/)"
         }
     }
 }
diff --git a/arcanist/linter/ClangFormatLinter.php b/arcanist/linter/ClangFormatLinter.php
index 323f6020c..da1a8ef75 100644
--- a/arcanist/linter/ClangFormatLinter.php
+++ b/arcanist/linter/ClangFormatLinter.php
@@ -1,104 +1,104 @@
 <?php
 
 /**
  * Uses the clang format to format C/C++/Obj-C code
  */
 final class ClangFormatLinter extends ArcanistExternalLinter {
 
   public function getInfoName() {
     return 'clang-format';
   }
 
   public function getInfoURI() {
     return '';
   }
 
   public function getInfoDescription() {
     return pht('Use clang-format for processing specified files.');
   }
 
   public function getLinterName() {
     return 'clang-format';
   }
 
   public function getLinterConfigurationName() {
     return 'clang-format';
   }
 
   public function getLinterConfigurationOptions() {
     $options = array();
     return $options + parent::getLinterConfigurationOptions();
   }
 
   public function getDefaultBinary() {
     return 'clang-format';
   }
 
   public function getVersion() {
     list($stdout) = execx('%C -version', $this->getExecutableCommand());
 
     $matches = array();
     $regex = '/^clang-format version (?P<version>\d+\.\d+)\./';
     if (preg_match($regex, $stdout, $matches)) {
       $version = $matches['version'];
     } else {
       return false;
     }
 
     /*
      * FIXME: This is a hack to only allow for clang-format version 10.x.
      * The .arclint `version` field only allow to filter versions using `=`,
      * `>`, `<`, `>=` or `<=`. There is no facility to define that the required
-     * version should be >= 10.0 and < 11.0.
+     * version should be >= 11.0 and < 12.0.
      */
-    if (substr($version, 0, 2) != '10') {
-      throw new Exception(pht('Linter %s requires clang-format version 10.x. '.
+    if (substr($version, 0, 2) != '11') {
+      throw new Exception(pht('Linter %s requires clang-format version 11.x. '.
                               'You have version %s.',
                               ClangFormatLinter::class,
                               $version));
     }
 
     return $version;
   }
 
   public function getInstallInstructions() {
     return pht('Make sure clang-format is in directory specified by $PATH');
   }
 
   public function shouldExpectCommandErrors() {
     return false;
   }
 
   protected function getMandatoryFlags() {
     return array();
   }
 
   protected function parseLinterOutput($path, $err, $stdout, $stderr) {
     $ok = ($err == 0);
 
     if (!$ok) {
       return false;
     }
 
     $root = $this->getProjectRoot();
     $path = Filesystem::resolvePath($path, $root);
     $orig = file_get_contents($path);
     if ($orig == $stdout) {
       return array();
     }
 
     $message = id(new ArcanistLintMessage())
       ->setPath($path)
       ->setLine(1)
       ->setChar(1)
       ->setGranularity(ArcanistLinter::GRANULARITY_FILE)
       ->setCode('CFMT')
       ->setSeverity(ArcanistLintSeverity::SEVERITY_AUTOFIX)
       ->setName('Code style violation')
       ->setDescription("'$path' has code style errors.")
       ->setOriginalText($orig)
       ->setReplacementText($stdout);
 
     return array($message);
   }
 }
diff --git a/contrib/teamcity/setup-debian-buster.sh b/contrib/teamcity/setup-debian-buster.sh
index e1d933555..467c8e437 100755
--- a/contrib/teamcity/setup-debian-buster.sh
+++ b/contrib/teamcity/setup-debian-buster.sh
@@ -1,30 +1,30 @@
 #!/usr/bin/env bash
 
 export LC_ALL=C.UTF-8
 
 set -euxo pipefail
 
 TEAMCITY_DIR=$(dirname "$0")
 
 # Install all the build dependencies
 "${TEAMCITY_DIR}"/../utils/install-dependencies.sh
 
 # Python library for interacting with teamcity
 pip3 install teamcity-messages
 # Install Python dependencies for the build bot
 # Note: Path should be relative to TEAMCITY_DIR since the base image build
 # context may be different than the project root.
 pip3 install -r "${TEAMCITY_DIR}"/../buildbot/requirements.txt
 
 # Make sure clang-10 has highest priority
-update-alternatives --install /usr/bin/clang clang "$(command -v clang-10)" 100
-update-alternatives --install /usr/bin/clang++ clang++ "$(command -v clang++-10)" 100
-update-alternatives --install /usr/bin/llvm-symbolizer llvm-symbolizer "$(command -v llvm-symbolizer-10)" 100
+update-alternatives --install /usr/bin/clang clang "$(command -v clang-11)" 100
+update-alternatives --install /usr/bin/clang++ clang++ "$(command -v clang++-11)" 100
+update-alternatives --install /usr/bin/llvm-symbolizer llvm-symbolizer "$(command -v llvm-symbolizer-11)" 100
 
 # Set default git config so that any git operations requiring authoring,
 # rebasing, or cherry-picking of commits just work out of the box.
 git config --global user.name "abc-bot"
 git config --global user.email "no-email-abc-bot@bitcoinabc.org"
 
 # npm uses ssh to connect to github by default, use https instead
 git config --global url."https://github.com".insteadOf ssh://git@github.com
diff --git a/contrib/utils/install-dependencies.sh b/contrib/utils/install-dependencies.sh
index a85c52280..0f7205856 100755
--- a/contrib/utils/install-dependencies.sh
+++ b/contrib/utils/install-dependencies.sh
@@ -1,139 +1,139 @@
 #!/usr/bin/env bash
 
 export LC_ALL=C.UTF-8
 
 set -euxo pipefail
 
 dpkg --add-architecture i386
 
 PACKAGES=(
   arcanist
   automake
   autotools-dev
   binutils
   bsdmainutils
   build-essential
   ccache
   curl
   default-jdk
   devscripts
   doxygen
   dput
   flake8
   g++-aarch64-linux-gnu
   g++-arm-linux-gnueabihf
   gettext-base
   git
   golang
   g++-mingw-w64
   gnupg
   graphviz
   gperf
   help2man
   imagemagick
   jq
   lcov
   less
   lib32stdc++-8-dev
   libboost-all-dev
   libbz2-dev
   libc6-dev:i386
   libcap-dev
   libdb++-dev
   libdb-dev
   libevent-dev
   libjemalloc-dev
   libminiupnpc-dev
   libprotobuf-dev
   libqrencode-dev
   libqt5core5a
   libqt5dbus5
   libqt5gui5
   librsvg2-bin
   libsqlite3-dev
   libssl-dev
   libtiff-tools
   libtinfo5
   libtool
   libzmq3-dev
   lld
   make
   ninja-build
   nsis
   php-codesniffer
   pkg-config
   protobuf-compiler
   python3
   python3-autopep8
   python3-pip
   python3-setuptools
   python3-yaml
   python3-zmq
   qemu-user-static
   qttools5-dev
   qttools5-dev-tools
   software-properties-common
   tar
   wget
   xvfb
   yamllint
   wine
 )
 
 function join_by() {
   local IFS="$1"
   shift
   echo "$*"
 }
 
 apt-get update
 DEBIAN_FRONTEND=noninteractive apt-get install -y $(join_by ' ' "${PACKAGES[@]}")
 
 BACKPORTS=(
   cmake
   shellcheck
 )
 
 echo "deb http://deb.debian.org/debian buster-backports main" | tee -a /etc/apt/sources.list
 apt-get update
 DEBIAN_FRONTEND=noninteractive apt-get -t buster-backports install -y $(join_by ' ' "${BACKPORTS[@]}")
 
 
 # Install llvm-8 and clang-10
 apt-key add "$(dirname "$0")"/llvm.pub
 add-apt-repository "deb https://apt.llvm.org/buster/   llvm-toolchain-buster-8  main"
-add-apt-repository "deb https://apt.llvm.org/buster/   llvm-toolchain-buster-10  main"
+add-apt-repository "deb https://apt.llvm.org/buster/   llvm-toolchain-buster-11  main"
 apt-get update
 
 LLVM_PACKAGES=(
-  clang-10
-  clang-format-10
-  clang-tidy-10
-  clang-tools-10
+  clang-11
+  clang-format-11
+  clang-tidy-11
+  clang-tools-11
 )
 DEBIAN_FRONTEND=noninteractive apt-get install -y $(join_by ' ' "${LLVM_PACKAGES[@]}")
 
 # Use the mingw posix variant
 update-alternatives --set x86_64-w64-mingw32-g++ $(command -v x86_64-w64-mingw32-g++-posix)
 update-alternatives --set x86_64-w64-mingw32-gcc $(command -v x86_64-w64-mingw32-gcc-posix)
 
 # Python library for merging nested structures
 pip3 install deepmerge
 # For running Python test suites
 pip3 install pytest
 
 # Up-to-date mypy and isort packages are required python linters
 pip3 install isort==5.6.4 mypy==0.780
 echo "export PATH=\"$(python3 -m site --user-base)/bin:\$PATH\"" >> ~/.bashrc
 # shellcheck source=/dev/null
 source ~/.bashrc
 
 # Install pandoc. The version from buster is outdated, so get a more recent one
 # from github.
 wget https://github.com/jgm/pandoc/releases/download/2.10.1/pandoc-2.10.1-1-amd64.deb
 echo "4515d6fe2bf8b82765d8dfa1e1b63ccb0ff3332d60389f948672eaa37932e936 pandoc-2.10.1-1-amd64.deb" | sha256sum -c
 DEBIAN_FRONTEND=noninteractive dpkg -i pandoc-2.10.1-1-amd64.deb
 
 # Install npm v7.x and nodejs v15.x
 curl -sL https://deb.nodesource.com/setup_15.x | bash -
 apt-get install -y nodejs
diff --git a/src/i2p.cpp b/src/i2p.cpp
index c37851e11..eadbe54ad 100644
--- a/src/i2p.cpp
+++ b/src/i2p.cpp
@@ -1,421 +1,421 @@
 // Copyright (c) 2020-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.
 
 #include <i2p.h>
 
 #include <chainparams.h>
 #include <compat.h>
 #include <compat/endian.h>
 #include <crypto/sha256.h>
 #include <fs.h>
 #include <logging.h>
 #include <netaddress.h>
 #include <netbase.h>
 #include <random.h>
 #include <tinyformat.h>
 #include <util/readwritefile.h>
 #include <util/sock.h>
 #include <util/spanparsing.h>
 #include <util/strencodings.h>
 #include <util/system.h>
 
 #include <chrono>
 #include <memory>
 #include <stdexcept>
 #include <string>
 
 namespace i2p {
 
 /**
  * Swap Standard Base64 <-> I2P Base64.
  * Standard Base64 uses `+` and `/` as last two characters of its alphabet.
  * I2P Base64 uses `-` and `~` respectively.
  * So it is easy to detect in which one is the input and convert to the other.
  * @param[in] from Input to convert.
  * @return converted `from`
  */
 static std::string SwapBase64(const std::string &from) {
     std::string to;
     to.resize(from.size());
     for (size_t i = 0; i < from.size(); ++i) {
         switch (from[i]) {
             case '-':
                 to[i] = '+';
                 break;
             case '~':
                 to[i] = '/';
                 break;
             case '+':
                 to[i] = '-';
                 break;
             case '/':
                 to[i] = '~';
                 break;
             default:
                 to[i] = from[i];
                 break;
         }
     }
     return to;
 }
 
 /**
  * Decode an I2P-style Base64 string.
  * @param[in] i2p_b64 I2P-style Base64 string.
  * @return decoded `i2p_b64`
  * @throw std::runtime_error if decoding fails
  */
 static Binary DecodeI2PBase64(const std::string &i2p_b64) {
     const std::string &std_b64 = SwapBase64(i2p_b64);
     bool invalid;
     Binary decoded = DecodeBase64(std_b64.c_str(), &invalid);
     if (invalid) {
         throw std::runtime_error(
             strprintf("Cannot decode Base64: \"%s\"", i2p_b64));
     }
     return decoded;
 }
 
 /**
  * Derive the .b32.i2p address of an I2P destination (binary).
  * @param[in] dest I2P destination.
  * @return the address that corresponds to `dest`
  * @throw std::runtime_error if conversion fails
  */
 static CNetAddr DestBinToAddr(const Binary &dest) {
     CSHA256 hasher;
     hasher.Write(dest.data(), dest.size());
     uint8_t hash[CSHA256::OUTPUT_SIZE];
     hasher.Finalize(hash);
 
     CNetAddr addr;
     const std::string addr_str = EncodeBase32(hash, false) + ".b32.i2p";
     if (!addr.SetSpecial(addr_str)) {
         throw std::runtime_error(
             strprintf("Cannot parse I2P address: \"%s\"", addr_str));
     }
 
     return addr;
 }
 
 /**
  * Derive the .b32.i2p address of an I2P destination (I2P-style Base64).
  * @param[in] dest I2P destination.
  * @return the address that corresponds to `dest`
  * @throw std::runtime_error if conversion fails
  */
 static CNetAddr DestB64ToAddr(const std::string &dest) {
     const Binary &decoded = DecodeI2PBase64(dest);
     return DestBinToAddr(decoded);
 }
 
 namespace sam {
 
     Session::Session(const fs::path &private_key_file,
                      const CService &control_host, CThreadInterrupt *interrupt)
         : m_private_key_file(private_key_file), m_control_host(control_host),
           m_interrupt(interrupt),
           m_control_sock(std::make_unique<Sock>(INVALID_SOCKET)) {}
 
     Session::~Session() {
         LOCK(m_mutex);
         Disconnect();
     }
 
     bool Session::Listen(Connection &conn) {
         try {
             LOCK(m_mutex);
             CreateIfNotCreatedAlready();
             conn.me = m_my_addr;
             conn.sock = StreamAccept();
             return true;
         } catch (const std::runtime_error &e) {
             Log("Error listening: %s", e.what());
             CheckControlSock();
         }
         return false;
     }
 
     bool Session::Accept(Connection &conn) {
         try {
             while (!*m_interrupt) {
                 Sock::Event occurred;
                 conn.sock->Wait(MAX_WAIT_FOR_IO, Sock::RECV, &occurred);
 
                 if ((occurred & Sock::RECV) == 0) {
                     // Timeout, no incoming connections within MAX_WAIT_FOR_IO.
                     continue;
                 }
 
                 const std::string &peer_dest = conn.sock->RecvUntilTerminator(
                     '\n', MAX_WAIT_FOR_IO, *m_interrupt, MAX_MSG_SIZE);
 
                 conn.peer = CService(DestB64ToAddr(peer_dest), I2P_SAM31_PORT);
 
                 return true;
             }
         } catch (const std::runtime_error &e) {
             Log("Error accepting: %s", e.what());
             CheckControlSock();
         }
         return false;
     }
 
     bool Session::Connect(const CService &to, Connection &conn,
                           bool &proxy_error) {
         // Refuse connecting to arbitrary ports. We don't specify any
         // destination port to the SAM proxy when connecting (SAM 3.1 does not
         // use ports) and it forces/defaults it to I2P_SAM31_PORT.
         if (to.GetPort() != I2P_SAM31_PORT) {
             proxy_error = false;
             return false;
         }
 
         proxy_error = true;
 
         std::string session_id;
         std::unique_ptr<Sock> sock;
         conn.peer = to;
 
         try {
             {
                 LOCK(m_mutex);
                 CreateIfNotCreatedAlready();
                 session_id = m_session_id;
                 conn.me = m_my_addr;
                 sock = Hello();
             }
 
             const Reply &lookup_reply = SendRequestAndGetReply(
                 *sock, strprintf("NAMING LOOKUP NAME=%s", to.ToStringIP()));
 
             const std::string &dest = lookup_reply.Get("VALUE");
 
             const Reply &connect_reply = SendRequestAndGetReply(
                 *sock,
                 strprintf("STREAM CONNECT ID=%s DESTINATION=%s SILENT=false",
                           session_id, dest),
                 false);
 
             const std::string &result = connect_reply.Get("RESULT");
 
             if (result == "OK") {
                 conn.sock = std::move(sock);
                 return true;
             }
 
             if (result == "INVALID_ID") {
                 LOCK(m_mutex);
                 Disconnect();
                 throw std::runtime_error("Invalid session id");
             }
 
             if (result == "CANT_REACH_PEER" || result == "TIMEOUT") {
                 proxy_error = false;
             }
 
             throw std::runtime_error(strprintf("\"%s\"", connect_reply.full));
         } catch (const std::runtime_error &e) {
             Log("Error connecting to %s: %s", to.ToString(), e.what());
             CheckControlSock();
             return false;
         }
     }
 
     // Private methods
 
     std::string Session::Reply::Get(const std::string &key) const {
         const auto &pos = keys.find(key);
         if (pos == keys.end() || !pos->second.has_value()) {
             throw std::runtime_error(
                 strprintf("Missing %s= in the reply to \"%s\": \"%s\"", key,
                           request, full));
         }
         return pos->second.value();
     }
 
     template <typename... Args>
-    void Session::Log(const std::string &fmt, const Args &... args) const {
+    void Session::Log(const std::string &fmt, const Args &...args) const {
         LogPrint(BCLog::I2P, "I2P: %s\n", tfm::format(fmt, args...));
     }
 
     Session::Reply Session::SendRequestAndGetReply(const Sock &sock,
                                                    const std::string &request,
                                                    bool check_result_ok) const {
         sock.SendComplete(request + "\n", MAX_WAIT_FOR_IO, *m_interrupt);
 
         Reply reply;
 
         // Don't log the full "SESSION CREATE ..." because it contains our
         // private key.
         reply.request = request.substr(0, 14) == "SESSION CREATE"
                             ? "SESSION CREATE ..."
                             : request;
 
         // It could take a few minutes for the I2P router to reply as it is
         // querying the I2P network (when doing name lookup, for example).
         // Notice: `RecvUntilTerminator()` is checking `m_interrupt` more often,
         // so we would not be stuck here for long if `m_interrupt` is signaled.
         static constexpr auto recv_timeout = 3min;
 
         reply.full = sock.RecvUntilTerminator('\n', recv_timeout, *m_interrupt,
                                               MAX_MSG_SIZE);
 
         for (const auto &kv : spanparsing::Split(reply.full, ' ')) {
             const auto &pos = std::find(kv.begin(), kv.end(), '=');
             if (pos != kv.end()) {
                 reply.keys.emplace(std::string{kv.begin(), pos},
                                    std::string{pos + 1, kv.end()});
             } else {
                 reply.keys.emplace(std::string{kv.begin(), kv.end()},
                                    std::nullopt);
             }
         }
 
         if (check_result_ok && reply.Get("RESULT") != "OK") {
             throw std::runtime_error(strprintf(
                 "Unexpected reply to \"%s\": \"%s\"", request, reply.full));
         }
 
         return reply;
     }
 
     std::unique_ptr<Sock> Session::Hello() const {
         auto sock = CreateSock(m_control_host);
 
         if (!sock) {
             throw std::runtime_error("Cannot create socket");
         }
 
         if (!ConnectSocketDirectly(m_control_host, *sock, nConnectTimeout,
                                    true)) {
             throw std::runtime_error(
                 strprintf("Cannot connect to %s", m_control_host.ToString()));
         }
 
         SendRequestAndGetReply(*sock, "HELLO VERSION MIN=3.1 MAX=3.1");
 
         return sock;
     }
 
     void Session::CheckControlSock() {
         LOCK(m_mutex);
 
         std::string errmsg;
         if (!m_control_sock->IsConnected(errmsg)) {
             Log("Control socket error: %s", errmsg);
             Disconnect();
         }
     }
 
     void Session::DestGenerate(const Sock &sock) {
         // https://geti2p.net/spec/common-structures#key-certificates
         // "7" or "EdDSA_SHA512_Ed25519" - "Recent Router Identities and
         // Destinations". Use "7" because i2pd <2.24.0 does not recognize the
         // textual form.
         const Reply &reply = SendRequestAndGetReply(
             sock, "DEST GENERATE SIGNATURE_TYPE=7", false);
 
         m_private_key = DecodeI2PBase64(reply.Get("PRIV"));
     }
 
     void Session::GenerateAndSavePrivateKey(const Sock &sock) {
         DestGenerate(sock);
 
         // umask is set to 077 in init.cpp, which is ok (unless -sysperms is
         // given)
         if (!WriteBinaryFile(
                 m_private_key_file,
                 std::string(m_private_key.begin(), m_private_key.end()))) {
             throw std::runtime_error(
                 strprintf("Cannot save I2P private key to %s",
                           fs::quoted(fs::PathToString(m_private_key_file))));
         }
     }
 
     Binary Session::MyDestination() const {
         // From https://geti2p.net/spec/common-structures#destination:
         // "They are 387 bytes plus the certificate length specified at bytes
         // 385-386, which may be non-zero"
         static constexpr size_t DEST_LEN_BASE = 387;
         static constexpr size_t CERT_LEN_POS = 385;
 
         uint16_t cert_len;
         memcpy(&cert_len, &m_private_key.at(CERT_LEN_POS), sizeof(cert_len));
         cert_len = be16toh(cert_len);
 
         const size_t dest_len = DEST_LEN_BASE + cert_len;
 
         return Binary{m_private_key.begin(), m_private_key.begin() + dest_len};
     }
 
     void Session::CreateIfNotCreatedAlready() {
         std::string errmsg;
         if (m_control_sock->IsConnected(errmsg)) {
             return;
         }
 
         Log("Creating SAM session with %s", m_control_host.ToString());
 
         auto sock = Hello();
 
         const auto &[read_ok, data] = ReadBinaryFile(m_private_key_file);
         if (read_ok) {
             m_private_key.assign(data.begin(), data.end());
         } else {
             GenerateAndSavePrivateKey(*sock);
         }
 
         const std::string &session_id = GetRandHash().GetHex().substr(
             0, 10); // full is an overkill, too verbose in the logs
         const std::string &private_key_b64 =
             SwapBase64(EncodeBase64(m_private_key));
 
         SendRequestAndGetReply(
             *sock, strprintf("SESSION CREATE STYLE=STREAM ID=%s DESTINATION=%s",
                              session_id, private_key_b64));
 
         m_my_addr = CService(DestBinToAddr(MyDestination()), I2P_SAM31_PORT);
         m_session_id = session_id;
         m_control_sock = std::move(sock);
 
         LogPrintf("I2P: SAM session created: session id=%s, my address=%s\n",
                   m_session_id, m_my_addr.ToString());
     }
 
     std::unique_ptr<Sock> Session::StreamAccept() {
         auto sock = Hello();
 
         const Reply &reply = SendRequestAndGetReply(
             *sock, strprintf("STREAM ACCEPT ID=%s SILENT=false", m_session_id),
             false);
 
         const std::string &result = reply.Get("RESULT");
 
         if (result == "OK") {
             return sock;
         }
 
         if (result == "INVALID_ID") {
             // If our session id is invalid, then force session re-creation on
             // next usage.
             Disconnect();
         }
 
         throw std::runtime_error(strprintf("\"%s\"", reply.full));
     }
 
     void Session::Disconnect() {
         if (m_control_sock->Get() != INVALID_SOCKET) {
             if (m_session_id.empty()) {
                 Log("Destroying incomplete session");
             } else {
                 Log("Destroying session %s", m_session_id);
             }
         }
         m_control_sock->Reset();
         m_session_id.clear();
     }
 } // namespace sam
 } // namespace i2p
diff --git a/src/i2p.h b/src/i2p.h
index 5c39f946f..3a05bf8cf 100644
--- a/src/i2p.h
+++ b/src/i2p.h
@@ -1,283 +1,283 @@
 // Copyright (c) 2020-2020 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #ifndef BITCOIN_I2P_H
 #define BITCOIN_I2P_H
 
 #include <compat.h>
 #include <fs.h>
 #include <netaddress.h>
 #include <sync.h>
 #include <threadinterrupt.h>
 #include <util/sock.h>
 
 #include <memory>
 #include <optional>
 #include <string>
 #include <unordered_map>
 #include <vector>
 
 namespace i2p {
 
 /**
  * Binary data.
  */
 using Binary = std::vector<uint8_t>;
 
 /**
  * An established connection with another peer.
  */
 struct Connection {
     /** Connected socket. */
     std::unique_ptr<Sock> sock;
 
     /** Our I2P address. */
     CService me;
 
     /** The peer's I2P address. */
     CService peer;
 };
 
 namespace sam {
 
     /**
      * The maximum size of an incoming message from the I2P SAM proxy (in
      * bytes). Used to avoid a runaway proxy from sending us an "unlimited"
      * amount of data without a terminator. The longest known message is ~1400
      * bytes, so this is high enough not to be triggered during normal
      * operation, yet low enough to avoid a malicious proxy from filling our
      * memory.
      */
     static constexpr size_t MAX_MSG_SIZE{65536};
 
     /**
      * I2P SAM session.
      */
     class Session {
     public:
         /**
          * Construct a session. This will not initiate any IO, the session will
          * be lazily created later when first used.
          * @param[in] private_key_file Path to a private key file. If the file
          * does not exist then the private key will be generated and saved into
          * the file.
          * @param[in] control_host Location of the SAM proxy.
          * @param[in,out] interrupt If this is signaled then all operations are
          * canceled as soon as possible and executing methods throw an
          * exception. Notice: only a pointer to the `CThreadInterrupt` object is
          * saved, so it must not be destroyed earlier than this `Session`
          * object.
          */
         Session(const fs::path &private_key_file, const CService &control_host,
                 CThreadInterrupt *interrupt);
 
         /**
          * Destroy the session, closing the internally used sockets. The sockets
          * that have been returned by `Accept()` or `Connect()` will not be
          * closed, but they will be closed by the SAM proxy because the session
          * is destroyed. So they will return an error next time we try to read
          * or write to them.
          */
         ~Session();
 
         /**
          * Start listening for an incoming connection.
          * @param[out] conn Upon successful completion the `sock` and `me`
          * members will be set to the listening socket and address.
          * @return true on success
          */
         bool Listen(Connection &conn);
 
         /**
          * Wait for and accept a new incoming connection.
          * @param[in,out] conn The `sock` member is used for waiting and
          * accepting. Upon successful completion the `peer` member will be set
          * to the address of the incoming peer.
          * @return true on success
          */
         bool Accept(Connection &conn);
 
         /**
          * Connect to an I2P peer.
          * @param[in] to Peer to connect to.
          * @param[out] conn Established connection. Only set if `true` is
          * returned.
          * @param[out] proxy_error If an error occurs due to proxy or general
          * network failure, then this is set to `true`. If an error occurs due
          * to unreachable peer (likely peer is down), then it is set to `false`.
          * Only set if `false` is returned.
          * @return true on success
          */
         bool Connect(const CService &to, Connection &conn, bool &proxy_error);
 
     private:
         /**
          * A reply from the SAM proxy.
          */
         struct Reply {
             /**
              * Full, unparsed reply.
              */
             std::string full;
 
             /**
              * Request, used for detailed error reporting.
              */
             std::string request;
 
             /**
              * A map of keywords from the parsed reply.
              * For example, if the reply is "A=X B C=YZ", then the map will be
              * keys["A"] == "X"
              * keys["B"] == (empty std::optional)
              * keys["C"] == "YZ"
              */
             std::unordered_map<std::string, std::optional<std::string>> keys;
 
             /**
              * Get the value of a given key.
              * For example if the reply is "A=X B" then:
              * Value("A") -> "X"
              * Value("B") -> throws
              * Value("C") -> throws
              * @param[in] key Key whose value to retrieve
              * @returns the key's value
              * @throws std::runtime_error if the key is not present or if it has
              * no value
              */
             std::string Get(const std::string &key) const;
         };
 
         /**
          * Log a message in the `BCLog::I2P` category.
          * @param[in] fmt printf(3)-like format string.
          * @param[in] args printf(3)-like arguments that correspond to `fmt`.
          */
         template <typename... Args>
-        void Log(const std::string &fmt, const Args &... args) const;
+        void Log(const std::string &fmt, const Args &...args) const;
 
         /**
          * Send request and get a reply from the SAM proxy.
          * @param[in] sock A socket that is connected to the SAM proxy.
          * @param[in] request Raw request to send, a newline terminator is
          * appended to it.
          * @param[in] check_result_ok If true then after receiving the reply a
          * check is made whether it contains "RESULT=OK" and an exception is
          * thrown if it does not.
          * @throws std::runtime_error if an error occurs
          */
         Reply SendRequestAndGetReply(const Sock &sock,
                                      const std::string &request,
                                      bool check_result_ok = true) const;
 
         /**
          * Open a new connection to the SAM proxy.
          * @return a connected socket
          * @throws std::runtime_error if an error occurs
          */
         std::unique_ptr<Sock> Hello() const EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
 
         /**
          * Check the control socket for errors and possibly disconnect.
          */
         void CheckControlSock();
 
         /**
          * Generate a new destination with the SAM proxy and set `m_private_key`
          * to it.
          * @param[in] sock Socket to use for talking to the SAM proxy.
          * @throws std::runtime_error if an error occurs
          */
         void DestGenerate(const Sock &sock) EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
 
         /**
          * Generate a new destination with the SAM proxy, set `m_private_key` to
          * it and save it on disk to `m_private_key_file`.
          * @param[in] sock Socket to use for talking to the SAM proxy.
          * @throws std::runtime_error if an error occurs
          */
         void GenerateAndSavePrivateKey(const Sock &sock)
             EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
 
         /**
          * Derive own destination from `m_private_key`.
          * @see https://geti2p.net/spec/common-structures#destination
          * @return an I2P destination
          */
         Binary MyDestination() const EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
 
         /**
          * Create the session if not already created. Reads the private key file
          * and connects to the SAM proxy.
          * @throws std::runtime_error if an error occurs
          */
         void CreateIfNotCreatedAlready() EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
 
         /**
          * Open a new connection to the SAM proxy and issue "STREAM ACCEPT"
          * request using the existing session id.
          * @return the idle socket that is waiting for a peer to connect to us
          * @throws std::runtime_error if an error occurs
          */
         std::unique_ptr<Sock> StreamAccept() EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
 
         /**
          * Destroy the session, closing the internally used sockets.
          */
         void Disconnect() EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
 
         /**
          * The name of the file where this peer's private key is stored (in
          * binary).
          */
         const fs::path m_private_key_file;
 
         /**
          * The host and port of the SAM control service.
          */
         const CService m_control_host;
 
         /**
          * Cease network activity when this is signaled.
          */
         CThreadInterrupt *const m_interrupt;
 
         /**
          * Mutex protecting the members that can be concurrently accessed.
          */
         mutable Mutex m_mutex;
 
         /**
          * The private key of this peer.
          * @see The reply to the "DEST GENERATE" command in
          * https://geti2p.net/en/docs/api/samv3
          */
         Binary m_private_key GUARDED_BY(m_mutex);
 
         /**
          * SAM control socket.
          * Used to connect to the I2P SAM service and create a session
          * ("SESSION CREATE"). With the established session id we later open
          * other connections to the SAM service to accept incoming I2P
          * connections and make outgoing ones.
          * See https://geti2p.net/en/docs/api/samv3
          */
         std::unique_ptr<Sock> m_control_sock GUARDED_BY(m_mutex);
 
         /**
          * Our .b32.i2p address.
          * Derived from `m_private_key`.
          */
         CService m_my_addr GUARDED_BY(m_mutex);
 
         /**
          * SAM session id.
          */
         std::string m_session_id GUARDED_BY(m_mutex);
     };
 
 } // namespace sam
 } // namespace i2p
 
 #endif // BITCOIN_I2P_H
diff --git a/src/index/base.cpp b/src/index/base.cpp
index 6c5d90a77..b5628428f 100644
--- a/src/index/base.cpp
+++ b/src/index/base.cpp
@@ -1,337 +1,337 @@
 // Copyright (c) 2017-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.
 
 #include <blockdb.h>
 #include <chain.h>
 #include <chainparams.h>
 #include <config.h>
 #include <index/base.h>
 #include <node/ui_interface.h>
 #include <shutdown.h>
 #include <tinyformat.h>
 #include <util/system.h>
 #include <util/translation.h>
 #include <validation.h>
 #include <warnings.h>
 
 #include <functional>
 
 constexpr char DB_BEST_BLOCK = 'B';
 
 constexpr int64_t SYNC_LOG_INTERVAL = 30;           // seconds
 constexpr int64_t SYNC_LOCATOR_WRITE_INTERVAL = 30; // seconds
 
 template <typename... Args>
-static void FatalError(const char *fmt, const Args &... args) {
+static void FatalError(const char *fmt, const Args &...args) {
     std::string strMessage = tfm::format(fmt, args...);
     SetMiscWarning(Untranslated(strMessage));
     LogPrintf("*** %s\n", strMessage);
     AbortError(_("A fatal internal error occurred, see debug.log for details"));
     StartShutdown();
 }
 
 BaseIndex::DB::DB(const fs::path &path, size_t n_cache_size, bool f_memory,
                   bool f_wipe, bool f_obfuscate)
     : CDBWrapper(path, n_cache_size, f_memory, f_wipe, f_obfuscate) {}
 
 bool BaseIndex::DB::ReadBestBlock(CBlockLocator &locator) const {
     bool success = Read(DB_BEST_BLOCK, locator);
     if (!success) {
         locator.SetNull();
     }
     return success;
 }
 
 void BaseIndex::DB::WriteBestBlock(CDBBatch &batch,
                                    const CBlockLocator &locator) {
     batch.Write(DB_BEST_BLOCK, locator);
 }
 
 BaseIndex::~BaseIndex() {
     Interrupt();
     Stop();
 }
 
 bool BaseIndex::Init() {
     CBlockLocator locator;
     if (!GetDB().ReadBestBlock(locator)) {
         locator.SetNull();
     }
 
     LOCK(cs_main);
     if (locator.IsNull()) {
         m_best_block_index = nullptr;
     } else {
         m_best_block_index = FindForkInGlobalIndex(::ChainActive(), locator);
     }
     m_synced = m_best_block_index.load() == ::ChainActive().Tip();
     return true;
 }
 
 static const CBlockIndex *NextSyncBlock(const CBlockIndex *pindex_prev)
     EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
     AssertLockHeld(cs_main);
 
     if (!pindex_prev) {
         return ::ChainActive().Genesis();
     }
 
     const CBlockIndex *pindex = ::ChainActive().Next(pindex_prev);
     if (pindex) {
         return pindex;
     }
 
     return ::ChainActive().Next(::ChainActive().FindFork(pindex_prev));
 }
 
 void BaseIndex::ThreadSync() {
     const CBlockIndex *pindex = m_best_block_index.load();
     if (!m_synced) {
         auto &consensus_params = GetConfig().GetChainParams().GetConsensus();
 
         int64_t last_log_time = 0;
         int64_t last_locator_write_time = 0;
         while (true) {
             if (m_interrupt) {
                 m_best_block_index = pindex;
                 // No need to handle errors in Commit. If it fails, the error
                 // will be already be logged. The best way to recover is to
                 // continue, as index cannot be corrupted by a missed commit to
                 // disk for an advanced index state.
                 Commit();
                 return;
             }
 
             {
                 LOCK(cs_main);
                 const CBlockIndex *pindex_next = NextSyncBlock(pindex);
                 if (!pindex_next) {
                     m_best_block_index = pindex;
                     m_synced = true;
                     // No need to handle errors in Commit. See rationale above.
                     Commit();
                     break;
                 }
                 if (pindex_next->pprev != pindex &&
                     !Rewind(pindex, pindex_next->pprev)) {
                     FatalError(
                         "%s: Failed to rewind index %s to a previous chain tip",
                         __func__, GetName());
                     return;
                 }
                 pindex = pindex_next;
             }
 
             int64_t current_time = GetTime();
             if (last_log_time + SYNC_LOG_INTERVAL < current_time) {
                 LogPrintf("Syncing %s with block chain from height %d\n",
                           GetName(), pindex->nHeight);
                 last_log_time = current_time;
             }
 
             if (last_locator_write_time + SYNC_LOCATOR_WRITE_INTERVAL <
                 current_time) {
                 m_best_block_index = pindex;
                 last_locator_write_time = current_time;
                 // No need to handle errors in Commit. See rationale above.
                 Commit();
             }
 
             CBlock block;
             if (!ReadBlockFromDisk(block, pindex, consensus_params)) {
                 FatalError("%s: Failed to read block %s from disk", __func__,
                            pindex->GetBlockHash().ToString());
                 return;
             }
             if (!WriteBlock(block, pindex)) {
                 FatalError("%s: Failed to write block %s to index database",
                            __func__, pindex->GetBlockHash().ToString());
                 return;
             }
         }
     }
 
     if (pindex) {
         LogPrintf("%s is enabled at height %d\n", GetName(), pindex->nHeight);
     } else {
         LogPrintf("%s is enabled\n", GetName());
     }
 }
 
 bool BaseIndex::Commit() {
     CDBBatch batch(GetDB());
     if (!CommitInternal(batch) || !GetDB().WriteBatch(batch)) {
         return error("%s: Failed to commit latest %s state", __func__,
                      GetName());
     }
     return true;
 }
 
 bool BaseIndex::CommitInternal(CDBBatch &batch) {
     LOCK(cs_main);
     GetDB().WriteBestBlock(batch,
                            ::ChainActive().GetLocator(m_best_block_index));
     return true;
 }
 
 bool BaseIndex::Rewind(const CBlockIndex *current_tip,
                        const CBlockIndex *new_tip) {
     assert(current_tip == m_best_block_index);
     assert(current_tip->GetAncestor(new_tip->nHeight) == new_tip);
 
     // In the case of a reorg, ensure persisted block locator is not stale.
     m_best_block_index = new_tip;
     if (!Commit()) {
         // If commit fails, revert the best block index to avoid corruption.
         m_best_block_index = current_tip;
         return false;
     }
 
     return true;
 }
 
 void BaseIndex::BlockConnected(const std::shared_ptr<const CBlock> &block,
                                const CBlockIndex *pindex) {
     if (!m_synced) {
         return;
     }
 
     const CBlockIndex *best_block_index = m_best_block_index.load();
     if (!best_block_index) {
         if (pindex->nHeight != 0) {
             FatalError("%s: First block connected is not the genesis block "
                        "(height=%d)",
                        __func__, pindex->nHeight);
             return;
         }
     } else {
         // Ensure block connects to an ancestor of the current best block. This
         // should be the case most of the time, but may not be immediately after
         // the the sync thread catches up and sets m_synced. Consider the case
         // where there is a reorg and the blocks on the stale branch are in the
         // ValidationInterface queue backlog even after the sync thread has
         // caught up to the new chain tip. In this unlikely event, log a warning
         // and let the queue clear.
         if (best_block_index->GetAncestor(pindex->nHeight - 1) !=
             pindex->pprev) {
             LogPrintf("%s: WARNING: Block %s does not connect to an ancestor "
                       "of known best chain (tip=%s); not updating index\n",
                       __func__, pindex->GetBlockHash().ToString(),
                       best_block_index->GetBlockHash().ToString());
             return;
         }
         if (best_block_index != pindex->pprev &&
             !Rewind(best_block_index, pindex->pprev)) {
             FatalError("%s: Failed to rewind index %s to a previous chain tip",
                        __func__, GetName());
             return;
         }
     }
 
     if (WriteBlock(*block, pindex)) {
         m_best_block_index = pindex;
     } else {
         FatalError("%s: Failed to write block %s to index", __func__,
                    pindex->GetBlockHash().ToString());
         return;
     }
 }
 
 void BaseIndex::ChainStateFlushed(const CBlockLocator &locator) {
     if (!m_synced) {
         return;
     }
 
     const BlockHash &locator_tip_hash = locator.vHave.front();
     const CBlockIndex *locator_tip_index;
     {
         LOCK(cs_main);
         locator_tip_index = LookupBlockIndex(locator_tip_hash);
     }
 
     if (!locator_tip_index) {
         FatalError("%s: First block (hash=%s) in locator was not found",
                    __func__, locator_tip_hash.ToString());
         return;
     }
 
     // This checks that ChainStateFlushed callbacks are received after
     // BlockConnected. The check may fail immediately after the the sync thread
     // catches up and sets m_synced. Consider the case where there is a reorg
     // and the blocks on the stale branch are in the ValidationInterface queue
     // backlog even after the sync thread has caught up to the new chain tip. In
     // this unlikely event, log a warning and let the queue clear.
     const CBlockIndex *best_block_index = m_best_block_index.load();
     if (best_block_index->GetAncestor(locator_tip_index->nHeight) !=
         locator_tip_index) {
         LogPrintf("%s: WARNING: Locator contains block (hash=%s) not on known "
                   "best chain (tip=%s); not writing index locator\n",
                   __func__, locator_tip_hash.ToString(),
                   best_block_index->GetBlockHash().ToString());
         return;
     }
 
     // No need to handle errors in Commit. If it fails, the error will be
     // already be logged. The best way to recover is to continue, as index
     // cannot be corrupted by a missed commit to disk for an advanced index
     // state.
     Commit();
 }
 
 bool BaseIndex::BlockUntilSyncedToCurrentChain() const {
     AssertLockNotHeld(cs_main);
 
     if (!m_synced) {
         return false;
     }
 
     {
         // Skip the queue-draining stuff if we know we're caught up with
         // ::ChainActive().Tip().
         LOCK(cs_main);
         const CBlockIndex *chain_tip = ::ChainActive().Tip();
         const CBlockIndex *best_block_index = m_best_block_index.load();
         if (best_block_index->GetAncestor(chain_tip->nHeight) == chain_tip) {
             return true;
         }
     }
 
     LogPrintf("%s: %s is catching up on block notifications\n", __func__,
               GetName());
     SyncWithValidationInterfaceQueue();
     return true;
 }
 
 void BaseIndex::Interrupt() {
     m_interrupt();
 }
 
 void BaseIndex::Start() {
     // Need to register this ValidationInterface before running Init(), so that
     // callbacks are not missed if Init sets m_synced to true.
     RegisterValidationInterface(this);
     if (!Init()) {
         FatalError("%s: %s failed to initialize", __func__, GetName());
         return;
     }
 
     m_thread_sync = std::thread(&TraceThread<std::function<void()>>, GetName(),
                                 std::bind(&BaseIndex::ThreadSync, this));
 }
 
 void BaseIndex::Stop() {
     UnregisterValidationInterface(this);
 
     if (m_thread_sync.joinable()) {
         m_thread_sync.join();
     }
 }
 
 IndexSummary BaseIndex::GetSummary() const {
     IndexSummary summary{};
     summary.name = GetName();
     summary.synced = m_synced;
     summary.best_block_height = m_best_block_index.load()->nHeight;
     return summary;
 }
diff --git a/src/logging.h b/src/logging.h
index 81423c6bc..8dc437bd5 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -1,218 +1,218 @@
 // Copyright (c) 2009-2010 Satoshi Nakamoto
 // Copyright (c) 2009-2016 The Bitcoin Core developers
 // Copyright (c) 2017-2019 The Bitcoin developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #ifndef BITCOIN_LOGGING_H
 #define BITCOIN_LOGGING_H
 
 #include <fs.h>
 #include <threadsafety.h>
 #include <tinyformat.h>
 #include <util/string.h>
 
 #include <atomic>
 #include <cstdint>
 #include <list>
 #include <mutex>
 #include <string>
 
 static const bool DEFAULT_LOGTIMEMICROS = false;
 static const bool DEFAULT_LOGIPS = false;
 static const bool DEFAULT_LOGTIMESTAMPS = true;
 static const bool DEFAULT_LOGTHREADNAMES = false;
 static const bool DEFAULT_LOGSOURCELOCATIONS = false;
 
 extern bool fLogIPs;
 extern const char *const DEFAULT_DEBUGLOGFILE;
 
 struct LogCategory {
     std::string category;
     bool active;
 };
 
 namespace BCLog {
 
 enum LogFlags : uint32_t {
     NONE = 0,
     NET = (1 << 0),
     TOR = (1 << 1),
     MEMPOOL = (1 << 2),
     HTTP = (1 << 3),
     BENCH = (1 << 4),
     ZMQ = (1 << 5),
     WALLETDB = (1 << 6),
     RPC = (1 << 7),
     ESTIMATEFEE = (1 << 8),
     ADDRMAN = (1 << 9),
     SELECTCOINS = (1 << 10),
     REINDEX = (1 << 11),
     CMPCTBLOCK = (1 << 12),
     RAND = (1 << 13),
     PRUNE = (1 << 14),
     PROXY = (1 << 15),
     MEMPOOLREJ = (1 << 16),
     LIBEVENT = (1 << 17),
     COINDB = (1 << 18),
     QT = (1 << 19),
     LEVELDB = (1 << 20),
     VALIDATION = (1 << 21),
     AVALANCHE = (1 << 22),
     I2P = (1 << 23),
     ALL = ~uint32_t(0),
 };
 
 class Logger {
 private:
     // Can not use Mutex from sync.h because in debug mode it would cause a
     // deadlock when a potential deadlock was detected
     mutable StdMutex m_cs;
 
     FILE *m_fileout GUARDED_BY(m_cs) = nullptr;
     std::list<std::string> m_msgs_before_open GUARDED_BY(m_cs);
     //! Buffer messages before logging can be started.
     bool m_buffering GUARDED_BY(m_cs) = true;
 
     /**
      * m_started_new_line is a state variable that will suppress printing of the
      * timestamp when multiple calls are made that don't end in a newline.
      */
     std::atomic_bool m_started_new_line{true};
 
     /**
      * Log categories bitfield.
      */
     std::atomic<uint32_t> m_categories{0};
 
     std::string LogTimestampStr(const std::string &str);
 
     /** Slots that connect to the print signal */
     std::list<std::function<void(const std::string &)>>
         m_print_callbacks GUARDED_BY(m_cs){};
 
 public:
     bool m_print_to_console = false;
     bool m_print_to_file = false;
 
     bool m_log_timestamps = DEFAULT_LOGTIMESTAMPS;
     bool m_log_time_micros = DEFAULT_LOGTIMEMICROS;
     bool m_log_threadnames = DEFAULT_LOGTHREADNAMES;
     bool m_log_sourcelocations = DEFAULT_LOGSOURCELOCATIONS;
 
     fs::path m_file_path;
     std::atomic<bool> m_reopen_file{false};
 
     ~Logger();
 
     /** Send a string to the log output */
     void LogPrintStr(const std::string &str,
                      const std::string &logging_function,
                      const std::string &source_file, const int source_line);
 
     /** Returns whether logs will be written to any output */
     bool Enabled() const {
         StdLockGuard scoped_lock(m_cs);
         return m_buffering || m_print_to_console || m_print_to_file ||
                !m_print_callbacks.empty();
     }
 
     /** Connect a slot to the print signal and return the connection */
     std::list<std::function<void(const std::string &)>>::iterator
     PushBackCallback(std::function<void(const std::string &)> fun) {
         StdLockGuard scoped_lock(m_cs);
         m_print_callbacks.push_back(std::move(fun));
         return --m_print_callbacks.end();
     }
 
     /** Delete a connection */
     void DeleteCallback(
         std::list<std::function<void(const std::string &)>>::iterator it) {
         StdLockGuard scoped_lock(m_cs);
         m_print_callbacks.erase(it);
     }
 
     /** Start logging (and flush all buffered messages) */
     bool StartLogging();
     /** Only for testing */
     void DisconnectTestLogger();
 
     void ShrinkDebugFile();
 
     uint32_t GetCategoryMask() const { return m_categories.load(); }
 
     void EnableCategory(LogFlags category);
     bool EnableCategory(const std::string &str);
     void DisableCategory(LogFlags category);
     bool DisableCategory(const std::string &str);
 
     /** Return true if log accepts specified category */
     bool WillLogCategory(LogFlags category) const;
 
     /** Returns a vector of the log categories */
     std::vector<LogCategory> LogCategoriesList() const;
     /** Returns a string with the log categories */
     std::string LogCategoriesString() const {
         return Join(LogCategoriesList(), ", ",
                     [&](const LogCategory &i) { return i.category; });
     };
 
     /** Default for whether ShrinkDebugFile should be run */
     bool DefaultShrinkDebugFile() const;
 };
 
 } // namespace BCLog
 
 BCLog::Logger &LogInstance();
 
 /** Return true if log accepts specified category */
 static inline bool LogAcceptCategory(BCLog::LogFlags category) {
     return LogInstance().WillLogCategory(category);
 }
 
 /** Return true if str parses as a log category and set the flag */
 bool GetLogCategory(BCLog::LogFlags &flag, const std::string &str);
 
 // Be conservative when using LogPrintf/error or other things which
 // unconditionally log to debug.log! It should not be the case that an inbound
 // peer can fill up a user's disk with debug.log entries.
 template <typename... Args>
 static inline void
 LogPrintf_(const std::string &logging_function, const std::string &source_file,
-           const int source_line, const char *fmt, const Args &... args) {
+           const int source_line, const char *fmt, const Args &...args) {
     if (LogInstance().Enabled()) {
         std::string log_msg;
         try {
             log_msg = tfm::format(fmt, args...);
         } catch (tinyformat::format_error &fmterr) {
             /**
              * Original format string will have newline so don't add one here
              */
             log_msg = "Error \"" + std::string(fmterr.what()) +
                       "\" while formatting log message: " + fmt;
         }
         LogInstance().LogPrintStr(log_msg, logging_function, source_file,
                                   source_line);
     }
 }
 
 #define LogPrintf(...) LogPrintf_(__func__, __FILE__, __LINE__, __VA_ARGS__)
 
 // Use a macro instead of a function for conditional logging to prevent
 // evaluating arguments when logging for the category is not enabled.
 #define LogPrint(category, ...)                                                \
     do {                                                                       \
         if (LogAcceptCategory((category))) {                                   \
             LogPrintf(__VA_ARGS__);                                            \
         }                                                                      \
     } while (0)
 
 /**
  * These are aliases used to explicitly state that the message should not end
  * with a newline character. It allows for detecting the missing newlines that
  * could make the logs hard to read.
  */
 #define LogPrintfToBeContinued LogPrintf
 #define LogPrintToBeContinued LogPrint
 
 #endif // BITCOIN_LOGGING_H
diff --git a/src/netbase.cpp b/src/netbase.cpp
index e02502ad1..ecc5715f0 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -1,857 +1,857 @@
 // Copyright (c) 2009-2010 Satoshi Nakamoto
 // Copyright (c) 2009-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.
 
 #include <netbase.h>
 
 #include <compat.h>
 #include <sync.h>
 #include <tinyformat.h>
 #include <util/sock.h>
 #include <util/strencodings.h>
 #include <util/string.h>
 #include <util/system.h>
 #include <util/time.h>
 
 #include <atomic>
 #include <chrono>
 #include <cstdint>
 #include <functional>
 #include <memory>
 
 #ifndef WIN32
 #include <fcntl.h>
 #else
 #include <codecvt>
 #endif
 
 #ifdef USE_POLL
 #include <poll.h>
 #endif
 
 // Settings
 static Mutex g_proxyinfo_mutex;
 static proxyType proxyInfo[NET_MAX] GUARDED_BY(g_proxyinfo_mutex);
 static proxyType nameProxy GUARDED_BY(g_proxyinfo_mutex);
 int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
 bool fNameLookup = DEFAULT_NAME_LOOKUP;
 
 // Need ample time for negotiation for very slow proxies such as Tor
 // (milliseconds)
 static const int SOCKS5_RECV_TIMEOUT = 20 * 1000;
 static std::atomic<bool> interruptSocks5Recv(false);
 
 std::vector<CNetAddr> WrappedGetAddrInfo(const std::string &name,
                                          bool allow_lookup) {
     addrinfo ai_hint{};
     // We want a TCP port, which is a streaming socket type
     ai_hint.ai_socktype = SOCK_STREAM;
     ai_hint.ai_protocol = IPPROTO_TCP;
     // We don't care which address family (IPv4 or IPv6) is returned
     ai_hint.ai_family = AF_UNSPEC;
     // If we allow lookups of hostnames, use the AI_ADDRCONFIG flag to only
     // return addresses whose family we have an address configured for.
     //
     // If we don't allow lookups, then use the AI_NUMERICHOST flag for
     // getaddrinfo to only decode numerical network addresses and suppress
     // hostname lookups.
     ai_hint.ai_flags = allow_lookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
 
     addrinfo *ai_res{nullptr};
     const int n_err{getaddrinfo(name.c_str(), nullptr, &ai_hint, &ai_res)};
     if (n_err != 0) {
         return {};
     }
 
     // Traverse the linked list starting with ai_trav.
     addrinfo *ai_trav{ai_res};
     std::vector<CNetAddr> resolved_addresses;
     while (ai_trav != nullptr) {
         if (ai_trav->ai_family == AF_INET) {
             assert(ai_trav->ai_addrlen >= sizeof(sockaddr_in));
             resolved_addresses.emplace_back(
                 reinterpret_cast<sockaddr_in *>(ai_trav->ai_addr)->sin_addr);
         }
         if (ai_trav->ai_family == AF_INET6) {
             assert(ai_trav->ai_addrlen >= sizeof(sockaddr_in6));
             const sockaddr_in6 *s6{
                 reinterpret_cast<sockaddr_in6 *>(ai_trav->ai_addr)};
             resolved_addresses.emplace_back(s6->sin6_addr, s6->sin6_scope_id);
         }
         ai_trav = ai_trav->ai_next;
     }
     freeaddrinfo(ai_res);
 
     return resolved_addresses;
 }
 
 DNSLookupFn g_dns_lookup{WrappedGetAddrInfo};
 
 enum Network ParseNetwork(const std::string &net_in) {
     std::string net = ToLower(net_in);
     if (net == "ipv4") {
         return NET_IPV4;
     }
     if (net == "ipv6") {
         return NET_IPV6;
     }
     if (net == "onion") {
         return NET_ONION;
     }
     if (net == "tor") {
         LogPrintf("Warning: net name 'tor' is deprecated and will be removed "
                   "in the future. You should use 'onion' instead.\n");
         return NET_ONION;
     }
     if (net == "i2p") {
         return NET_I2P;
     }
     return NET_UNROUTABLE;
 }
 
 std::string GetNetworkName(enum Network net) {
     switch (net) {
         case NET_UNROUTABLE:
             return "not_publicly_routable";
         case NET_IPV4:
             return "ipv4";
         case NET_IPV6:
             return "ipv6";
         case NET_ONION:
             return "onion";
         case NET_I2P:
             return "i2p";
         case NET_CJDNS:
             return "cjdns";
         case NET_INTERNAL:
             return "internal";
         case NET_MAX:
             assert(false);
     } // no default case, so the compiler can warn about missing cases
 
     assert(false);
 }
 
 std::vector<std::string> GetNetworkNames(bool append_unroutable) {
     std::vector<std::string> names;
     for (int n = 0; n < NET_MAX; ++n) {
         const enum Network network { static_cast<Network>(n) };
         if (network == NET_UNROUTABLE || network == NET_CJDNS ||
             network == NET_INTERNAL) {
             continue;
         }
         names.emplace_back(GetNetworkName(network));
     }
     if (append_unroutable) {
         names.emplace_back(GetNetworkName(NET_UNROUTABLE));
     }
     return names;
 }
 
 static bool LookupIntern(const std::string &name, std::vector<CNetAddr> &vIP,
                          unsigned int nMaxSolutions, bool fAllowLookup,
                          DNSLookupFn dns_lookup_function) {
     vIP.clear();
 
     if (!ValidAsCString(name)) {
         return false;
     }
 
     {
         CNetAddr addr;
         // From our perspective, onion addresses are not hostnames but rather
         // direct encodings of CNetAddr much like IPv4 dotted-decimal notation
         // or IPv6 colon-separated hextet notation. Since we can't use
         // getaddrinfo to decode them and it wouldn't make sense to resolve
         // them, we return a network address representing it instead. See
         // CNetAddr::SetSpecial(const std::string&) for more details.
         if (addr.SetSpecial(name)) {
             vIP.push_back(addr);
             return true;
         }
     }
 
     for (const CNetAddr &resolved : dns_lookup_function(name, fAllowLookup)) {
         if (nMaxSolutions > 0 && vIP.size() >= nMaxSolutions) {
             break;
         }
 
         // Never allow resolving to an internal address. Consider any such
         // result invalid.
         if (!resolved.IsInternal()) {
             vIP.push_back(resolved);
         }
     }
 
     return (vIP.size() > 0);
 }
 
 bool LookupHost(const std::string &name, std::vector<CNetAddr> &vIP,
                 unsigned int nMaxSolutions, bool fAllowLookup,
                 DNSLookupFn dns_lookup_function) {
     if (!ValidAsCString(name)) {
         return false;
     }
     std::string strHost = name;
     if (strHost.empty()) {
         return false;
     }
     if (strHost.front() == '[' && strHost.back() == ']') {
         strHost = strHost.substr(1, strHost.size() - 2);
     }
 
     return LookupIntern(strHost, vIP, nMaxSolutions, fAllowLookup,
                         dns_lookup_function);
 }
 
 bool LookupHost(const std::string &name, CNetAddr &addr, bool fAllowLookup,
                 DNSLookupFn dns_lookup_function) {
     if (!ValidAsCString(name)) {
         return false;
     }
     std::vector<CNetAddr> vIP;
     LookupHost(name, vIP, 1, fAllowLookup, dns_lookup_function);
     if (vIP.empty()) {
         return false;
     }
     addr = vIP.front();
     return true;
 }
 
 bool Lookup(const std::string &name, std::vector<CService> &vAddr,
             uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions,
             DNSLookupFn dns_lookup_function) {
     if (name.empty() || !ValidAsCString(name)) {
         return false;
     }
     uint16_t port{portDefault};
     std::string hostname;
     SplitHostPort(name, port, hostname);
 
     std::vector<CNetAddr> vIP;
     bool fRet = LookupIntern(hostname, vIP, nMaxSolutions, fAllowLookup,
                              dns_lookup_function);
     if (!fRet) {
         return false;
     }
     vAddr.resize(vIP.size());
     for (unsigned int i = 0; i < vIP.size(); i++) {
         vAddr[i] = CService(vIP[i], port);
     }
     return true;
 }
 
 bool Lookup(const std::string &name, CService &addr, uint16_t portDefault,
             bool fAllowLookup, DNSLookupFn dns_lookup_function) {
     if (!ValidAsCString(name)) {
         return false;
     }
     std::vector<CService> vService;
     bool fRet = Lookup(name, vService, portDefault, fAllowLookup, 1,
                        dns_lookup_function);
     if (!fRet) {
         return false;
     }
     addr = vService[0];
     return true;
 }
 
 CService LookupNumeric(const std::string &name, uint16_t portDefault,
                        DNSLookupFn dns_lookup_function) {
     if (!ValidAsCString(name)) {
         return {};
     }
     CService addr;
     // "1.2:345" will fail to resolve the ip, but will still set the port.
     // If the ip fails to resolve, re-init the result.
     if (!Lookup(name, addr, portDefault, false, dns_lookup_function)) {
         addr = CService();
     }
     return addr;
 }
 
 /** SOCKS version */
 enum SOCKSVersion : uint8_t { SOCKS4 = 0x04, SOCKS5 = 0x05 };
 
 /** Values defined for METHOD in RFC1928 */
 enum SOCKS5Method : uint8_t {
     NOAUTH = 0x00,        //!< No authentication required
     GSSAPI = 0x01,        //!< GSSAPI
     USER_PASS = 0x02,     //!< Username/password
     NO_ACCEPTABLE = 0xff, //!< No acceptable methods
 };
 
 /** Values defined for CMD in RFC1928 */
 enum SOCKS5Command : uint8_t {
     CONNECT = 0x01,
     BIND = 0x02,
     UDP_ASSOCIATE = 0x03
 };
 
 /** Values defined for REP in RFC1928 */
 enum SOCKS5Reply : uint8_t {
     SUCCEEDED = 0x00,        //!< Succeeded
     GENFAILURE = 0x01,       //!< General failure
     NOTALLOWED = 0x02,       //!< Connection not allowed by ruleset
     NETUNREACHABLE = 0x03,   //!< Network unreachable
     HOSTUNREACHABLE = 0x04,  //!< Network unreachable
     CONNREFUSED = 0x05,      //!< Connection refused
     TTLEXPIRED = 0x06,       //!< TTL expired
     CMDUNSUPPORTED = 0x07,   //!< Command not supported
     ATYPEUNSUPPORTED = 0x08, //!< Address type not supported
 };
 
 /** Values defined for ATYPE in RFC1928 */
 enum SOCKS5Atyp : uint8_t {
     IPV4 = 0x01,
     DOMAINNAME = 0x03,
     IPV6 = 0x04,
 };
 
 /** Status codes that can be returned by InterruptibleRecv */
 enum class IntrRecvError {
     OK,
     Timeout,
     Disconnected,
     NetworkError,
     Interrupted
 };
 
 /**
  * Try to read a specified number of bytes from a socket. Please read the "see
  * also" section for more detail.
  *
  * @param data The buffer where the read bytes should be stored.
  * @param len The number of bytes to read into the specified buffer.
  * @param timeout The total timeout in milliseconds for this read.
  * @param sock The socket (has to be in non-blocking mode) from which to read
  * bytes.
  *
  * @returns An IntrRecvError indicating the resulting status of this read.
  *          IntrRecvError::OK only if all of the specified number of bytes were
  *          read.
  *
  * @see This function can be interrupted by calling InterruptSocks5(bool).
  *      Sockets can be made non-blocking with SetSocketNonBlocking(const
  *      SOCKET&, bool).
  */
 static IntrRecvError InterruptibleRecv(uint8_t *data, size_t len, int timeout,
                                        const Sock &sock) {
     int64_t curTime = GetTimeMillis();
     int64_t endTime = curTime + timeout;
     while (len > 0 && curTime < endTime) {
         // Optimistically try the recv first
         ssize_t ret = sock.Recv(data, len, 0);
         if (ret > 0) {
             len -= ret;
             data += ret;
         } else if (ret == 0) {
             // Unexpected disconnection
             return IntrRecvError::Disconnected;
         } else {
             // Other error or blocking
             int nErr = WSAGetLastError();
             if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK ||
                 nErr == WSAEINVAL) {
                 // Only wait at most MAX_WAIT_FOR_IO at a time, unless
                 // we're approaching the end of the specified total timeout
                 const auto remaining =
                     std::chrono::milliseconds{endTime - curTime};
                 const auto timeout_ = std::min(
                     remaining, std::chrono::milliseconds{MAX_WAIT_FOR_IO});
                 if (!sock.Wait(timeout_, Sock::RECV)) {
                     return IntrRecvError::NetworkError;
                 }
             } else {
                 return IntrRecvError::NetworkError;
             }
         }
         if (interruptSocks5Recv) {
             return IntrRecvError::Interrupted;
         }
         curTime = GetTimeMillis();
     }
     return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout;
 }
 
 /** Credentials for proxy authentication */
 struct ProxyCredentials {
     std::string username;
     std::string password;
 };
 
 /** Convert SOCKS5 reply to an error message */
 static std::string Socks5ErrorString(uint8_t err) {
     switch (err) {
         case SOCKS5Reply::GENFAILURE:
             return "general failure";
         case SOCKS5Reply::NOTALLOWED:
             return "connection not allowed";
         case SOCKS5Reply::NETUNREACHABLE:
             return "network unreachable";
         case SOCKS5Reply::HOSTUNREACHABLE:
             return "host unreachable";
         case SOCKS5Reply::CONNREFUSED:
             return "connection refused";
         case SOCKS5Reply::TTLEXPIRED:
             return "TTL expired";
         case SOCKS5Reply::CMDUNSUPPORTED:
             return "protocol error";
         case SOCKS5Reply::ATYPEUNSUPPORTED:
             return "address type not supported";
         default:
             return "unknown";
     }
 }
 
 /**
  * Connect to a specified destination service through an already connected
  * SOCKS5 proxy.
  *
  * @param strDest The destination fully-qualified domain name.
  * @param port The destination port.
  * @param auth The credentials with which to authenticate with the specified
  *             SOCKS5 proxy.
  * @param sock The SOCKS5 proxy socket.
  *
  * @returns Whether or not the operation succeeded.
  *
  * @note The specified SOCKS5 proxy socket must already be connected to the
  *       SOCKS5 proxy.
  *
  * @see <a href="https://www.ietf.org/rfc/rfc1928.txt">RFC1928: SOCKS Protocol
  *      Version 5</a>
  */
 static bool Socks5(const std::string &strDest, uint16_t port,
                    const ProxyCredentials *auth, const Sock &sock) {
     IntrRecvError recvr;
     LogPrint(BCLog::NET, "SOCKS5 connecting %s\n", strDest);
     if (strDest.size() > 255) {
         return error("Hostname too long");
     }
     // Construct the version identifier/method selection message
     std::vector<uint8_t> vSocks5Init;
     // We want the SOCK5 protocol
     vSocks5Init.push_back(SOCKSVersion::SOCKS5);
     if (auth) {
         // 2 method identifiers follow...
         vSocks5Init.push_back(0x02);
         vSocks5Init.push_back(SOCKS5Method::NOAUTH);
         vSocks5Init.push_back(SOCKS5Method::USER_PASS);
     } else {
         // 1 method identifier follows...
         vSocks5Init.push_back(0x01);
         vSocks5Init.push_back(SOCKS5Method::NOAUTH);
     }
     ssize_t ret =
         sock.Send(vSocks5Init.data(), vSocks5Init.size(), MSG_NOSIGNAL);
     if (ret != (ssize_t)vSocks5Init.size()) {
         return error("Error sending to proxy");
     }
     uint8_t pchRet1[2];
     if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, sock)) !=
         IntrRecvError::OK) {
         LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() "
                   "timeout or other failure\n",
                   strDest, port);
         return false;
     }
     if (pchRet1[0] != SOCKSVersion::SOCKS5) {
         return error("Proxy failed to initialize");
     }
     if (pchRet1[1] == SOCKS5Method::USER_PASS && auth) {
         // Perform username/password authentication (as described in RFC1929)
         std::vector<uint8_t> vAuth;
         // Current (and only) version of user/pass subnegotiation
         vAuth.push_back(0x01);
         if (auth->username.size() > 255 || auth->password.size() > 255) {
             return error("Proxy username or password too long");
         }
         vAuth.push_back(auth->username.size());
         vAuth.insert(vAuth.end(), auth->username.begin(), auth->username.end());
         vAuth.push_back(auth->password.size());
         vAuth.insert(vAuth.end(), auth->password.begin(), auth->password.end());
         ret = sock.Send(vAuth.data(), vAuth.size(), MSG_NOSIGNAL);
         if (ret != (ssize_t)vAuth.size()) {
             return error("Error sending authentication to proxy");
         }
         LogPrint(BCLog::PROXY, "SOCKS5 sending proxy authentication %s:%s\n",
                  auth->username, auth->password);
         uint8_t pchRetA[2];
         if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT,
                                        sock)) != IntrRecvError::OK) {
             return error("Error reading proxy authentication response");
         }
         if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) {
             return error("Proxy authentication unsuccessful");
         }
     } else if (pchRet1[1] == SOCKS5Method::NOAUTH) {
         // Perform no authentication
     } else {
         return error("Proxy requested wrong authentication method %02x",
                      pchRet1[1]);
     }
     std::vector<uint8_t> vSocks5;
     // VER protocol version
     vSocks5.push_back(SOCKSVersion::SOCKS5);
     // CMD CONNECT
     vSocks5.push_back(SOCKS5Command::CONNECT);
     // RSV Reserved must be 0
     vSocks5.push_back(0x00);
     // ATYP DOMAINNAME
     vSocks5.push_back(SOCKS5Atyp::DOMAINNAME);
     // Length<=255 is checked at beginning of function
     vSocks5.push_back(strDest.size());
     vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());
     vSocks5.push_back((port >> 8) & 0xFF);
     vSocks5.push_back((port >> 0) & 0xFF);
     ret = sock.Send(vSocks5.data(), vSocks5.size(), MSG_NOSIGNAL);
     if (ret != (ssize_t)vSocks5.size()) {
         return error("Error sending to proxy");
     }
     uint8_t pchRet2[4];
     if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, sock)) !=
         IntrRecvError::OK) {
         if (recvr == IntrRecvError::Timeout) {
             /**
              * If a timeout happens here, this effectively means we timed out
              * while connecting to the remote node. This is very common for Tor,
              * so do not print an error message.
              */
             return false;
         } else {
             return error("Error while reading proxy response");
         }
     }
     if (pchRet2[0] != SOCKSVersion::SOCKS5) {
         return error("Proxy failed to accept request");
     }
     if (pchRet2[1] != SOCKS5Reply::SUCCEEDED) {
         // Failures to connect to a peer that are not proxy errors
         LogPrintf("Socks5() connect to %s:%d failed: %s\n", strDest, port,
                   Socks5ErrorString(pchRet2[1]));
         return false;
     }
     // Reserved field must be 0
     if (pchRet2[2] != 0x00) {
         return error("Error: malformed proxy response");
     }
     uint8_t pchRet3[256];
     switch (pchRet2[3]) {
         case SOCKS5Atyp::IPV4:
             recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, sock);
             break;
         case SOCKS5Atyp::IPV6:
             recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, sock);
             break;
         case SOCKS5Atyp::DOMAINNAME: {
             recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, sock);
             if (recvr != IntrRecvError::OK) {
                 return error("Error reading from proxy");
             }
             int nRecv = pchRet3[0];
             recvr =
                 InterruptibleRecv(pchRet3, nRecv, SOCKS5_RECV_TIMEOUT, sock);
             break;
         }
         default:
             return error("Error: malformed proxy response");
     }
     if (recvr != IntrRecvError::OK) {
         return error("Error reading from proxy");
     }
     if ((recvr = InterruptibleRecv(pchRet3, 2, SOCKS5_RECV_TIMEOUT, sock)) !=
         IntrRecvError::OK) {
         return error("Error reading from proxy");
     }
     LogPrint(BCLog::NET, "SOCKS5 connected %s\n", strDest);
     return true;
 }
 
 std::unique_ptr<Sock> CreateSockTCP(const CService &address_family) {
     // Create a sockaddr from the specified service.
     struct sockaddr_storage sockaddr;
     socklen_t len = sizeof(sockaddr);
     if (!address_family.GetSockAddr((struct sockaddr *)&sockaddr, &len)) {
         LogPrintf("Cannot create socket for %s: unsupported network\n",
                   address_family.ToString());
         return nullptr;
     }
 
     // Create a TCP socket in the address family of the specified service.
     SOCKET hSocket = socket(((struct sockaddr *)&sockaddr)->sa_family,
                             SOCK_STREAM, IPPROTO_TCP);
     if (hSocket == INVALID_SOCKET) {
         return nullptr;
     }
 
     // Ensure that waiting for I/O on this socket won't result in undefined
     // behavior.
     if (!IsSelectableSocket(hSocket)) {
         CloseSocket(hSocket);
         LogPrintf("Cannot create connection: non-selectable socket created (fd "
                   ">= FD_SETSIZE ?)\n");
         return nullptr;
     }
 
 #ifdef SO_NOSIGPIPE
     int set = 1;
     // Set the no-sigpipe option on the socket for BSD systems, other UNIXes
     // should use the MSG_NOSIGNAL flag for every send.
     setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (sockopt_arg_type)&set,
                sizeof(int));
 #endif
 
     // Set the no-delay option (disable Nagle's algorithm) on the TCP socket.
     SetSocketNoDelay(hSocket);
 
     // Set the non-blocking option on the socket.
     if (!SetSocketNonBlocking(hSocket, true)) {
         CloseSocket(hSocket);
         LogPrintf("CreateSocket: Setting socket to non-blocking "
                   "failed, error %s\n",
                   NetworkErrorString(WSAGetLastError()));
         return nullptr;
     }
     return std::make_unique<Sock>(hSocket);
 }
 
 std::function<std::unique_ptr<Sock>(const CService &)> CreateSock =
     CreateSockTCP;
 
 template <typename... Args>
 static void LogConnectFailure(bool manual_connection, const char *fmt,
-                              const Args &... args) {
+                              const Args &...args) {
     std::string error_message = tfm::format(fmt, args...);
     if (manual_connection) {
         LogPrintf("%s\n", error_message);
     } else {
         LogPrint(BCLog::NET, "%s\n", error_message);
     }
 }
 
 bool ConnectSocketDirectly(const CService &addrConnect, const Sock &sock,
                            int nTimeout, bool manual_connection) {
     // Create a sockaddr from the specified service.
     struct sockaddr_storage sockaddr;
     socklen_t len = sizeof(sockaddr);
     if (sock.Get() == INVALID_SOCKET) {
         LogPrintf("Cannot connect to %s: invalid socket\n",
                   addrConnect.ToString());
         return false;
     }
     if (!addrConnect.GetSockAddr((struct sockaddr *)&sockaddr, &len)) {
         LogPrintf("Cannot connect to %s: unsupported network\n",
                   addrConnect.ToString());
         return false;
     }
 
     // Connect to the addrConnect service on the hSocket socket.
     if (sock.Connect(reinterpret_cast<struct sockaddr *>(&sockaddr), len) ==
         SOCKET_ERROR) {
         int nErr = WSAGetLastError();
         // WSAEINVAL is here because some legacy version of winsock uses it
         if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK ||
             nErr == WSAEINVAL) {
             // Connection didn't actually fail, but is being established
             // asynchronously. Thus, use async I/O api (select/poll)
             // synchronously to check for successful connection with a timeout.
             const Sock::Event requested = Sock::RECV | Sock::SEND;
             Sock::Event occurred;
             if (!sock.Wait(std::chrono::milliseconds{nTimeout}, requested,
                            &occurred)) {
                 LogPrintf("wait for connect to %s failed: %s\n",
                           addrConnect.ToString(),
                           NetworkErrorString(WSAGetLastError()));
                 return false;
             } else if (occurred == 0) {
                 LogPrint(BCLog::NET, "connection attempt to %s timed out\n",
                          addrConnect.ToString());
                 return false;
             }
 
             // Even if the wait was successful, the connect might not
             // have been successful. The reason for this failure is hidden away
             // in the SO_ERROR for the socket in modern systems. We read it into
             // sockerr here.
             int sockerr;
             socklen_t sockerr_len = sizeof(sockerr);
             if (sock.GetSockOpt(SOL_SOCKET, SO_ERROR,
                                 (sockopt_arg_type)&sockerr,
                                 &sockerr_len) == SOCKET_ERROR) {
                 LogPrintf("getsockopt() for %s failed: %s\n",
                           addrConnect.ToString(),
                           NetworkErrorString(WSAGetLastError()));
                 return false;
             }
             if (sockerr != 0) {
                 LogConnectFailure(
                     manual_connection, "connect() to %s failed after wait: %s",
                     addrConnect.ToString(), NetworkErrorString(sockerr));
                 return false;
             }
         }
 #ifdef WIN32
         else if (WSAGetLastError() != WSAEISCONN)
 #else
         else
 #endif
         {
             LogConnectFailure(manual_connection, "connect() to %s failed: %s",
                               addrConnect.ToString(),
                               NetworkErrorString(WSAGetLastError()));
             return false;
         }
     }
     return true;
 }
 
 bool SetProxy(enum Network net, const proxyType &addrProxy) {
     assert(net >= 0 && net < NET_MAX);
     if (!addrProxy.IsValid()) {
         return false;
     }
     LOCK(g_proxyinfo_mutex);
     proxyInfo[net] = addrProxy;
     return true;
 }
 
 bool GetProxy(enum Network net, proxyType &proxyInfoOut) {
     assert(net >= 0 && net < NET_MAX);
     LOCK(g_proxyinfo_mutex);
     if (!proxyInfo[net].IsValid()) {
         return false;
     }
     proxyInfoOut = proxyInfo[net];
     return true;
 }
 
 bool SetNameProxy(const proxyType &addrProxy) {
     if (!addrProxy.IsValid()) {
         return false;
     }
     LOCK(g_proxyinfo_mutex);
     nameProxy = addrProxy;
     return true;
 }
 
 bool GetNameProxy(proxyType &nameProxyOut) {
     LOCK(g_proxyinfo_mutex);
     if (!nameProxy.IsValid()) {
         return false;
     }
     nameProxyOut = nameProxy;
     return true;
 }
 
 bool HaveNameProxy() {
     LOCK(g_proxyinfo_mutex);
     return nameProxy.IsValid();
 }
 
 bool IsProxy(const CNetAddr &addr) {
     LOCK(g_proxyinfo_mutex);
     for (int i = 0; i < NET_MAX; i++) {
         if (addr == static_cast<CNetAddr>(proxyInfo[i].proxy)) {
             return true;
         }
     }
     return false;
 }
 
 bool ConnectThroughProxy(const proxyType &proxy, const std::string &strDest,
                          uint16_t port, const Sock &sock, int nTimeout,
                          bool &outProxyConnectionFailed) {
     // first connect to proxy server
     if (!ConnectSocketDirectly(proxy.proxy, sock, nTimeout, true)) {
         outProxyConnectionFailed = true;
         return false;
     }
     // do socks negotiation
     if (proxy.randomize_credentials) {
         ProxyCredentials random_auth;
         static std::atomic_int counter(0);
         random_auth.username = random_auth.password =
             strprintf("%i", counter++);
         if (!Socks5(strDest, port, &random_auth, sock)) {
             return false;
         }
     } else if (!Socks5(strDest, port, 0, sock)) {
         return false;
     }
     return true;
 }
 
 bool LookupSubNet(const std::string &strSubnet, CSubNet &ret,
                   DNSLookupFn dns_lookup_function) {
     if (!ValidAsCString(strSubnet)) {
         return false;
     }
     size_t slash = strSubnet.find_last_of('/');
     std::vector<CNetAddr> vIP;
 
     std::string strAddress = strSubnet.substr(0, slash);
     // TODO: Use LookupHost(const std::string&, CNetAddr&, bool) instead to just
     if (LookupHost(strAddress, vIP, 1, false, dns_lookup_function)) {
         CNetAddr network = vIP[0];
         if (slash != strSubnet.npos) {
             std::string strNetmask = strSubnet.substr(slash + 1);
             uint8_t n;
             if (ParseUInt8(strNetmask, &n)) {
                 // If valid number, assume CIDR variable-length subnet masking
                 ret = CSubNet(network, n);
                 return ret.IsValid();
             } else {
                 // If not a valid number, try full netmask syntax
                 // Never allow lookup for netmask
                 if (LookupHost(strNetmask, vIP, 1, false,
                                dns_lookup_function)) {
                     ret = CSubNet(network, vIP[0]);
                     return ret.IsValid();
                 }
             }
         } else {
             ret = CSubNet(network);
             return ret.IsValid();
         }
     }
     return false;
 }
 
 bool SetSocketNonBlocking(const SOCKET &hSocket, bool fNonBlocking) {
     if (fNonBlocking) {
 #ifdef WIN32
         u_long nOne = 1;
         if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR) {
 #else
         int fFlags = fcntl(hSocket, F_GETFL, 0);
         if (fcntl(hSocket, F_SETFL, fFlags | O_NONBLOCK) == SOCKET_ERROR) {
 #endif
             return false;
         }
     } else {
 #ifdef WIN32
         u_long nZero = 0;
         if (ioctlsocket(hSocket, FIONBIO, &nZero) == SOCKET_ERROR) {
 #else
         int fFlags = fcntl(hSocket, F_GETFL, 0);
         if (fcntl(hSocket, F_SETFL, fFlags & ~O_NONBLOCK) == SOCKET_ERROR) {
 #endif
             return false;
         }
     }
 
     return true;
 }
 
 bool SetSocketNoDelay(const SOCKET &hSocket) {
     int set = 1;
     int rc = setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY,
                         (sockopt_arg_type)&set, sizeof(int));
     return rc == 0;
 }
 
 void InterruptSocks5(bool interrupt) {
     interruptSocks5Recv = interrupt;
 }
diff --git a/src/netmessagemaker.h b/src/netmessagemaker.h
index b39da87a1..da5c51f94 100644
--- a/src/netmessagemaker.h
+++ b/src/netmessagemaker.h
@@ -1,37 +1,37 @@
 // Copyright (c) 2009-2010 Satoshi Nakamoto
 // Copyright (c) 2009-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.
 
 #ifndef BITCOIN_NETMESSAGEMAKER_H
 #define BITCOIN_NETMESSAGEMAKER_H
 
 #include <serialize.h>
 
 struct CSerializedNetMsg;
 class CVectorWriter;
 
 class CNetMsgMaker {
 public:
     explicit CNetMsgMaker(int nVersionIn) : nVersion(nVersionIn) {}
 
     template <typename... Args>
     CSerializedNetMsg Make(int nFlags, std::string msg_type,
-                           Args &&... args) const {
+                           Args &&...args) const {
         CSerializedNetMsg msg;
         msg.m_type = std::move(msg_type);
         CVectorWriter{SER_NETWORK, nFlags | nVersion, msg.data, 0,
                       std::forward<Args>(args)...};
         return msg;
     }
 
     template <typename... Args>
-    CSerializedNetMsg Make(std::string msg_type, Args &&... args) const {
+    CSerializedNetMsg Make(std::string msg_type, Args &&...args) const {
         return Make(0, std::move(msg_type), std::forward<Args>(args)...);
     }
 
 private:
     const int nVersion;
 };
 
 #endif // BITCOIN_NETMESSAGEMAKER_H
diff --git a/src/prevector.h b/src/prevector.h
index 8dc64a306..82f5c7c55 100644
--- a/src/prevector.h
+++ b/src/prevector.h
@@ -1,615 +1,615 @@
 // Copyright (c) 2015-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.
 
 #ifndef BITCOIN_PREVECTOR_H
 #define BITCOIN_PREVECTOR_H
 
 #include <algorithm>
 #include <cassert>
 #include <cstddef>
 #include <cstdint>
 #include <cstdlib>
 #include <cstring>
 #include <type_traits>
 #include <utility>
 
 /**
  * Implements a drop-in replacement for std::vector<T> which stores up to N
  * elements directly (without heap allocation). The types Size and Diff are used
  * to store element counts, and can be any unsigned + signed type.
  *
  * Storage layout is either:
  * - Direct allocation:
  *   - Size _size: the number of used elements (between 0 and N)
  *   - T direct[N]: an array of N elements of type T
  *     (only the first _size are initialized).
  * - Indirect allocation:
  *   - Size _size: the number of used elements plus N + 1
  *   - Size capacity: the number of allocated elements
  *   - T* indirect: a pointer to an array of capacity elements of type T
  *     (only the first _size are initialized).
  *
  * The data type T must be movable by memmove/realloc(). Once we switch to C++,
  * move constructors can be used instead.
  */
 template <unsigned int N, typename T, typename Size = uint32_t,
           typename Diff = int32_t>
 class prevector {
 public:
     typedef Size size_type;
     typedef Diff difference_type;
     typedef T value_type;
     typedef value_type &reference;
     typedef const value_type &const_reference;
     typedef value_type *pointer;
     typedef const value_type *const_pointer;
 
     class iterator {
         T *ptr;
 
     public:
         typedef Diff difference_type;
         typedef T value_type;
         typedef T *pointer;
         typedef T &reference;
         typedef std::random_access_iterator_tag iterator_category;
         iterator() : ptr(nullptr) {}
         iterator(T *ptr_) : ptr(ptr_) {}
         T &operator*() const { return *ptr; }
         T *operator->() const { return ptr; }
         T &operator[](size_type pos) { return ptr[pos]; }
         const T &operator[](size_type pos) const { return ptr[pos]; }
         iterator &operator++() {
             ptr++;
             return *this;
         }
         iterator &operator--() {
             ptr--;
             return *this;
         }
         iterator operator++(int) {
             iterator copy(*this);
             ++(*this);
             return copy;
         }
         iterator operator--(int) {
             iterator copy(*this);
             --(*this);
             return copy;
         }
         difference_type friend operator-(iterator a, iterator b) {
             return (&(*a) - &(*b));
         }
         iterator operator+(size_type n) { return iterator(ptr + n); }
         iterator &operator+=(size_type n) {
             ptr += n;
             return *this;
         }
         iterator operator-(size_type n) { return iterator(ptr - n); }
         iterator &operator-=(size_type n) {
             ptr -= n;
             return *this;
         }
         bool operator==(iterator x) const { return ptr == x.ptr; }
         bool operator!=(iterator x) const { return ptr != x.ptr; }
         bool operator>=(iterator x) const { return ptr >= x.ptr; }
         bool operator<=(iterator x) const { return ptr <= x.ptr; }
         bool operator>(iterator x) const { return ptr > x.ptr; }
         bool operator<(iterator x) const { return ptr < x.ptr; }
     };
 
     class reverse_iterator {
         T *ptr;
 
     public:
         typedef Diff difference_type;
         typedef T value_type;
         typedef T *pointer;
         typedef T &reference;
         typedef std::bidirectional_iterator_tag iterator_category;
         reverse_iterator() : ptr(nullptr) {}
         reverse_iterator(T *ptr_) : ptr(ptr_) {}
         T &operator*() { return *ptr; }
         const T &operator*() const { return *ptr; }
         T *operator->() { return ptr; }
         const T *operator->() const { return ptr; }
         reverse_iterator &operator--() {
             ptr++;
             return *this;
         }
         reverse_iterator &operator++() {
             ptr--;
             return *this;
         }
         reverse_iterator operator++(int) {
             reverse_iterator copy(*this);
             ++(*this);
             return copy;
         }
         reverse_iterator operator--(int) {
             reverse_iterator copy(*this);
             --(*this);
             return copy;
         }
         bool operator==(reverse_iterator x) const { return ptr == x.ptr; }
         bool operator!=(reverse_iterator x) const { return ptr != x.ptr; }
     };
 
     class const_iterator {
         const T *ptr;
 
     public:
         typedef Diff difference_type;
         typedef const T value_type;
         typedef const T *pointer;
         typedef const T &reference;
         typedef std::random_access_iterator_tag iterator_category;
         const_iterator() : ptr(nullptr) {}
         const_iterator(const T *ptr_) : ptr(ptr_) {}
         const_iterator(iterator x) : ptr(&(*x)) {}
         const T &operator*() const { return *ptr; }
         const T *operator->() const { return ptr; }
         const T &operator[](size_type pos) const { return ptr[pos]; }
         const_iterator &operator++() {
             ptr++;
             return *this;
         }
         const_iterator &operator--() {
             ptr--;
             return *this;
         }
         const_iterator operator++(int) {
             const_iterator copy(*this);
             ++(*this);
             return copy;
         }
         const_iterator operator--(int) {
             const_iterator copy(*this);
             --(*this);
             return copy;
         }
         difference_type friend operator-(const_iterator a, const_iterator b) {
             return (&(*a) - &(*b));
         }
         const_iterator operator+(size_type n) {
             return const_iterator(ptr + n);
         }
         const_iterator &operator+=(size_type n) {
             ptr += n;
             return *this;
         }
         const_iterator operator-(size_type n) {
             return const_iterator(ptr - n);
         }
         const_iterator &operator-=(size_type n) {
             ptr -= n;
             return *this;
         }
         bool operator==(const_iterator x) const { return ptr == x.ptr; }
         bool operator!=(const_iterator x) const { return ptr != x.ptr; }
         bool operator>=(const_iterator x) const { return ptr >= x.ptr; }
         bool operator<=(const_iterator x) const { return ptr <= x.ptr; }
         bool operator>(const_iterator x) const { return ptr > x.ptr; }
         bool operator<(const_iterator x) const { return ptr < x.ptr; }
     };
 
     class const_reverse_iterator {
         const T *ptr;
 
     public:
         typedef Diff difference_type;
         typedef const T value_type;
         typedef const T *pointer;
         typedef const T &reference;
         typedef std::bidirectional_iterator_tag iterator_category;
         const_reverse_iterator() : ptr(nullptr) {}
         const_reverse_iterator(const T *ptr_) : ptr(ptr_) {}
         const_reverse_iterator(reverse_iterator x) : ptr(&(*x)) {}
         const T &operator*() const { return *ptr; }
         const T *operator->() const { return ptr; }
         const_reverse_iterator &operator--() {
             ptr++;
             return *this;
         }
         const_reverse_iterator &operator++() {
             ptr--;
             return *this;
         }
         const_reverse_iterator operator++(int) {
             const_reverse_iterator copy(*this);
             ++(*this);
             return copy;
         }
         const_reverse_iterator operator--(int) {
             const_reverse_iterator copy(*this);
             --(*this);
             return copy;
         }
         bool operator==(const_reverse_iterator x) const { return ptr == x.ptr; }
         bool operator!=(const_reverse_iterator x) const { return ptr != x.ptr; }
     };
 
 private:
 #pragma pack(push, 1)
     union direct_or_indirect {
         char direct[sizeof(T) * N];
         struct {
             char *indirect;
             size_type capacity;
         } indirect_contents;
     };
 #pragma pack(pop)
     alignas(char *) direct_or_indirect _union = {};
     size_type _size = 0;
 
     static_assert(alignof(char *) % alignof(size_type) == 0 &&
                       sizeof(char *) % alignof(size_type) == 0,
                   "size_type cannot have more restrictive alignment "
                   "requirement than pointer");
     static_assert(alignof(char *) % alignof(T) == 0,
                   "value_type T cannot have more restrictive alignment "
                   "requirement than pointer");
 
     T *direct_ptr(difference_type pos) {
         return reinterpret_cast<T *>(_union.direct) + pos;
     }
     const T *direct_ptr(difference_type pos) const {
         return reinterpret_cast<const T *>(_union.direct) + pos;
     }
     T *indirect_ptr(difference_type pos) {
         return reinterpret_cast<T *>(_union.indirect_contents.indirect) + pos;
     }
     const T *indirect_ptr(difference_type pos) const {
         return reinterpret_cast<const T *>(_union.indirect_contents.indirect) +
                pos;
     }
     bool is_direct() const { return _size <= N; }
 
     void change_capacity(size_type new_capacity) {
         if (new_capacity <= N) {
             if (!is_direct()) {
                 T *indirect = indirect_ptr(0);
                 T *src = indirect;
                 T *dst = direct_ptr(0);
                 memcpy(dst, src, size() * sizeof(T));
                 free(indirect);
                 _size -= N + 1;
             }
         } else {
             if (!is_direct()) {
                 // FIXME: Because malloc/realloc here won't call new_handler if
                 // allocation fails, assert success. These should instead use an
                 // allocator or new/delete so that handlers are called as
                 // necessary, but performance would be slightly degraded by
                 // doing so.
                 _union.indirect_contents.indirect = static_cast<char *>(
                     realloc(_union.indirect_contents.indirect,
                             ((size_t)sizeof(T)) * new_capacity));
                 assert(_union.indirect_contents.indirect);
                 _union.indirect_contents.capacity = new_capacity;
             } else {
                 char *new_indirect = static_cast<char *>(
                     malloc(((size_t)sizeof(T)) * new_capacity));
                 assert(new_indirect);
                 T *src = direct_ptr(0);
                 T *dst = reinterpret_cast<T *>(new_indirect);
                 memcpy(dst, src, size() * sizeof(T));
                 _union.indirect_contents.indirect = new_indirect;
                 _union.indirect_contents.capacity = new_capacity;
                 _size += N + 1;
             }
         }
     }
 
     T *item_ptr(difference_type pos) {
         return is_direct() ? direct_ptr(pos) : indirect_ptr(pos);
     }
     const T *item_ptr(difference_type pos) const {
         return is_direct() ? direct_ptr(pos) : indirect_ptr(pos);
     }
 
     void fill(T *dst, ptrdiff_t count, const T &value = T{}) {
         std::fill_n(dst, count, value);
     }
 
     template <typename InputIterator>
     void fill(T *dst, InputIterator first, InputIterator last) {
         while (first != last) {
             new (static_cast<void *>(dst)) T(*first);
             ++dst;
             ++first;
         }
     }
 
 public:
     void assign(size_type n, const T &val) {
         clear();
         if (capacity() < n) {
             change_capacity(n);
         }
         _size += n;
         fill(item_ptr(0), n, val);
     }
 
     template <typename InputIterator>
     void assign(InputIterator first, InputIterator last) {
         size_type n = last - first;
         clear();
         if (capacity() < n) {
             change_capacity(n);
         }
         _size += n;
         fill(item_ptr(0), first, last);
     }
 
     prevector() {}
 
     explicit prevector(size_type n) { resize(n); }
 
     explicit prevector(size_type n, const T &val) {
         change_capacity(n);
         _size += n;
         fill(item_ptr(0), n, val);
     }
 
     template <typename InputIterator>
     prevector(InputIterator first, InputIterator last) {
         size_type n = last - first;
         change_capacity(n);
         _size += n;
         fill(item_ptr(0), first, last);
     }
 
     prevector(const prevector<N, T, Size, Diff> &other) {
         size_type n = other.size();
         change_capacity(n);
         _size += n;
         fill(item_ptr(0), other.begin(), other.end());
     }
 
     prevector(prevector<N, T, Size, Diff> &&other) { swap(other); }
 
     prevector &operator=(const prevector<N, T, Size, Diff> &other) {
         if (&other == this) {
             return *this;
         }
         assign(other.begin(), other.end());
         return *this;
     }
 
     prevector &operator=(prevector<N, T, Size, Diff> &&other) {
         swap(other);
         return *this;
     }
 
     size_type size() const { return is_direct() ? _size : _size - N - 1; }
 
     bool empty() const { return size() == 0; }
 
     iterator begin() { return iterator(item_ptr(0)); }
     const_iterator begin() const { return const_iterator(item_ptr(0)); }
     iterator end() { return iterator(item_ptr(size())); }
     const_iterator end() const { return const_iterator(item_ptr(size())); }
 
     reverse_iterator rbegin() { return reverse_iterator(item_ptr(size() - 1)); }
     const_reverse_iterator rbegin() const {
         return const_reverse_iterator(item_ptr(size() - 1));
     }
     reverse_iterator rend() { return reverse_iterator(item_ptr(-1)); }
     const_reverse_iterator rend() const {
         return const_reverse_iterator(item_ptr(-1));
     }
 
     size_t capacity() const {
         if (is_direct()) {
             return N;
         } else {
             return _union.indirect_contents.capacity;
         }
     }
 
     T &operator[](size_type pos) { return *item_ptr(pos); }
 
     const T &operator[](size_type pos) const { return *item_ptr(pos); }
 
     void resize(size_type new_size) {
         size_type cur_size = size();
         if (cur_size == new_size) {
             return;
         }
         if (cur_size > new_size) {
             erase(item_ptr(new_size), end());
             return;
         }
         if (new_size > capacity()) {
             change_capacity(new_size);
         }
         ptrdiff_t increase = new_size - cur_size;
         fill(item_ptr(cur_size), increase);
         _size += increase;
     }
 
     void reserve(size_type new_capacity) {
         if (new_capacity > capacity()) {
             change_capacity(new_capacity);
         }
     }
 
     void shrink_to_fit() { change_capacity(size()); }
 
     void clear() { resize(0); }
 
     iterator insert(iterator pos, const T &value) {
         size_type p = pos - begin();
         size_type new_size = size() + 1;
         if (capacity() < new_size) {
             change_capacity(new_size + (new_size >> 1));
         }
         T *ptr = item_ptr(p);
         memmove(ptr + 1, ptr, (size() - p) * sizeof(T));
         _size++;
         new (static_cast<void *>(ptr)) T(value);
         return iterator(ptr);
     }
 
     void insert(iterator pos, size_type count, const T &value) {
         size_type p = pos - begin();
         size_type new_size = size() + count;
         if (capacity() < new_size) {
             change_capacity(new_size + (new_size >> 1));
         }
         T *ptr = item_ptr(p);
         memmove(ptr + count, ptr, (size() - p) * sizeof(T));
         _size += count;
         fill(item_ptr(p), count, value);
     }
 
     template <typename InputIterator>
     void insert(iterator pos, InputIterator first, InputIterator last) {
         size_type p = pos - begin();
         difference_type count = last - first;
         size_type new_size = size() + count;
         if (capacity() < new_size) {
             change_capacity(new_size + (new_size >> 1));
         }
         T *ptr = item_ptr(p);
         memmove(ptr + count, ptr, (size() - p) * sizeof(T));
         _size += count;
         fill(ptr, first, last);
     }
 
     inline void resize_uninitialized(size_type new_size) {
         // resize_uninitialized changes the size of the prevector but does not
         // initialize it. If size < new_size, the added elements must be
         // initialized explicitly.
         if (capacity() < new_size) {
             change_capacity(new_size);
             _size += new_size - size();
             return;
         }
         if (new_size < size()) {
             erase(item_ptr(new_size), end());
         } else {
             _size += new_size - size();
         }
     }
 
     iterator erase(iterator pos) { return erase(pos, pos + 1); }
 
     iterator erase(iterator first, iterator last) {
         // Erase is not allowed to the change the object's capacity. That means
         // that when starting with an indirectly allocated prevector with
         // size and capacity > N, the result may be a still indirectly allocated
         // prevector with size <= N and capacity > N. A shrink_to_fit() call is
         // necessary to switch to the (more efficient) directly allocated
         // representation (with capacity N and size <= N).
         iterator p = first;
         char *endp = (char *)&(*end());
         if (!std::is_trivially_destructible<T>::value) {
             while (p != last) {
                 (*p).~T();
                 _size--;
                 ++p;
             }
         } else {
             _size -= last - p;
         }
         memmove(&(*first), &(*last), endp - ((char *)(&(*last))));
         return first;
     }
 
-    template <typename... Args> void emplace_back(Args &&... args) {
+    template <typename... Args> void emplace_back(Args &&...args) {
         size_type new_size = size() + 1;
         if (capacity() < new_size) {
             change_capacity(new_size + (new_size >> 1));
         }
         new (item_ptr(size())) T(std::forward<Args>(args)...);
         _size++;
     }
 
     void push_back(const T &value) { emplace_back(value); }
 
     void pop_back() { erase(end() - 1, end()); }
 
     T &front() { return *item_ptr(0); }
 
     const T &front() const { return *item_ptr(0); }
 
     T &back() { return *item_ptr(size() - 1); }
 
     const T &back() const { return *item_ptr(size() - 1); }
 
     void swap(prevector<N, T, Size, Diff> &other) {
         std::swap(_union, other._union);
         std::swap(_size, other._size);
     }
 
     ~prevector() {
         if (!std::is_trivially_destructible<T>::value) {
             clear();
         }
         if (!is_direct()) {
             free(_union.indirect_contents.indirect);
             _union.indirect_contents.indirect = nullptr;
         }
     }
 
     bool operator==(const prevector<N, T, Size, Diff> &other) const {
         if (other.size() != size()) {
             return false;
         }
         const_iterator b1 = begin();
         const_iterator b2 = other.begin();
         const_iterator e1 = end();
         while (b1 != e1) {
             if ((*b1) != (*b2)) {
                 return false;
             }
             ++b1;
             ++b2;
         }
         return true;
     }
 
     bool operator!=(const prevector<N, T, Size, Diff> &other) const {
         return !(*this == other);
     }
 
     bool operator<(const prevector<N, T, Size, Diff> &other) const {
         if (size() < other.size()) {
             return true;
         }
         if (size() > other.size()) {
             return false;
         }
         const_iterator b1 = begin();
         const_iterator b2 = other.begin();
         const_iterator e1 = end();
         while (b1 != e1) {
             if ((*b1) < (*b2)) {
                 return true;
             }
             if ((*b2) < (*b1)) {
                 return false;
             }
             ++b1;
             ++b2;
         }
         return false;
     }
 
     size_t allocated_memory() const {
         if (is_direct()) {
             return 0;
         } else {
             return ((size_t)(sizeof(T))) * _union.indirect_contents.capacity;
         }
     }
 
     value_type *data() { return item_ptr(0); }
 
     const value_type *data() const { return item_ptr(0); }
 };
 
 #endif // BITCOIN_PREVECTOR_H
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 7d78628d7..9d9c3ec50 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -1,1660 +1,1658 @@
 // Copyright (c) 2011-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.
 
 #include <qt/bitcoingui.h>
 
 #include <chain.h>
 #include <chainparams.h>
 #include <config.h>
 #include <interfaces/handler.h>
 #include <interfaces/node.h>
 #include <node/ui_interface.h>
 #include <qt/bitcoinunits.h>
 #include <qt/clientmodel.h>
 #include <qt/createwalletdialog.h>
 #include <qt/guiconstants.h>
 #include <qt/guiutil.h>
 #ifdef Q_OS_MAC
 #include <qt/macdockiconhandler.h>
 #endif
 #include <qt/modaloverlay.h>
 #include <qt/networkstyle.h>
 #include <qt/notificator.h>
 #include <qt/openuridialog.h>
 #include <qt/optionsmodel.h>
 #include <qt/platformstyle.h>
 #include <qt/rpcconsole.h>
 #include <qt/utilitydialog.h>
 #ifdef ENABLE_WALLET
 #include <qt/walletcontroller.h>
 #include <qt/walletframe.h>
 #include <qt/walletmodel.h>
 #include <qt/walletview.h>
 #endif // ENABLE_WALLET
 #include <util/system.h>
 #include <util/translation.h>
 #include <validation.h>
 
 #include <functional>
 #include <memory>
 
 #include <QAction>
 #include <QApplication>
 #include <QComboBox>
 #include <QDateTime>
 #include <QDragEnterEvent>
 #include <QListWidget>
 #include <QMenu>
 #include <QMenuBar>
 #include <QMessageBox>
 #include <QMimeData>
 #include <QProgressDialog>
 #include <QScreen>
 #include <QSettings>
 #include <QShortcut>
 #include <QStackedWidget>
 #include <QStatusBar>
 #include <QStyle>
 #include <QSystemTrayIcon>
 #include <QTimer>
 #include <QToolBar>
 #include <QUrlQuery>
 #include <QVBoxLayout>
 #include <QWindow>
 
 const std::string BitcoinGUI::DEFAULT_UIPLATFORM =
 #if defined(Q_OS_MAC)
     "macosx"
 #elif defined(Q_OS_WIN)
     "windows"
 #else
     "other"
 #endif
     ;
 
 BitcoinGUI::BitcoinGUI(interfaces::Node &node, const Config *configIn,
                        const PlatformStyle *_platformStyle,
                        const NetworkStyle *networkStyle, QWidget *parent)
     : QMainWindow(parent), m_node(node), trayIconMenu{new QMenu()},
       config(configIn), platformStyle(_platformStyle),
       m_network_style(networkStyle) {
     QSettings settings;
     if (!restoreGeometry(settings.value("MainWindowGeometry").toByteArray())) {
         // Restore failed (perhaps missing setting), center the window
         move(QGuiApplication::primaryScreen()->availableGeometry().center() -
              frameGeometry().center());
     }
 
 #ifdef ENABLE_WALLET
     enableWallet = WalletModel::isWalletEnabled();
 #endif // ENABLE_WALLET
     QApplication::setWindowIcon(m_network_style->getTrayAndWindowIcon());
     setWindowIcon(m_network_style->getTrayAndWindowIcon());
     updateWindowTitle();
 
     rpcConsole = new RPCConsole(node, _platformStyle, nullptr);
     helpMessageDialog = new HelpMessageDialog(this, false);
 #ifdef ENABLE_WALLET
     if (enableWallet) {
         /** Create wallet frame and make it the central widget */
         walletFrame = new WalletFrame(_platformStyle, this);
         setCentralWidget(walletFrame);
     } else
 #endif // ENABLE_WALLET
     {
         /**
          * When compiled without wallet or -disablewallet is provided,  the
          * central widget is the rpc console.
          */
         setCentralWidget(rpcConsole);
         Q_EMIT consoleShown(rpcConsole);
     }
 
     modalOverlay = new ModalOverlay(enableWallet, this->centralWidget());
 
     // Accept D&D of URIs
     setAcceptDrops(true);
 
     // Create actions for the toolbar, menu bar and tray/dock icon
     // Needs walletFrame to be initialized
     createActions();
 
     // Create application menu bar
     createMenuBar();
 
     // Create the toolbars
     createToolBars();
 
     // Create system tray icon and notification
     if (QSystemTrayIcon::isSystemTrayAvailable()) {
         createTrayIcon();
     }
     notificator =
         new Notificator(QApplication::applicationName(), trayIcon, this);
 
     // Create status bar
     statusBar();
 
     // Disable size grip because it looks ugly and nobody needs it
     statusBar()->setSizeGripEnabled(false);
 
     // Status bar notification icons
     QFrame *frameBlocks = new QFrame();
     frameBlocks->setContentsMargins(0, 0, 0, 0);
     frameBlocks->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
     QHBoxLayout *frameBlocksLayout = new QHBoxLayout(frameBlocks);
     frameBlocksLayout->setContentsMargins(3, 0, 3, 0);
     frameBlocksLayout->setSpacing(3);
     unitDisplayControl = new UnitDisplayStatusBarControl(platformStyle);
     labelWalletEncryptionIcon = new QLabel();
     labelWalletHDStatusIcon = new QLabel();
     labelProxyIcon = new GUIUtil::ClickableLabel();
     connectionsControl = new GUIUtil::ClickableLabel();
     labelBlocksIcon = new GUIUtil::ClickableLabel();
     if (enableWallet) {
         frameBlocksLayout->addStretch();
         frameBlocksLayout->addWidget(unitDisplayControl);
         frameBlocksLayout->addStretch();
         frameBlocksLayout->addWidget(labelWalletEncryptionIcon);
         frameBlocksLayout->addWidget(labelWalletHDStatusIcon);
     }
     frameBlocksLayout->addWidget(labelProxyIcon);
     frameBlocksLayout->addStretch();
     frameBlocksLayout->addWidget(connectionsControl);
     frameBlocksLayout->addStretch();
     frameBlocksLayout->addWidget(labelBlocksIcon);
     frameBlocksLayout->addStretch();
 
     // Progress bar and label for blocks download
     progressBarLabel = new QLabel();
     progressBarLabel->setVisible(false);
     progressBar = new GUIUtil::ProgressBar();
     progressBar->setAlignment(Qt::AlignCenter);
     progressBar->setVisible(false);
 
     // Override style sheet for progress bar for styles that have a segmented
     // progress bar, as they make the text unreadable (workaround for issue
     // #1071)
     // See https://doc.qt.io/qt-5/gallery.html
     QString curStyle = QApplication::style()->metaObject()->className();
     if (curStyle == "QWindowsStyle" || curStyle == "QWindowsXPStyle") {
         progressBar->setStyleSheet(
             "QProgressBar { background-color: #e8e8e8; border: 1px solid grey; "
             "border-radius: 7px; padding: 1px; text-align: center; } "
             "QProgressBar::chunk { background: QLinearGradient(x1: 0, y1: 0, "
             "x2: 1, y2: 0, stop: 0 #FF8000, stop: 1 orange); border-radius: "
             "7px; margin: 0px; }");
     }
 
     statusBar()->addWidget(progressBarLabel);
     statusBar()->addWidget(progressBar);
     statusBar()->addPermanentWidget(frameBlocks);
 
     // Install event filter to be able to catch status tip events
     // (QEvent::StatusTip)
     this->installEventFilter(this);
 
     // Initially wallet actions should be disabled
     setWalletActionsEnabled(false);
 
     // Subscribe to notifications from core
     subscribeToCoreSignals();
 
     connect(connectionsControl, &GUIUtil::ClickableLabel::clicked,
             [this] { m_node.setNetworkActive(!m_node.getNetworkActive()); });
     connect(labelProxyIcon, &GUIUtil::ClickableLabel::clicked,
             [this] { openOptionsDialogWithTab(OptionsDialog::TAB_NETWORK); });
 
     connect(labelBlocksIcon, &GUIUtil::ClickableLabel::clicked, this,
             &BitcoinGUI::showModalOverlay);
     connect(progressBar, &GUIUtil::ClickableProgressBar::clicked, this,
             &BitcoinGUI::showModalOverlay);
 #ifdef ENABLE_WALLET
     if (enableWallet) {
         connect(walletFrame, &WalletFrame::requestedSyncWarningInfo, this,
                 &BitcoinGUI::showModalOverlay);
     }
 #endif
 
 #ifdef Q_OS_MAC
     m_app_nap_inhibitor = new CAppNapInhibitor;
 #endif
 
     GUIUtil::handleCloseWindowShortcut(this);
 }
 
 BitcoinGUI::~BitcoinGUI() {
     // Unsubscribe from notifications from core
     unsubscribeFromCoreSignals();
 
     QSettings settings;
     settings.setValue("MainWindowGeometry", saveGeometry());
     // Hide tray icon, as deleting will let it linger until quit (on Ubuntu)
     if (trayIcon) {
         trayIcon->hide();
     }
 #ifdef Q_OS_MAC
     delete m_app_nap_inhibitor;
     delete appMenuBar;
     MacDockIconHandler::cleanup();
 #endif
 
     delete rpcConsole;
 }
 
 void BitcoinGUI::createActions() {
     QActionGroup *tabGroup = new QActionGroup(this);
     connect(modalOverlay, &ModalOverlay::triggered, tabGroup,
             &QActionGroup::setEnabled);
 
     overviewAction =
         new QAction(platformStyle->SingleColorIcon(":/icons/overview"),
                     tr("&Overview"), this);
     overviewAction->setStatusTip(tr("Show general overview of wallet"));
     overviewAction->setToolTip(overviewAction->statusTip());
     overviewAction->setCheckable(true);
     overviewAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_1));
     tabGroup->addAction(overviewAction);
 
     sendCoinsAction = new QAction(
         platformStyle->SingleColorIcon(":/icons/send"), tr("&Send"), this);
     sendCoinsAction->setStatusTip(tr("Send coins to a Bitcoin address"));
     sendCoinsAction->setToolTip(sendCoinsAction->statusTip());
     sendCoinsAction->setCheckable(true);
     sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2));
     tabGroup->addAction(sendCoinsAction);
 
     sendCoinsMenuAction = new QAction(sendCoinsAction->text(), this);
     sendCoinsMenuAction->setStatusTip(sendCoinsAction->statusTip());
     sendCoinsMenuAction->setToolTip(sendCoinsMenuAction->statusTip());
 
     receiveCoinsAction = new QAction(
         platformStyle->SingleColorIcon(":/icons/receiving_addresses"),
         tr("&Receive"), this);
     receiveCoinsAction->setStatusTip(
         tr("Request payments (generates QR codes and %1: URIs)")
             .arg(QString::fromStdString(
                 config->GetChainParams().CashAddrPrefix())));
     receiveCoinsAction->setToolTip(receiveCoinsAction->statusTip());
     receiveCoinsAction->setCheckable(true);
     receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3));
     tabGroup->addAction(receiveCoinsAction);
 
     receiveCoinsMenuAction = new QAction(receiveCoinsAction->text(), this);
     receiveCoinsMenuAction->setStatusTip(receiveCoinsAction->statusTip());
     receiveCoinsMenuAction->setToolTip(receiveCoinsMenuAction->statusTip());
 
     historyAction =
         new QAction(platformStyle->SingleColorIcon(":/icons/history"),
                     tr("&Transactions"), this);
     historyAction->setStatusTip(tr("Browse transaction history"));
     historyAction->setToolTip(historyAction->statusTip());
     historyAction->setCheckable(true);
     historyAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_4));
     tabGroup->addAction(historyAction);
 
 #ifdef ENABLE_WALLET
     // These showNormalIfMinimized are needed because Send Coins and Receive
     // Coins can be triggered from the tray menu, and need to show the GUI to be
     // useful.
     connect(overviewAction, &QAction::triggered,
             [this] { showNormalIfMinimized(); });
     connect(overviewAction, &QAction::triggered, this,
             &BitcoinGUI::gotoOverviewPage);
     connect(sendCoinsAction, &QAction::triggered,
             [this] { showNormalIfMinimized(); });
     connect(sendCoinsAction, &QAction::triggered,
             [this] { gotoSendCoinsPage(); });
     connect(sendCoinsMenuAction, &QAction::triggered,
             [this] { showNormalIfMinimized(); });
     connect(sendCoinsMenuAction, &QAction::triggered,
             [this] { gotoSendCoinsPage(); });
     connect(receiveCoinsAction, &QAction::triggered,
             [this] { showNormalIfMinimized(); });
     connect(receiveCoinsAction, &QAction::triggered, this,
             &BitcoinGUI::gotoReceiveCoinsPage);
     connect(receiveCoinsMenuAction, &QAction::triggered,
             [this] { showNormalIfMinimized(); });
     connect(receiveCoinsMenuAction, &QAction::triggered, this,
             &BitcoinGUI::gotoReceiveCoinsPage);
     connect(historyAction, &QAction::triggered,
             [this] { showNormalIfMinimized(); });
     connect(historyAction, &QAction::triggered, this,
             &BitcoinGUI::gotoHistoryPage);
 #endif // ENABLE_WALLET
 
     quitAction = new QAction(tr("E&xit"), this);
     quitAction->setStatusTip(tr("Quit application"));
     quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
     quitAction->setMenuRole(QAction::QuitRole);
     aboutAction = new QAction(tr("&About %1").arg(PACKAGE_NAME), this);
     aboutAction->setStatusTip(
         tr("Show information about %1").arg(PACKAGE_NAME));
     aboutAction->setMenuRole(QAction::AboutRole);
     aboutAction->setEnabled(false);
     aboutQtAction = new QAction(tr("About &Qt"), this);
     aboutQtAction->setStatusTip(tr("Show information about Qt"));
     aboutQtAction->setMenuRole(QAction::AboutQtRole);
     optionsAction = new QAction(tr("&Options..."), this);
     optionsAction->setStatusTip(
         tr("Modify configuration options for %1").arg(PACKAGE_NAME));
     optionsAction->setMenuRole(QAction::PreferencesRole);
     optionsAction->setEnabled(false);
     toggleHideAction = new QAction(tr("&Show / Hide"), this);
     toggleHideAction->setStatusTip(tr("Show or hide the main Window"));
 
     encryptWalletAction = new QAction(tr("&Encrypt Wallet..."), this);
     encryptWalletAction->setStatusTip(
         tr("Encrypt the private keys that belong to your wallet"));
     encryptWalletAction->setCheckable(true);
     backupWalletAction = new QAction(tr("&Backup Wallet..."), this);
     backupWalletAction->setStatusTip(tr("Backup wallet to another location"));
     changePassphraseAction = new QAction(tr("&Change Passphrase..."), this);
     changePassphraseAction->setStatusTip(
         tr("Change the passphrase used for wallet encryption"));
     signMessageAction = new QAction(tr("Sign &message..."), this);
     signMessageAction->setStatusTip(
         tr("Sign messages with your Bitcoin addresses to prove you own them"));
     verifyMessageAction = new QAction(tr("&Verify message..."), this);
     verifyMessageAction->setStatusTip(
         tr("Verify messages to ensure they were signed with specified Bitcoin "
            "addresses"));
     m_load_psbt_action = new QAction(tr("Load PSBT..."), this);
     m_load_psbt_action->setStatusTip(
         tr("Load Partially Signed Bitcoin Transaction"));
 
     openRPCConsoleAction = new QAction(tr("&Debug window"), this);
     openRPCConsoleAction->setStatusTip(
         tr("Open node debugging and diagnostic console"));
     // initially disable the debug window menu item
     openRPCConsoleAction->setEnabled(false);
     openRPCConsoleAction->setObjectName("openRPCConsoleAction");
 
     usedSendingAddressesAction = new QAction(tr("&Sending addresses"), this);
     usedSendingAddressesAction->setStatusTip(
         tr("Show the list of used sending addresses and labels"));
     usedReceivingAddressesAction =
         new QAction(tr("&Receiving addresses"), this);
     usedReceivingAddressesAction->setStatusTip(
         tr("Show the list of used receiving addresses and labels"));
 
     openAction = new QAction(tr("Open &URI..."), this);
     openAction->setStatusTip(
         tr("Open a %1: URI or payment request")
             .arg(QString::fromStdString(
                 config->GetChainParams().CashAddrPrefix())));
 
     m_open_wallet_action = new QAction(tr("Open Wallet"), this);
     m_open_wallet_action->setEnabled(false);
     m_open_wallet_action->setStatusTip(tr("Open a wallet"));
     m_open_wallet_menu = new QMenu(this);
 
     m_close_wallet_action = new QAction(tr("Close Wallet..."), this);
     m_close_wallet_action->setStatusTip(tr("Close wallet"));
 
     m_create_wallet_action = new QAction(tr("Create Wallet..."), this);
     m_create_wallet_action->setEnabled(false);
     m_create_wallet_action->setStatusTip(tr("Create a new wallet"));
 
     m_close_all_wallets_action = new QAction(tr("Close All Wallets..."), this);
     m_close_all_wallets_action->setStatusTip(tr("Close all wallets"));
 
     showHelpMessageAction = new QAction(tr("&Command-line options"), this);
     showHelpMessageAction->setMenuRole(QAction::NoRole);
     showHelpMessageAction->setStatusTip(
         tr("Show the %1 help message to get a list with possible Bitcoin "
            "command-line options")
             .arg(PACKAGE_NAME));
 
     m_mask_values_action = new QAction(tr("&Mask values"), this);
     m_mask_values_action->setShortcut(
         QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_M));
     m_mask_values_action->setStatusTip(
         tr("Mask the values in the Overview tab"));
     m_mask_values_action->setCheckable(true);
 
     connect(quitAction, &QAction::triggered, qApp, QApplication::quit);
     connect(aboutAction, &QAction::triggered, this, &BitcoinGUI::aboutClicked);
     connect(aboutQtAction, &QAction::triggered, qApp, QApplication::aboutQt);
     connect(optionsAction, &QAction::triggered, this,
             &BitcoinGUI::optionsClicked);
     connect(toggleHideAction, &QAction::triggered, this,
             &BitcoinGUI::toggleHidden);
     connect(showHelpMessageAction, &QAction::triggered, this,
             &BitcoinGUI::showHelpMessageClicked);
     connect(openRPCConsoleAction, &QAction::triggered, this,
             &BitcoinGUI::showDebugWindow);
     // prevents an open debug window from becoming stuck/unusable on client
     // shutdown
     connect(quitAction, &QAction::triggered, rpcConsole, &QWidget::hide);
 
 #ifdef ENABLE_WALLET
     if (walletFrame) {
         connect(encryptWalletAction, &QAction::triggered, walletFrame,
                 &WalletFrame::encryptWallet);
         connect(backupWalletAction, &QAction::triggered, walletFrame,
                 &WalletFrame::backupWallet);
         connect(changePassphraseAction, &QAction::triggered, walletFrame,
                 &WalletFrame::changePassphrase);
         connect(signMessageAction, &QAction::triggered,
                 [this] { showNormalIfMinimized(); });
         connect(signMessageAction, &QAction::triggered,
                 [this] { gotoSignMessageTab(); });
         connect(verifyMessageAction, &QAction::triggered,
                 [this] { showNormalIfMinimized(); });
         connect(verifyMessageAction, &QAction::triggered,
                 [this] { gotoVerifyMessageTab(); });
         connect(m_load_psbt_action, &QAction::triggered,
                 [this] { gotoLoadPSBT(); });
         connect(usedSendingAddressesAction, &QAction::triggered, walletFrame,
                 &WalletFrame::usedSendingAddresses);
         connect(usedReceivingAddressesAction, &QAction::triggered, walletFrame,
                 &WalletFrame::usedReceivingAddresses);
         connect(openAction, &QAction::triggered, this,
                 &BitcoinGUI::openClicked);
         connect(m_open_wallet_menu, &QMenu::aboutToShow, [this] {
             m_open_wallet_menu->clear();
             for (const std::pair<const std::string, bool> &i :
                  m_wallet_controller->listWalletDir()) {
                 const std::string &path = i.first;
                 QString name = path.empty()
                                    ? QString("[" + tr("default wallet") + "]")
                                    : QString::fromStdString(path);
                 // Menu items remove single &. Single & are shown when && is in
                 // the string, but only the first occurrence. So replace only
                 // the first & with &&
                 name.replace(name.indexOf(QChar('&')), 1, QString("&&"));
                 QAction *action = m_open_wallet_menu->addAction(name);
 
                 if (i.second) {
                     // This wallet is already loaded
                     action->setEnabled(false);
                     continue;
                 }
 
                 connect(action, &QAction::triggered, [this, path] {
                     auto activity =
                         new OpenWalletActivity(m_wallet_controller, this);
                     connect(activity, &OpenWalletActivity::opened, this,
                             &BitcoinGUI::setCurrentWallet);
                     connect(activity, &OpenWalletActivity::finished, activity,
                             &QObject::deleteLater);
                     activity->open(path);
                 });
             }
             if (m_open_wallet_menu->isEmpty()) {
                 QAction *action =
                     m_open_wallet_menu->addAction(tr("No wallets available"));
                 action->setEnabled(false);
             }
         });
         connect(m_close_wallet_action, &QAction::triggered, [this] {
             m_wallet_controller->closeWallet(walletFrame->currentWalletModel(),
                                              this);
         });
         connect(m_create_wallet_action, &QAction::triggered, [this] {
             auto activity = new CreateWalletActivity(m_wallet_controller, this);
             connect(activity, &CreateWalletActivity::created, this,
                     &BitcoinGUI::setCurrentWallet);
             connect(activity, &CreateWalletActivity::finished, activity,
                     &QObject::deleteLater);
             activity->create();
         });
         connect(m_close_all_wallets_action, &QAction::triggered,
                 [this] { m_wallet_controller->closeAllWallets(this); });
         connect(m_mask_values_action, &QAction::toggled, this,
                 &BitcoinGUI::setPrivacy);
     }
 #endif // ENABLE_WALLET
 
     connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_C), this),
             &QShortcut::activated, this,
             &BitcoinGUI::showDebugWindowActivateConsole);
     connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_D), this),
             &QShortcut::activated, this, &BitcoinGUI::showDebugWindow);
 }
 
 void BitcoinGUI::createMenuBar() {
 #ifdef Q_OS_MAC
     // Create a decoupled menu bar on Mac which stays even if the window is
     // closed
     appMenuBar = new QMenuBar();
 #else
     // Get the main window's menu bar on other platforms
     appMenuBar = menuBar();
 #endif
 
     // Configure the menus
     QMenu *file = appMenuBar->addMenu(tr("&File"));
     if (walletFrame) {
         file->addAction(m_create_wallet_action);
         file->addAction(m_open_wallet_action);
         file->addAction(m_close_wallet_action);
         file->addAction(m_close_all_wallets_action);
         file->addSeparator();
         file->addAction(openAction);
         file->addAction(backupWalletAction);
         file->addAction(signMessageAction);
         file->addAction(verifyMessageAction);
         file->addAction(m_load_psbt_action);
         file->addSeparator();
     }
     file->addAction(quitAction);
 
     QMenu *settings = appMenuBar->addMenu(tr("&Settings"));
     if (walletFrame) {
         settings->addAction(encryptWalletAction);
         settings->addAction(changePassphraseAction);
         settings->addSeparator();
         settings->addAction(m_mask_values_action);
         settings->addSeparator();
     }
     settings->addAction(optionsAction);
 
     QMenu *window_menu = appMenuBar->addMenu(tr("&Window"));
 
     QAction *minimize_action = window_menu->addAction(tr("Minimize"));
     minimize_action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_M));
     connect(minimize_action, &QAction::triggered,
             [] { QApplication::activeWindow()->showMinimized(); });
     connect(qApp, &QApplication::focusWindowChanged,
             [minimize_action](QWindow *window) {
                 minimize_action->setEnabled(
                     window != nullptr &&
                     (window->flags() & Qt::Dialog) != Qt::Dialog &&
                     window->windowState() != Qt::WindowMinimized);
             });
 
 #ifdef Q_OS_MAC
     QAction *zoom_action = window_menu->addAction(tr("Zoom"));
     connect(zoom_action, &QAction::triggered, [] {
         QWindow *window = qApp->focusWindow();
         if (window->windowState() != Qt::WindowMaximized) {
             window->showMaximized();
         } else {
             window->showNormal();
         }
     });
 
     connect(qApp, &QApplication::focusWindowChanged,
             [zoom_action](QWindow *window) {
                 zoom_action->setEnabled(window != nullptr);
             });
 #endif
 
     if (walletFrame) {
 #ifdef Q_OS_MAC
         window_menu->addSeparator();
         QAction *main_window_action = window_menu->addAction(tr("Main Window"));
         connect(main_window_action, &QAction::triggered,
                 [this] { GUIUtil::bringToFront(this); });
 #endif
         window_menu->addSeparator();
         window_menu->addAction(usedSendingAddressesAction);
         window_menu->addAction(usedReceivingAddressesAction);
     }
 
     window_menu->addSeparator();
     for (RPCConsole::TabTypes tab_type : rpcConsole->tabs()) {
         QAction *tab_action =
             window_menu->addAction(rpcConsole->tabTitle(tab_type));
         tab_action->setShortcut(rpcConsole->tabShortcut(tab_type));
         connect(tab_action, &QAction::triggered, [this, tab_type] {
             rpcConsole->setTabFocus(tab_type);
             showDebugWindow();
         });
     }
 
     QMenu *help = appMenuBar->addMenu(tr("&Help"));
     help->addAction(showHelpMessageAction);
     help->addSeparator();
     help->addAction(aboutAction);
     help->addAction(aboutQtAction);
 }
 
 void BitcoinGUI::createToolBars() {
     if (walletFrame) {
         QToolBar *toolbar = addToolBar(tr("Tabs toolbar"));
         appToolBar = toolbar;
         toolbar->setContextMenuPolicy(Qt::PreventContextMenu);
         toolbar->setMovable(false);
         toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
         toolbar->addAction(overviewAction);
         toolbar->addAction(sendCoinsAction);
         toolbar->addAction(receiveCoinsAction);
         toolbar->addAction(historyAction);
         overviewAction->setChecked(true);
 
 #ifdef ENABLE_WALLET
         QWidget *spacer = new QWidget();
         spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
         toolbar->addWidget(spacer);
 
         m_wallet_selector = new QComboBox();
         m_wallet_selector->setSizeAdjustPolicy(QComboBox::AdjustToContents);
         connect(m_wallet_selector,
                 static_cast<void (QComboBox::*)(int)>(
                     &QComboBox::currentIndexChanged),
                 this, &BitcoinGUI::setCurrentWalletBySelectorIndex);
 
         m_wallet_selector_label = new QLabel();
         m_wallet_selector_label->setText(tr("Wallet:") + " ");
         m_wallet_selector_label->setBuddy(m_wallet_selector);
 
         m_wallet_selector_label_action =
             appToolBar->addWidget(m_wallet_selector_label);
         m_wallet_selector_action = appToolBar->addWidget(m_wallet_selector);
 
         m_wallet_selector_label_action->setVisible(false);
         m_wallet_selector_action->setVisible(false);
 #endif
     }
 }
 
 void BitcoinGUI::setClientModel(ClientModel *_clientModel,
                                 interfaces::BlockAndHeaderTipInfo *tip_info) {
     this->clientModel = _clientModel;
     if (_clientModel) {
         // Create system tray menu (or setup the dock menu) that late to prevent
         // users from calling actions, while the client has not yet fully loaded
         createTrayIconMenu();
 
         // Keep up to date with client
         updateNetworkState();
         connect(_clientModel, &ClientModel::numConnectionsChanged, this,
                 &BitcoinGUI::setNumConnections);
         connect(_clientModel, &ClientModel::networkActiveChanged, this,
                 &BitcoinGUI::setNetworkActive);
 
         modalOverlay->setKnownBestHeight(
             tip_info->header_height,
             QDateTime::fromTime_t(tip_info->header_time));
         setNumBlocks(tip_info->block_height,
                      QDateTime::fromTime_t(tip_info->block_time),
                      tip_info->verification_progress, false,
                      SynchronizationState::INIT_DOWNLOAD);
         connect(_clientModel, &ClientModel::numBlocksChanged, this,
                 &BitcoinGUI::setNumBlocks);
 
         // Receive and report messages from client model
         connect(_clientModel, &ClientModel::message,
                 [this](const QString &title, const QString &message,
                        unsigned int style) {
                     this->message(title, message, style);
                 });
 
         // Show progress dialog
         connect(_clientModel, &ClientModel::showProgress, this,
                 &BitcoinGUI::showProgress);
 
         rpcConsole->setClientModel(_clientModel, tip_info->block_height,
                                    tip_info->block_time,
                                    tip_info->verification_progress);
 
         updateProxyIcon();
 
 #ifdef ENABLE_WALLET
         if (walletFrame) {
             walletFrame->setClientModel(_clientModel);
         }
 #endif // ENABLE_WALLET
         unitDisplayControl->setOptionsModel(_clientModel->getOptionsModel());
 
         OptionsModel *optionsModel = _clientModel->getOptionsModel();
         if (optionsModel && trayIcon) {
             // be aware of the tray icon disable state change reported by the
             // OptionsModel object.
             connect(optionsModel, &OptionsModel::hideTrayIconChanged, this,
                     &BitcoinGUI::setTrayIconVisible);
 
             // initialize the disable state of the tray icon with the current
             // value in the model.
             setTrayIconVisible(optionsModel->getHideTrayIcon());
         }
     } else {
         // Disable possibility to show main window via action
         toggleHideAction->setEnabled(false);
         if (trayIconMenu) {
             // Disable context menu on tray icon
             trayIconMenu->clear();
         }
         // Propagate cleared model to child objects
         rpcConsole->setClientModel(nullptr);
 #ifdef ENABLE_WALLET
         if (walletFrame) {
             walletFrame->setClientModel(nullptr);
         }
 #endif // ENABLE_WALLET
         unitDisplayControl->setOptionsModel(nullptr);
     }
 }
 
 #ifdef ENABLE_WALLET
 void BitcoinGUI::setWalletController(WalletController *wallet_controller) {
     assert(!m_wallet_controller);
     assert(wallet_controller);
 
     m_wallet_controller = wallet_controller;
 
     m_create_wallet_action->setEnabled(true);
     m_open_wallet_action->setEnabled(true);
     m_open_wallet_action->setMenu(m_open_wallet_menu);
 
     connect(wallet_controller, &WalletController::walletAdded, this,
             &BitcoinGUI::addWallet);
     connect(wallet_controller, &WalletController::walletRemoved, this,
             &BitcoinGUI::removeWallet);
 
     for (WalletModel *wallet_model : m_wallet_controller->getOpenWallets()) {
         addWallet(wallet_model);
     }
 }
 
 WalletController *BitcoinGUI::getWalletController() {
     return m_wallet_controller;
 }
 
 void BitcoinGUI::addWallet(WalletModel *walletModel) {
     if (!walletFrame) {
         return;
     }
     if (!walletFrame->addWallet(walletModel)) {
         return;
     }
     rpcConsole->addWallet(walletModel);
     if (m_wallet_selector->count() == 0) {
         setWalletActionsEnabled(true);
     } else if (m_wallet_selector->count() == 1) {
         m_wallet_selector_label_action->setVisible(true);
         m_wallet_selector_action->setVisible(true);
     }
     const QString display_name = walletModel->getDisplayName();
     m_wallet_selector->addItem(display_name, QVariant::fromValue(walletModel));
 }
 
 void BitcoinGUI::removeWallet(WalletModel *walletModel) {
     if (!walletFrame) {
         return;
     }
 
     labelWalletHDStatusIcon->hide();
     labelWalletEncryptionIcon->hide();
 
     int index = m_wallet_selector->findData(QVariant::fromValue(walletModel));
     m_wallet_selector->removeItem(index);
     if (m_wallet_selector->count() == 0) {
         setWalletActionsEnabled(false);
         overviewAction->setChecked(true);
     } else if (m_wallet_selector->count() == 1) {
         m_wallet_selector_label_action->setVisible(false);
         m_wallet_selector_action->setVisible(false);
     }
     rpcConsole->removeWallet(walletModel);
     walletFrame->removeWallet(walletModel);
     updateWindowTitle();
 }
 
 void BitcoinGUI::setCurrentWallet(WalletModel *wallet_model) {
     if (!walletFrame) {
         return;
     }
     walletFrame->setCurrentWallet(wallet_model);
     for (int index = 0; index < m_wallet_selector->count(); ++index) {
         if (m_wallet_selector->itemData(index).value<WalletModel *>() ==
             wallet_model) {
             m_wallet_selector->setCurrentIndex(index);
             break;
         }
     }
     updateWindowTitle();
 }
 
 void BitcoinGUI::setCurrentWalletBySelectorIndex(int index) {
     WalletModel *wallet_model =
         m_wallet_selector->itemData(index).value<WalletModel *>();
     if (wallet_model) {
         setCurrentWallet(wallet_model);
     }
 }
 
 void BitcoinGUI::removeAllWallets() {
     if (!walletFrame) {
         return;
     }
     setWalletActionsEnabled(false);
     walletFrame->removeAllWallets();
 }
 #endif // ENABLE_WALLET
 
 void BitcoinGUI::setWalletActionsEnabled(bool enabled) {
     overviewAction->setEnabled(enabled);
     sendCoinsAction->setEnabled(enabled);
     sendCoinsMenuAction->setEnabled(enabled);
     receiveCoinsAction->setEnabled(enabled);
     receiveCoinsMenuAction->setEnabled(enabled);
     historyAction->setEnabled(enabled);
     encryptWalletAction->setEnabled(enabled);
     backupWalletAction->setEnabled(enabled);
     changePassphraseAction->setEnabled(enabled);
     signMessageAction->setEnabled(enabled);
     verifyMessageAction->setEnabled(enabled);
     usedSendingAddressesAction->setEnabled(enabled);
     usedReceivingAddressesAction->setEnabled(enabled);
     openAction->setEnabled(enabled);
     m_close_wallet_action->setEnabled(enabled);
     m_close_all_wallets_action->setEnabled(enabled);
 }
 
 void BitcoinGUI::createTrayIcon() {
     assert(QSystemTrayIcon::isSystemTrayAvailable());
 
 #ifndef Q_OS_MAC
     if (QSystemTrayIcon::isSystemTrayAvailable()) {
         trayIcon =
             new QSystemTrayIcon(m_network_style->getTrayAndWindowIcon(), this);
         QString toolTip = tr("%1 client").arg(PACKAGE_NAME) + " " +
                           m_network_style->getTitleAddText();
         trayIcon->setToolTip(toolTip);
     }
 #endif
 }
 
 void BitcoinGUI::createTrayIconMenu() {
 #ifndef Q_OS_MAC
     // Return if trayIcon is unset (only on non-macOSes)
     if (!trayIcon) {
         return;
     }
 
     trayIcon->setContextMenu(trayIconMenu.get());
     connect(trayIcon, &QSystemTrayIcon::activated, this,
             &BitcoinGUI::trayIconActivated);
 #else
     // Note: On macOS, the Dock icon is used to provide the tray's
     // functionality.
     MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance();
     connect(dockIconHandler, &MacDockIconHandler::dockIconClicked, this,
             &BitcoinGUI::macosDockIconActivated);
     trayIconMenu->setAsDockMenu();
 #endif
 
     // Configuration of the tray icon (or Dock icon) menu
 #ifndef Q_OS_MAC
     // Note: On macOS, the Dock icon's menu already has Show / Hide action.
     trayIconMenu->addAction(toggleHideAction);
     trayIconMenu->addSeparator();
 #endif
     if (enableWallet) {
         trayIconMenu->addAction(sendCoinsMenuAction);
         trayIconMenu->addAction(receiveCoinsMenuAction);
         trayIconMenu->addSeparator();
         trayIconMenu->addAction(signMessageAction);
         trayIconMenu->addAction(verifyMessageAction);
         trayIconMenu->addSeparator();
     }
     trayIconMenu->addAction(optionsAction);
     trayIconMenu->addAction(openRPCConsoleAction);
 #ifndef Q_OS_MAC
     // This is built-in on macOS
     trayIconMenu->addSeparator();
     trayIconMenu->addAction(quitAction);
 #endif
 }
 
 #ifndef Q_OS_MAC
 void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason) {
     if (reason == QSystemTrayIcon::Trigger) {
         // Click on system tray icon triggers show/hide of the main window
         toggleHidden();
     }
 }
 #else
 void BitcoinGUI::macosDockIconActivated() {
     show();
     activateWindow();
 }
 #endif
 
 void BitcoinGUI::optionsClicked() {
     openOptionsDialogWithTab(OptionsDialog::TAB_MAIN);
 }
 
 void BitcoinGUI::aboutClicked() {
     if (!clientModel) {
         return;
     }
 
     HelpMessageDialog dlg(this, true);
     dlg.exec();
 }
 
 void BitcoinGUI::showDebugWindow() {
     GUIUtil::bringToFront(rpcConsole);
     Q_EMIT consoleShown(rpcConsole);
 }
 
 void BitcoinGUI::showDebugWindowActivateConsole() {
     rpcConsole->setTabFocus(RPCConsole::TabTypes::CONSOLE);
     showDebugWindow();
 }
 
 void BitcoinGUI::showHelpMessageClicked() {
     helpMessageDialog->show();
 }
 
 #ifdef ENABLE_WALLET
 void BitcoinGUI::openClicked() {
     OpenURIDialog dlg(config->GetChainParams(), this);
     if (dlg.exec()) {
         Q_EMIT receivedURI(dlg.getURI());
     }
 }
 
 void BitcoinGUI::gotoOverviewPage() {
     overviewAction->setChecked(true);
     if (walletFrame) {
         walletFrame->gotoOverviewPage();
     }
 }
 
 void BitcoinGUI::gotoHistoryPage() {
     historyAction->setChecked(true);
     if (walletFrame) {
         walletFrame->gotoHistoryPage();
     }
 }
 
 void BitcoinGUI::gotoReceiveCoinsPage() {
     receiveCoinsAction->setChecked(true);
     if (walletFrame) {
         walletFrame->gotoReceiveCoinsPage();
     }
 }
 
 void BitcoinGUI::gotoSendCoinsPage(QString addr) {
     sendCoinsAction->setChecked(true);
     if (walletFrame) {
         walletFrame->gotoSendCoinsPage(addr);
     }
 }
 
 void BitcoinGUI::gotoSignMessageTab(QString addr) {
     if (walletFrame) {
         walletFrame->gotoSignMessageTab(addr);
     }
 }
 
 void BitcoinGUI::gotoVerifyMessageTab(QString addr) {
     if (walletFrame) {
         walletFrame->gotoVerifyMessageTab(addr);
     }
 }
 void BitcoinGUI::gotoLoadPSBT() {
     if (walletFrame) {
         walletFrame->gotoLoadPSBT();
     }
 }
 #endif // ENABLE_WALLET
 
 void BitcoinGUI::updateNetworkState() {
     int count = clientModel->getNumConnections();
     QString icon;
     switch (count) {
         case 0:
             icon = ":/icons/connect_0";
             break;
         case 1:
         case 2:
         case 3:
             icon = ":/icons/connect_1";
             break;
         case 4:
         case 5:
         case 6:
             icon = ":/icons/connect_2";
             break;
         case 7:
         case 8:
         case 9:
             icon = ":/icons/connect_3";
             break;
         default:
             icon = ":/icons/connect_4";
             break;
     }
 
     QString tooltip;
 
     if (m_node.getNetworkActive()) {
         tooltip = tr("%n active connection(s) to Bitcoin network", "", count) +
                   QString(".<br>") + tr("Click to disable network activity.");
     } else {
         tooltip = tr("Network activity disabled.") + QString("<br>") +
                   tr("Click to enable network activity again.");
         icon = ":/icons/network_disabled";
     }
 
     // Don't word-wrap this (fixed-width) tooltip
     tooltip = QString("<nobr>") + tooltip + QString("</nobr>");
     connectionsControl->setToolTip(tooltip);
 
     connectionsControl->setPixmap(platformStyle->SingleColorIcon(icon).pixmap(
         STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
 }
 
 void BitcoinGUI::setNumConnections(int count) {
     updateNetworkState();
 }
 
 void BitcoinGUI::setNetworkActive(bool networkActive) {
     updateNetworkState();
 }
 
 void BitcoinGUI::updateHeadersSyncProgressLabel() {
     int64_t headersTipTime = clientModel->getHeaderTipTime();
     int headersTipHeight = clientModel->getHeaderTipHeight();
     int estHeadersLeft =
         (GetTime() - headersTipTime) /
         config->GetChainParams().GetConsensus().nPowTargetSpacing;
     if (estHeadersLeft > HEADER_HEIGHT_DELTA_SYNC) {
         progressBarLabel->setText(
             tr("Syncing Headers (%1%)...")
                 .arg(QString::number(100.0 /
                                          (headersTipHeight + estHeadersLeft) *
                                          headersTipHeight,
                                      'f', 1)));
     }
 }
 
 void BitcoinGUI::openOptionsDialogWithTab(OptionsDialog::Tab tab) {
     if (!clientModel || !clientModel->getOptionsModel()) {
         return;
     }
 
     OptionsDialog dlg(this, enableWallet);
     dlg.setCurrentTab(tab);
     dlg.setModel(clientModel->getOptionsModel());
     dlg.exec();
 }
 
 void BitcoinGUI::setNumBlocks(int count, const QDateTime &blockDate,
                               double nVerificationProgress, bool header,
                               SynchronizationState sync_state) {
 // Disabling macOS App Nap on initial sync, disk and reindex operations.
 #ifdef Q_OS_MAC
     if (sync_state == SynchronizationState::POST_INIT) {
         m_app_nap_inhibitor->enableAppNap();
     } else {
         m_app_nap_inhibitor->disableAppNap();
     }
 #endif
 
     if (modalOverlay) {
         if (header) {
             modalOverlay->setKnownBestHeight(count, blockDate);
         } else {
             modalOverlay->tipUpdate(count, blockDate, nVerificationProgress);
         }
     }
     if (!clientModel) {
         return;
     }
 
     // Prevent orphan statusbar messages (e.g. hover Quit in main menu, wait
     // until chain-sync starts -> garbled text)
     statusBar()->clearMessage();
 
     // Acquire current block source
     enum BlockSource blockSource = clientModel->getBlockSource();
     switch (blockSource) {
         case BlockSource::NETWORK:
             if (header) {
                 updateHeadersSyncProgressLabel();
                 return;
             }
             progressBarLabel->setText(tr("Synchronizing with network..."));
             updateHeadersSyncProgressLabel();
             break;
         case BlockSource::DISK:
             if (header) {
                 progressBarLabel->setText(tr("Indexing blocks on disk..."));
             } else {
                 progressBarLabel->setText(tr("Processing blocks on disk..."));
             }
             break;
         case BlockSource::REINDEX:
             progressBarLabel->setText(tr("Reindexing blocks on disk..."));
             break;
         case BlockSource::NONE:
             if (header) {
                 return;
             }
             progressBarLabel->setText(tr("Connecting to peers..."));
             break;
     }
 
     QString tooltip;
 
     QDateTime currentDate = QDateTime::currentDateTime();
     qint64 secs = blockDate.secsTo(currentDate);
 
     tooltip = tr("Processed %n block(s) of transaction history.", "", count);
 
     // Set icon state: spinning if catching up, tick otherwise
     if (secs < MAX_BLOCK_TIME_GAP) {
         tooltip = tr("Up to date") + QString(".<br>") + tooltip;
         labelBlocksIcon->setPixmap(
             platformStyle->SingleColorIcon(":/icons/synced")
                 .pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
 
 #ifdef ENABLE_WALLET
         if (walletFrame) {
             walletFrame->showOutOfSyncWarning(false);
             modalOverlay->showHide(true, true);
         }
 #endif // ENABLE_WALLET
 
         progressBarLabel->setVisible(false);
         progressBar->setVisible(false);
     } else {
         QString timeBehindText = GUIUtil::formatNiceTimeOffset(secs);
 
         progressBarLabel->setVisible(true);
         progressBar->setFormat(tr("%1 behind").arg(timeBehindText));
         progressBar->setMaximum(1000000000);
         progressBar->setValue(nVerificationProgress * 1000000000.0 + 0.5);
         progressBar->setVisible(true);
 
         tooltip = tr("Catching up...") + QString("<br>") + tooltip;
         if (count != prevBlocks) {
             labelBlocksIcon->setPixmap(
                 platformStyle
                     ->SingleColorIcon(QString(":/animation/spinner-%1")
                                           .arg(spinnerFrame, 3, 10, QChar('0')))
                     .pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
             spinnerFrame = (spinnerFrame + 1) % SPINNER_FRAMES;
         }
         prevBlocks = count;
 
 #ifdef ENABLE_WALLET
         if (walletFrame) {
             walletFrame->showOutOfSyncWarning(true);
             modalOverlay->showHide();
         }
 #endif // ENABLE_WALLET
 
         tooltip += QString("<br>");
         tooltip +=
             tr("Last received block was generated %1 ago.").arg(timeBehindText);
         tooltip += QString("<br>");
         tooltip += tr("Transactions after this will not yet be visible.");
     }
 
     // Don't word-wrap this (fixed-width) tooltip
     tooltip = QString("<nobr>") + tooltip + QString("</nobr>");
 
     labelBlocksIcon->setToolTip(tooltip);
     progressBarLabel->setToolTip(tooltip);
     progressBar->setToolTip(tooltip);
 }
 
 void BitcoinGUI::message(const QString &title, QString message,
                          unsigned int style, bool *ret,
                          const QString &detailed_message) {
     // Default title. On macOS, the window title is ignored (as required by the
     // macOS Guidelines).
     QString strTitle{PACKAGE_NAME};
     // Default to information icon
     int nMBoxIcon = QMessageBox::Information;
     int nNotifyIcon = Notificator::Information;
 
     QString msgType;
     if (!title.isEmpty()) {
         msgType = title;
     } else {
         switch (style) {
             case CClientUIInterface::MSG_ERROR:
                 msgType = tr("Error");
                 message = tr("Error: %1").arg(message);
                 break;
             case CClientUIInterface::MSG_WARNING:
                 msgType = tr("Warning");
                 message = tr("Warning: %1").arg(message);
                 break;
             case CClientUIInterface::MSG_INFORMATION:
                 msgType = tr("Information");
                 // No need to prepend the prefix here.
                 break;
             default:
                 break;
         }
     }
 
     if (!msgType.isEmpty()) {
         strTitle += " - " + msgType;
     }
 
     if (style & CClientUIInterface::ICON_ERROR) {
         nMBoxIcon = QMessageBox::Critical;
         nNotifyIcon = Notificator::Critical;
     } else if (style & CClientUIInterface::ICON_WARNING) {
         nMBoxIcon = QMessageBox::Warning;
         nNotifyIcon = Notificator::Warning;
     }
 
     if (style & CClientUIInterface::MODAL) {
         // Check for buttons, use OK as default, if none was supplied
         QMessageBox::StandardButton buttons;
         if (!(buttons = (QMessageBox::StandardButton)(
                   style & CClientUIInterface::BTN_MASK))) {
             buttons = QMessageBox::Ok;
         }
 
         showNormalIfMinimized();
         QMessageBox mBox(static_cast<QMessageBox::Icon>(nMBoxIcon), strTitle,
                          message, buttons, this);
         mBox.setTextFormat(Qt::PlainText);
         mBox.setDetailedText(detailed_message);
         int r = mBox.exec();
         if (ret != nullptr) {
             *ret = r == QMessageBox::Ok;
         }
     } else {
         notificator->notify(static_cast<Notificator::Class>(nNotifyIcon),
                             strTitle, message);
     }
 }
 
 void BitcoinGUI::changeEvent(QEvent *e) {
     QMainWindow::changeEvent(e);
 #ifndef Q_OS_MAC // Ignored on Mac
     if (e->type() == QEvent::WindowStateChange) {
         if (clientModel && clientModel->getOptionsModel() &&
             clientModel->getOptionsModel()->getMinimizeToTray()) {
             QWindowStateChangeEvent *wsevt =
                 static_cast<QWindowStateChangeEvent *>(e);
             if (!(wsevt->oldState() & Qt::WindowMinimized) && isMinimized()) {
                 QTimer::singleShot(0, this, &BitcoinGUI::hide);
                 e->ignore();
             } else if ((wsevt->oldState() & Qt::WindowMinimized) &&
                        !isMinimized()) {
                 QTimer::singleShot(0, this, &BitcoinGUI::show);
                 e->ignore();
             }
         }
     }
 #endif
 }
 
 void BitcoinGUI::closeEvent(QCloseEvent *event) {
 #ifndef Q_OS_MAC // Ignored on Mac
     if (clientModel && clientModel->getOptionsModel()) {
         if (!clientModel->getOptionsModel()->getMinimizeOnClose()) {
             // close rpcConsole in case it was open to make some space for the
             // shutdown window
             rpcConsole->close();
 
             QApplication::quit();
         } else {
             QMainWindow::showMinimized();
             event->ignore();
         }
     }
 #else
     QMainWindow::closeEvent(event);
 #endif
 }
 
 void BitcoinGUI::showEvent(QShowEvent *event) {
     // enable the debug window when the main window shows up
     openRPCConsoleAction->setEnabled(true);
     aboutAction->setEnabled(true);
     optionsAction->setEnabled(true);
 }
 
 #ifdef ENABLE_WALLET
 void BitcoinGUI::incomingTransaction(const QString &date, int unit,
                                      const Amount amount, const QString &type,
                                      const QString &address,
                                      const QString &label,
                                      const QString &walletName) {
     // On new transaction, make an info balloon
     QString msg = tr("Date: %1\n").arg(date) +
                   tr("Amount: %1\n")
                       .arg(BitcoinUnits::formatWithUnit(unit, amount, true));
     if (m_node.walletClient().getWallets().size() > 1 &&
         !walletName.isEmpty()) {
         msg += tr("Wallet: %1\n").arg(walletName);
     }
     msg += tr("Type: %1\n").arg(type);
     if (!label.isEmpty()) {
         msg += tr("Label: %1\n").arg(label);
     } else if (!address.isEmpty()) {
         msg += tr("Address: %1\n").arg(address);
     }
     message(amount < Amount::zero() ? tr("Sent transaction")
                                     : tr("Incoming transaction"),
             msg, CClientUIInterface::MSG_INFORMATION);
 }
 #endif // ENABLE_WALLET
 
 void BitcoinGUI::dragEnterEvent(QDragEnterEvent *event) {
     // Accept only URIs
     if (event->mimeData()->hasUrls()) {
         event->acceptProposedAction();
     }
 }
 
 void BitcoinGUI::dropEvent(QDropEvent *event) {
     if (event->mimeData()->hasUrls()) {
         for (const QUrl &uri : event->mimeData()->urls()) {
             Q_EMIT receivedURI(uri.toString());
         }
     }
     event->acceptProposedAction();
 }
 
 bool BitcoinGUI::eventFilter(QObject *object, QEvent *event) {
     // Catch status tip events
     if (event->type() == QEvent::StatusTip) {
         // Prevent adding text from setStatusTip(), if we currently use the
         // status bar for displaying other stuff
         if (progressBarLabel->isVisible() || progressBar->isVisible()) {
             return true;
         }
     }
     return QMainWindow::eventFilter(object, event);
 }
 
 #ifdef ENABLE_WALLET
 bool BitcoinGUI::handlePaymentRequest(const SendCoinsRecipient &recipient) {
     // URI has to be valid
     if (walletFrame && walletFrame->handlePaymentRequest(recipient)) {
         showNormalIfMinimized();
         gotoSendCoinsPage();
         return true;
     }
     return false;
 }
 
 void BitcoinGUI::setHDStatus(bool privkeyDisabled, int hdEnabled) {
     labelWalletHDStatusIcon->setPixmap(
         platformStyle
-            ->SingleColorIcon(privkeyDisabled
-                                  ? ":/icons/eye"
-                                  : hdEnabled ? ":/icons/hd_enabled"
+            ->SingleColorIcon(privkeyDisabled ? ":/icons/eye"
+                              : hdEnabled     ? ":/icons/hd_enabled"
                                               : ":/icons/hd_disabled")
             .pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
     labelWalletHDStatusIcon->setToolTip(
-        privkeyDisabled
-            ? tr("Private key <b>disabled</b>")
-            : hdEnabled ? tr("HD key generation is <b>enabled</b>")
+        privkeyDisabled ? tr("Private key <b>disabled</b>")
+        : hdEnabled     ? tr("HD key generation is <b>enabled</b>")
                         : tr("HD key generation is <b>disabled</b>"));
     labelWalletHDStatusIcon->show();
     // eventually disable the QLabel to set its opacity to 50%
     labelWalletHDStatusIcon->setEnabled(hdEnabled);
 }
 
 void BitcoinGUI::setEncryptionStatus(int status) {
     switch (status) {
         case WalletModel::Unencrypted:
             labelWalletEncryptionIcon->hide();
             encryptWalletAction->setChecked(false);
             changePassphraseAction->setEnabled(false);
             encryptWalletAction->setEnabled(true);
             break;
         case WalletModel::Unlocked:
             labelWalletEncryptionIcon->show();
             labelWalletEncryptionIcon->setPixmap(
                 platformStyle->SingleColorIcon(":/icons/lock_open")
                     .pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
             labelWalletEncryptionIcon->setToolTip(
                 tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
             encryptWalletAction->setChecked(true);
             changePassphraseAction->setEnabled(true);
             encryptWalletAction->setEnabled(false);
             break;
         case WalletModel::Locked:
             labelWalletEncryptionIcon->show();
             labelWalletEncryptionIcon->setPixmap(
                 platformStyle->SingleColorIcon(":/icons/lock_closed")
                     .pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
             labelWalletEncryptionIcon->setToolTip(
                 tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
             encryptWalletAction->setChecked(true);
             changePassphraseAction->setEnabled(true);
             encryptWalletAction->setEnabled(false);
             break;
     }
 }
 
 void BitcoinGUI::updateWalletStatus() {
     if (!walletFrame) {
         return;
     }
     WalletView *const walletView = walletFrame->currentWalletView();
     if (!walletView) {
         return;
     }
     WalletModel *const walletModel = walletView->getWalletModel();
     setEncryptionStatus(walletModel->getEncryptionStatus());
     setHDStatus(walletModel->wallet().privateKeysDisabled(),
                 walletModel->wallet().hdEnabled());
 }
 #endif // ENABLE_WALLET
 
 void BitcoinGUI::updateProxyIcon() {
     std::string ip_port;
     bool proxy_enabled = clientModel->getProxyInfo(ip_port);
 
     if (proxy_enabled) {
         if (!labelProxyIcon->hasPixmap()) {
             QString ip_port_q = QString::fromStdString(ip_port);
             labelProxyIcon->setPixmap(
                 platformStyle->SingleColorIcon(":/icons/proxy")
                     .pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
             labelProxyIcon->setToolTip(
                 tr("Proxy is <b>enabled</b>: %1").arg(ip_port_q));
         } else {
             labelProxyIcon->show();
         }
     } else {
         labelProxyIcon->hide();
     }
 }
 
 void BitcoinGUI::updateWindowTitle() {
     QString window_title = PACKAGE_NAME;
 #ifdef ENABLE_WALLET
     if (walletFrame) {
         WalletModel *const wallet_model = walletFrame->currentWalletModel();
         if (wallet_model && !wallet_model->getWalletName().isEmpty()) {
             window_title += " - " + wallet_model->getDisplayName();
         }
     }
 #endif
     if (!m_network_style->getTitleAddText().isEmpty()) {
         window_title += " - " + m_network_style->getTitleAddText();
     }
     setWindowTitle(window_title);
 }
 
 void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden) {
     if (!clientModel) {
         return;
     }
 
     if (!isHidden() && !isMinimized() && !GUIUtil::isObscured(this) &&
         fToggleHidden) {
         hide();
     } else {
         GUIUtil::bringToFront(this);
     }
 }
 
 void BitcoinGUI::toggleHidden() {
     showNormalIfMinimized(true);
 }
 
 void BitcoinGUI::detectShutdown() {
     if (m_node.shutdownRequested()) {
         if (rpcConsole) {
             rpcConsole->hide();
         }
         qApp->quit();
     }
 }
 
 void BitcoinGUI::showProgress(const QString &title, int nProgress) {
     if (nProgress == 0) {
         progressDialog = new QProgressDialog(title, QString(), 0, 100);
         GUIUtil::PolishProgressDialog(progressDialog);
         progressDialog->setWindowModality(Qt::ApplicationModal);
         progressDialog->setMinimumDuration(0);
         progressDialog->setAutoClose(false);
         progressDialog->setValue(0);
     } else if (nProgress == 100) {
         if (progressDialog) {
             progressDialog->close();
             progressDialog->deleteLater();
             progressDialog = nullptr;
         }
     } else if (progressDialog) {
         progressDialog->setValue(nProgress);
     }
 }
 
 void BitcoinGUI::setTrayIconVisible(bool fHideTrayIcon) {
     if (trayIcon) {
         trayIcon->setVisible(!fHideTrayIcon);
     }
 }
 
 void BitcoinGUI::showModalOverlay() {
     if (modalOverlay &&
         (progressBar->isVisible() || modalOverlay->isLayerVisible())) {
         modalOverlay->toggleVisibility();
     }
 }
 
 static bool ThreadSafeMessageBox(BitcoinGUI *gui, const bilingual_str &message,
                                  const std::string &caption,
                                  unsigned int style) {
     bool modal = (style & CClientUIInterface::MODAL);
     // The SECURE flag has no effect in the Qt GUI.
     // bool secure = (style & CClientUIInterface::SECURE);
     style &= ~CClientUIInterface::SECURE;
     bool ret = false;
     // This is original message, in English, for googling and referencing.
     QString detailed_message;
     if (message.original != message.translated) {
         detailed_message = BitcoinGUI::tr("Original message:") + "\n" +
                            QString::fromStdString(message.original);
     }
 
     // In case of modal message, use blocking connection to wait for user to
     // click a button
     bool invoked = QMetaObject::invokeMethod(
         gui, "message",
         modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
         Q_ARG(QString, QString::fromStdString(caption)),
         Q_ARG(QString, QString::fromStdString(message.translated)),
         Q_ARG(unsigned int, style), Q_ARG(bool *, &ret),
         Q_ARG(QString, detailed_message));
     assert(invoked);
     return ret;
 }
 
 void BitcoinGUI::subscribeToCoreSignals() {
     // Connect signals to client
     m_handler_message_box = m_node.handleMessageBox(
         std::bind(ThreadSafeMessageBox, this, std::placeholders::_1,
                   std::placeholders::_2, std::placeholders::_3));
     m_handler_question = m_node.handleQuestion(
         std::bind(ThreadSafeMessageBox, this, std::placeholders::_1,
                   std::placeholders::_3, std::placeholders::_4));
 }
 
 void BitcoinGUI::unsubscribeFromCoreSignals() {
     // Disconnect signals from client
     m_handler_message_box->disconnect();
     m_handler_question->disconnect();
 }
 
 bool BitcoinGUI::isPrivacyModeActivated() const {
     assert(m_mask_values_action);
     return m_mask_values_action->isChecked();
 }
 
 UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(
     const PlatformStyle *platformStyle)
     : optionsModel(nullptr), menu(nullptr) {
     createContextMenu();
     setToolTip(tr("Unit to show amounts in. Click to select another unit."));
     QList<BitcoinUnits::Unit> units = BitcoinUnits::availableUnits();
     int max_width = 0;
     const QFontMetrics fm(font());
     for (const BitcoinUnits::Unit unit : units) {
         max_width = qMax(max_width,
                          GUIUtil::TextWidth(fm, BitcoinUnits::longName(unit)));
     }
     setMinimumSize(max_width, 0);
     setAlignment(Qt::AlignRight | Qt::AlignVCenter);
     setStyleSheet(QString("QLabel { color : %1 }")
                       .arg(platformStyle->SingleColor().name()));
 }
 
 /** So that it responds to button clicks */
 void UnitDisplayStatusBarControl::mousePressEvent(QMouseEvent *event) {
     onDisplayUnitsClicked(event->pos());
 }
 
 /** Creates context menu, its actions, and wires up all the relevant signals for
  * mouse events. */
 void UnitDisplayStatusBarControl::createContextMenu() {
     menu = new QMenu(this);
     for (const BitcoinUnits::Unit u : BitcoinUnits::availableUnits()) {
         QAction *menuAction =
             new QAction(QString(BitcoinUnits::longName(u)), this);
         menuAction->setData(QVariant(u));
         menu->addAction(menuAction);
     }
     connect(menu, &QMenu::triggered, this,
             &UnitDisplayStatusBarControl::onMenuSelection);
 }
 
 /** Lets the control know about the Options Model (and its signals) */
 void UnitDisplayStatusBarControl::setOptionsModel(OptionsModel *_optionsModel) {
     if (_optionsModel) {
         this->optionsModel = _optionsModel;
 
         // be aware of a display unit change reported by the OptionsModel
         // object.
         connect(_optionsModel, &OptionsModel::displayUnitChanged, this,
                 &UnitDisplayStatusBarControl::updateDisplayUnit);
 
         // initialize the display units label with the current value in the
         // model.
         updateDisplayUnit(_optionsModel->getDisplayUnit());
     }
 }
 
 /** When Display Units are changed on OptionsModel it will refresh the display
  * text of the control on the status bar */
 void UnitDisplayStatusBarControl::updateDisplayUnit(int newUnits) {
     setText(BitcoinUnits::longName(newUnits));
 }
 
 /** Shows context menu with Display Unit options by the mouse coordinates */
 void UnitDisplayStatusBarControl::onDisplayUnitsClicked(const QPoint &point) {
     QPoint globalPos = mapToGlobal(point);
     menu->exec(globalPos);
 }
 
 /** Tells underlying optionsModel to update its current display unit. */
 void UnitDisplayStatusBarControl::onMenuSelection(QAction *action) {
     if (action) {
         optionsModel->setDisplayUnit(action->data());
     }
 }
diff --git a/src/rcu.h b/src/rcu.h
index cd375aa8e..5a67fcae4 100644
--- a/src/rcu.h
+++ b/src/rcu.h
@@ -1,234 +1,234 @@
 // Copyright (c) 2018-2019 The Bitcoin developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #ifndef BITCOIN_RCU_H
 #define BITCOIN_RCU_H
 
 #include <atomic>
 #include <cassert>
 #include <cstdint>
 #include <functional>
 #include <map>
 #include <ostream>
 #include <type_traits>
 #include <utility>
 
 class RCUInfos;
 class RCUReadLock;
 
 class RCUInfos {
     std::atomic<uint64_t> state;
     std::atomic<RCUInfos *> next;
 
     std::map<uint64_t, std::function<void()>> cleanups;
 
     // The largest revision possible means unlocked.
     static const uint64_t UNLOCKED = -uint64_t(1);
 
     RCUInfos();
     ~RCUInfos();
 
     void readLock() {
         assert(!isLocked());
         state.store(revision.load());
     }
 
     void readFree() {
         assert(isLocked());
         state.store(UNLOCKED);
     }
 
     bool isLocked() const { return state.load() != UNLOCKED; }
     void registerCleanup(const std::function<void()> &f) {
         cleanups.emplace(++revision, f);
     }
 
     void synchronize();
     void runCleanups();
     uint64_t hasSyncedTo(uint64_t cutoff = UNLOCKED);
 
     friend class RCULock;
     friend struct RCUTest;
 
     static std::atomic<uint64_t> revision;
     static thread_local RCUInfos infos;
 };
 
 class RCULock {
     RCUInfos *infos;
 
     explicit RCULock(RCUInfos *infosIn) : infos(infosIn) { infos->readLock(); }
     friend class RCUInfos;
 
 public:
     RCULock() : RCULock(&RCUInfos::infos) {}
     ~RCULock() { infos->readFree(); }
 
     RCULock(const RCULock &) = delete;
     RCULock &operator=(const RCULock &) = delete;
 
     static bool isLocked() { return RCUInfos::infos.isLocked(); }
     static void registerCleanup(const std::function<void()> &f) {
         RCUInfos::infos.registerCleanup(f);
     }
 
     static void synchronize() { RCUInfos::infos.synchronize(); }
 };
 
 template <typename T> class RCUPtr {
     T *ptr;
 
     // Private construction, so factories have to be used.
     explicit RCUPtr(T *ptrIn) : ptr(ptrIn) {}
 
 public:
     RCUPtr() : ptr(nullptr) {}
 
     ~RCUPtr() {
         if (ptr != nullptr) {
             ptr->release();
         }
     }
 
     /**
      * Acquire ownership of some pointer.
      */
     static RCUPtr acquire(T *&ptrIn) {
         RCUPtr ret(ptrIn);
         ptrIn = nullptr;
         return ret;
     }
 
     /**
      * Construct a new object that is owned by the pointer.
      */
-    template <typename... Args> static RCUPtr make(Args &&... args) {
+    template <typename... Args> static RCUPtr make(Args &&...args) {
         return RCUPtr(new T(std::forward<Args>(args)...));
     }
 
     /**
      * Construct a new RCUPtr without transferring owership.
      */
     static RCUPtr copy(T *ptr) {
         if (ptr != nullptr) {
             ptr->acquire();
         }
 
         return RCUPtr::acquire(ptr);
     }
 
     /**
      * Copy semantic.
      */
     RCUPtr(const RCUPtr &src) : ptr(src.ptr) {
         if (ptr != nullptr) {
             ptr->acquire();
         }
     }
 
     RCUPtr &operator=(const RCUPtr &rhs) {
         RCUPtr tmp(rhs);
         std::swap(ptr, tmp.ptr);
         return *this;
     }
 
     /**
      * Move semantic.
      */
     RCUPtr(RCUPtr &&src) : RCUPtr() { std::swap(ptr, src.ptr); }
     RCUPtr &operator=(RCUPtr &&rhs) {
         std::swap(ptr, rhs.ptr);
         return *this;
     }
 
     /**
      * Get allows to access the undelying pointer. RCUPtr keeps ownership.
      */
     T *get() { return ptr; }
     const T *get() const { return ptr; }
 
     /**
      * Release transfers ownership of the pointer from RCUPtr to the caller.
      */
     T *release() {
         T *oldPtr = ptr;
         ptr = nullptr;
         return oldPtr;
     }
 
     /**
      * Operator overloading for convenience.
      */
     T *operator->() { return ptr; }
     const T *operator->() const { return ptr; }
 
     T &operator*() { return *ptr; }
     const T &operator*() const { return *ptr; }
 
     explicit operator bool() const { return ptr != nullptr; }
 
     /**
      * Equality checks.
      */
     friend bool operator==(const RCUPtr &lhs, const T *rhs) {
         return lhs.get() == rhs;
     }
 
     friend bool operator==(const RCUPtr &lhs, const RCUPtr &rhs) {
         return lhs == rhs.get();
     }
 
     friend bool operator!=(const RCUPtr &lhs, const T *rhs) {
         return !(lhs == rhs);
     }
 
     friend bool operator!=(const RCUPtr &lhs, const RCUPtr &rhs) {
         return !(lhs == rhs);
     }
 
     /**
      * ostream support.
      */
     friend std::ostream &operator<<(std::ostream &stream, const RCUPtr &rhs) {
         return stream << rhs.ptr;
     }
 };
 
 #define IMPLEMENT_RCU_REFCOUNT(T)                                              \
 private:                                                                       \
     mutable std::atomic<T> refcount{0};                                        \
                                                                                \
     void acquire() const { refcount++; }                                       \
                                                                                \
     bool tryDecrement() const {                                                \
         T count = refcount.load();                                             \
         while (count > 0) {                                                    \
             if (refcount.compare_exchange_weak(count, count - 1)) {            \
                 return true;                                                   \
             }                                                                  \
         }                                                                      \
                                                                                \
         return false;                                                          \
     }                                                                          \
                                                                                \
     void release() const {                                                     \
         if (tryDecrement()) {                                                  \
             return;                                                            \
         }                                                                      \
                                                                                \
         RCULock::registerCleanup([this] {                                      \
             if (tryDecrement()) {                                              \
                 return;                                                        \
             }                                                                  \
                                                                                \
             delete this;                                                       \
         });                                                                    \
     }                                                                          \
                                                                                \
     static_assert(std::is_integral<T>::value, "T must be an integral type.");  \
     static_assert(std::is_unsigned<T>::value, "T must be unsigned.");          \
                                                                                \
     template <typename> friend class ::RCUPtr
 
 #endif // BITCOIN_RCU_H
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index f3e2a3990..dbb9715c9 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -1,3105 +1,3105 @@
 // Copyright (c) 2010 Satoshi Nakamoto
 // Copyright (c) 2009-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.
 
 #include <rpc/blockchain.h>
 
 #include <amount.h>
 #include <blockdb.h>
 #include <blockfilter.h>
 #include <chain.h>
 #include <chainparams.h>
 #include <checkpoints.h>
 #include <coins.h>
 #include <config.h>
 #include <consensus/validation.h>
 #include <core_io.h>
 #include <hash.h>
 #include <index/blockfilterindex.h>
 #include <network.h>
 #include <node/coinstats.h>
 #include <node/context.h>
 #include <node/utxo_snapshot.h>
 #include <policy/policy.h>
 #include <primitives/transaction.h>
 #include <rpc/server.h>
 #include <rpc/util.h>
 #include <script/descriptor.h>
 #include <streams.h>
 #include <txdb.h>
 #include <txmempool.h>
 #include <undo.h>
 #include <util/ref.h>
 #include <util/strencodings.h>
 #include <util/system.h>
 #include <util/translation.h>
 #include <validation.h>
 #include <validationinterface.h>
 #include <versionbitsinfo.h> // For VersionBitsDeploymentInfo
 #include <warnings.h>
 
 #include <condition_variable>
 #include <cstdint>
 #include <memory>
 #include <mutex>
 
 struct CUpdatedBlock {
     BlockHash hash;
     int height;
 };
 
 static Mutex cs_blockchange;
 static std::condition_variable cond_blockchange;
 static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange);
 
 NodeContext &EnsureNodeContext(const util::Ref &context) {
     if (!context.Has<NodeContext>()) {
         throw JSONRPCError(RPC_INTERNAL_ERROR, "Node context not found");
     }
     return context.Get<NodeContext>();
 }
 
 CTxMemPool &EnsureMemPool(const util::Ref &context) {
     const NodeContext &node = EnsureNodeContext(context);
     if (!node.mempool) {
         throw JSONRPCError(RPC_CLIENT_MEMPOOL_DISABLED,
                            "Mempool disabled or instance not found");
     }
     return *node.mempool;
 }
 
 ChainstateManager &EnsureChainman(const util::Ref &context) {
     const NodeContext &node = EnsureNodeContext(context);
     if (!node.chainman) {
         throw JSONRPCError(RPC_INTERNAL_ERROR, "Node chainman not found");
     }
     return *node.chainman;
 }
 
 /**
  * Calculate the difficulty for a given block index.
  */
 double GetDifficulty(const CBlockIndex *blockindex) {
     CHECK_NONFATAL(blockindex);
 
     int nShift = (blockindex->nBits >> 24) & 0xff;
     double dDiff = double(0x0000ffff) / double(blockindex->nBits & 0x00ffffff);
 
     while (nShift < 29) {
         dDiff *= 256.0;
         nShift++;
     }
     while (nShift > 29) {
         dDiff /= 256.0;
         nShift--;
     }
 
     return dDiff;
 }
 
 static int ComputeNextBlockAndDepth(const CBlockIndex *tip,
                                     const CBlockIndex *blockindex,
                                     const CBlockIndex *&next) {
     next = tip->GetAncestor(blockindex->nHeight + 1);
     if (next && next->pprev == blockindex) {
         return tip->nHeight - blockindex->nHeight + 1;
     }
     next = nullptr;
     return blockindex == tip ? 1 : -1;
 }
 
 UniValue blockheaderToJSON(const CBlockIndex *tip,
                            const CBlockIndex *blockindex) {
     // Serialize passed information without accessing chain state of the active
     // chain!
     // For performance reasons
     AssertLockNotHeld(cs_main);
 
     UniValue result(UniValue::VOBJ);
     result.pushKV("hash", blockindex->GetBlockHash().GetHex());
     const CBlockIndex *pnext;
     int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
     result.pushKV("confirmations", confirmations);
     result.pushKV("height", blockindex->nHeight);
     result.pushKV("version", blockindex->nVersion);
     result.pushKV("versionHex", strprintf("%08x", blockindex->nVersion));
     result.pushKV("merkleroot", blockindex->hashMerkleRoot.GetHex());
     result.pushKV("time", int64_t(blockindex->nTime));
     result.pushKV("mediantime", int64_t(blockindex->GetMedianTimePast()));
     result.pushKV("nonce", uint64_t(blockindex->nNonce));
     result.pushKV("bits", strprintf("%08x", blockindex->nBits));
     result.pushKV("difficulty", GetDifficulty(blockindex));
     result.pushKV("chainwork", blockindex->nChainWork.GetHex());
     result.pushKV("nTx", uint64_t(blockindex->nTx));
 
     if (blockindex->pprev) {
         result.pushKV("previousblockhash",
                       blockindex->pprev->GetBlockHash().GetHex());
     }
     if (pnext) {
         result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
     }
     return result;
 }
 
 UniValue blockToJSON(const CBlock &block, const CBlockIndex *tip,
                      const CBlockIndex *blockindex, bool txDetails) {
     // Serialize passed information without accessing chain state of the active
     // chain!
     // For performance reasons
     AssertLockNotHeld(cs_main);
 
     UniValue result(UniValue::VOBJ);
     result.pushKV("hash", blockindex->GetBlockHash().GetHex());
     const CBlockIndex *pnext;
     int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
     result.pushKV("confirmations", confirmations);
     result.pushKV("size", (int)::GetSerializeSize(block, PROTOCOL_VERSION));
     result.pushKV("height", blockindex->nHeight);
     result.pushKV("version", block.nVersion);
     result.pushKV("versionHex", strprintf("%08x", block.nVersion));
     result.pushKV("merkleroot", block.hashMerkleRoot.GetHex());
     UniValue txs(UniValue::VARR);
     for (const auto &tx : block.vtx) {
         if (txDetails) {
             UniValue objTx(UniValue::VOBJ);
             TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags());
             txs.push_back(objTx);
         } else {
             txs.push_back(tx->GetId().GetHex());
         }
     }
     result.pushKV("tx", txs);
     result.pushKV("time", block.GetBlockTime());
     result.pushKV("mediantime", int64_t(blockindex->GetMedianTimePast()));
     result.pushKV("nonce", uint64_t(block.nNonce));
     result.pushKV("bits", strprintf("%08x", block.nBits));
     result.pushKV("difficulty", GetDifficulty(blockindex));
     result.pushKV("chainwork", blockindex->nChainWork.GetHex());
     result.pushKV("nTx", uint64_t(blockindex->nTx));
 
     if (blockindex->pprev) {
         result.pushKV("previousblockhash",
                       blockindex->pprev->GetBlockHash().GetHex());
     }
     if (pnext) {
         result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
     }
     return result;
 }
 
 static RPCHelpMan getblockcount() {
     return RPCHelpMan{
         "getblockcount",
         "Returns the height of the most-work fully-validated chain.\n"
         "The genesis block has height 0.\n",
         {},
         RPCResult{RPCResult::Type::NUM, "", "The current block count"},
         RPCExamples{HelpExampleCli("getblockcount", "") +
                     HelpExampleRpc("getblockcount", "")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             LOCK(cs_main);
             return ::ChainActive().Height();
         },
     };
 }
 
 static RPCHelpMan getbestblockhash() {
     return RPCHelpMan{
         "getbestblockhash",
         "Returns the hash of the best (tip) block in the "
         "most-work fully-validated chain.\n",
         {},
         RPCResult{RPCResult::Type::STR_HEX, "", "the block hash, hex-encoded"},
         RPCExamples{HelpExampleCli("getbestblockhash", "") +
                     HelpExampleRpc("getbestblockhash", "")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             LOCK(cs_main);
             return ::ChainActive().Tip()->GetBlockHash().GetHex();
         },
     };
 }
 
 RPCHelpMan getfinalizedblockhash() {
     return RPCHelpMan{
         "getfinalizedblockhash",
         "Returns the hash of the currently finalized block\n",
         {},
         RPCResult{RPCResult::Type::STR_HEX, "", "the block hash, hex-encoded"},
         RPCExamples{HelpExampleCli("getfinalizedblockhash", "") +
                     HelpExampleRpc("getfinalizedblockhash", "")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             LOCK(cs_main);
             const CBlockIndex *blockIndexFinalized =
                 ::ChainstateActive().GetFinalizedBlock();
             if (blockIndexFinalized) {
                 return blockIndexFinalized->GetBlockHash().GetHex();
             }
             return UniValue(UniValue::VSTR);
         },
     };
 }
 
 void RPCNotifyBlockChange(const CBlockIndex *pindex) {
     if (pindex) {
         LOCK(cs_blockchange);
         latestblock.hash = pindex->GetBlockHash();
         latestblock.height = pindex->nHeight;
     }
     cond_blockchange.notify_all();
 }
 
 static RPCHelpMan waitfornewblock() {
     return RPCHelpMan{
         "waitfornewblock",
         "Waits for a specific new block and returns useful info about it.\n"
         "\nReturns the current block on timeout or exit.\n",
         {
             {"timeout", RPCArg::Type::NUM, /* default */ "0",
              "Time in milliseconds to wait for a response. 0 indicates no "
              "timeout."},
         },
         RPCResult{RPCResult::Type::OBJ,
                   "",
                   "",
                   {
                       {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
                       {RPCResult::Type::NUM, "height", "Block height"},
                   }},
         RPCExamples{HelpExampleCli("waitfornewblock", "1000") +
                     HelpExampleRpc("waitfornewblock", "1000")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             int timeout = 0;
             if (!request.params[0].isNull()) {
                 timeout = request.params[0].get_int();
             }
 
             CUpdatedBlock block;
             {
                 WAIT_LOCK(cs_blockchange, lock);
                 block = latestblock;
                 if (timeout) {
                     cond_blockchange.wait_for(
                         lock, std::chrono::milliseconds(timeout),
                         [&block]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {
                             return latestblock.height != block.height ||
                                    latestblock.hash != block.hash ||
                                    !IsRPCRunning();
                         });
                 } else {
                     cond_blockchange.wait(
                         lock,
                         [&block]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {
                             return latestblock.height != block.height ||
                                    latestblock.hash != block.hash ||
                                    !IsRPCRunning();
                         });
                 }
                 block = latestblock;
             }
             UniValue ret(UniValue::VOBJ);
             ret.pushKV("hash", block.hash.GetHex());
             ret.pushKV("height", block.height);
             return ret;
         },
     };
 }
 
 static RPCHelpMan waitforblock() {
     return RPCHelpMan{
         "waitforblock",
         "Waits for a specific new block and returns useful info about it.\n"
         "\nReturns the current block on timeout or exit.\n",
         {
             {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO,
              "Block hash to wait for."},
             {"timeout", RPCArg::Type::NUM, /* default */ "0",
              "Time in milliseconds to wait for a response. 0 indicates no "
              "timeout."},
         },
         RPCResult{RPCResult::Type::OBJ,
                   "",
                   "",
                   {
                       {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
                       {RPCResult::Type::NUM, "height", "Block height"},
                   }},
         RPCExamples{HelpExampleCli("waitforblock",
                                    "\"0000000000079f8ef3d2c688c244eb7a4570b24c9"
                                    "ed7b4a8c619eb02596f8862\" 1000") +
                     HelpExampleRpc("waitforblock",
                                    "\"0000000000079f8ef3d2c688c244eb7a4570b24c9"
                                    "ed7b4a8c619eb02596f8862\", 1000")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             int timeout = 0;
 
             BlockHash hash(ParseHashV(request.params[0], "blockhash"));
 
             if (!request.params[1].isNull()) {
                 timeout = request.params[1].get_int();
             }
 
             CUpdatedBlock block;
             {
                 WAIT_LOCK(cs_blockchange, lock);
                 if (timeout) {
                     cond_blockchange.wait_for(
                         lock, std::chrono::milliseconds(timeout),
                         [&hash]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {
                             return latestblock.hash == hash || !IsRPCRunning();
                         });
                 } else {
                     cond_blockchange.wait(
                         lock,
                         [&hash]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {
                             return latestblock.hash == hash || !IsRPCRunning();
                         });
                 }
                 block = latestblock;
             }
 
             UniValue ret(UniValue::VOBJ);
             ret.pushKV("hash", block.hash.GetHex());
             ret.pushKV("height", block.height);
             return ret;
         },
     };
 }
 
 static RPCHelpMan waitforblockheight() {
     return RPCHelpMan{
         "waitforblockheight",
         "Waits for (at least) block height and returns the height and "
         "hash\nof the current tip.\n"
         "\nReturns the current block on timeout or exit.\n",
         {
             {"height", RPCArg::Type::NUM, RPCArg::Optional::NO,
              "Block height to wait for."},
             {"timeout", RPCArg::Type::NUM, /* default */ "0",
              "Time in milliseconds to wait for a response. 0 indicates no "
              "timeout."},
         },
         RPCResult{RPCResult::Type::OBJ,
                   "",
                   "",
                   {
                       {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
                       {RPCResult::Type::NUM, "height", "Block height"},
                   }},
         RPCExamples{HelpExampleCli("waitforblockheight", "100 1000") +
                     HelpExampleRpc("waitforblockheight", "100, 1000")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             int timeout = 0;
 
             int height = request.params[0].get_int();
 
             if (!request.params[1].isNull()) {
                 timeout = request.params[1].get_int();
             }
 
             CUpdatedBlock block;
             {
                 WAIT_LOCK(cs_blockchange, lock);
                 if (timeout) {
                     cond_blockchange.wait_for(
                         lock, std::chrono::milliseconds(timeout),
                         [&height]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {
                             return latestblock.height >= height ||
                                    !IsRPCRunning();
                         });
                 } else {
                     cond_blockchange.wait(
                         lock,
                         [&height]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {
                             return latestblock.height >= height ||
                                    !IsRPCRunning();
                         });
                 }
                 block = latestblock;
             }
             UniValue ret(UniValue::VOBJ);
             ret.pushKV("hash", block.hash.GetHex());
             ret.pushKV("height", block.height);
             return ret;
         },
     };
 }
 
 static RPCHelpMan syncwithvalidationinterfacequeue() {
     return RPCHelpMan{
         "syncwithvalidationinterfacequeue",
         "Waits for the validation interface queue to catch up on everything "
         "that was there when we entered this function.\n",
         {},
         RPCResult{RPCResult::Type::NONE, "", ""},
         RPCExamples{HelpExampleCli("syncwithvalidationinterfacequeue", "") +
                     HelpExampleRpc("syncwithvalidationinterfacequeue", "")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             SyncWithValidationInterfaceQueue();
             return NullUniValue;
         },
     };
 }
 
 static RPCHelpMan getdifficulty() {
     return RPCHelpMan{
         "getdifficulty",
         "Returns the proof-of-work difficulty as a multiple of the minimum "
         "difficulty.\n",
         {},
         RPCResult{RPCResult::Type::NUM, "",
                   "the proof-of-work difficulty as a multiple of the minimum "
                   "difficulty."},
         RPCExamples{HelpExampleCli("getdifficulty", "") +
                     HelpExampleRpc("getdifficulty", "")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             LOCK(cs_main);
             return GetDifficulty(::ChainActive().Tip());
         },
     };
 }
 
 static std::vector<RPCResult> MempoolEntryDescription() {
     const auto &ticker = Currency::get().ticker;
     return {
         RPCResult{RPCResult::Type::NUM, "size", "transaction size."},
         RPCResult{RPCResult::Type::STR_AMOUNT, "fee",
                   "transaction fee in " + ticker + " (DEPRECATED)"},
         RPCResult{RPCResult::Type::STR_AMOUNT, "modifiedfee",
                   "transaction fee with fee deltas used for mining priority "
                   "(DEPRECATED)"},
         RPCResult{RPCResult::Type::NUM_TIME, "time",
                   "local time transaction entered pool in seconds since 1 Jan "
                   "1970 GMT"},
         RPCResult{RPCResult::Type::NUM, "height",
                   "block height when transaction entered pool"},
         RPCResult{RPCResult::Type::NUM, "descendantcount",
                   "number of in-mempool descendant transactions (including "
                   "this one)"},
         RPCResult{RPCResult::Type::NUM, "descendantsize",
                   "transaction size of in-mempool descendants "
                   "(including this one)"},
         RPCResult{RPCResult::Type::STR_AMOUNT, "descendantfees",
                   "modified fees (see above) of in-mempool descendants "
                   "(including this one) (DEPRECATED)"},
         RPCResult{
             RPCResult::Type::NUM, "ancestorcount",
             "number of in-mempool ancestor transactions (including this one)"},
         RPCResult{
             RPCResult::Type::NUM, "ancestorsize",
             "transaction size of in-mempool ancestors (including this one)"},
         RPCResult{RPCResult::Type::STR_AMOUNT, "ancestorfees",
                   "modified fees (see above) of in-mempool ancestors "
                   "(including this one) (DEPRECATED)"},
         RPCResult{RPCResult::Type::OBJ,
                   "fees",
                   "",
                   {
                       RPCResult{RPCResult::Type::STR_AMOUNT, "base",
                                 "transaction fee in " + ticker},
                       RPCResult{RPCResult::Type::STR_AMOUNT, "modified",
                                 "transaction fee with fee deltas used for "
                                 "mining priority in " +
                                     ticker},
                       RPCResult{RPCResult::Type::STR_AMOUNT, "ancestor",
                                 "modified fees (see above) of in-mempool "
                                 "ancestors (including this one) in " +
                                     ticker},
                       RPCResult{RPCResult::Type::STR_AMOUNT, "descendant",
                                 "modified fees (see above) of in-mempool "
                                 "descendants (including this one) in " +
                                     ticker},
                   }},
         RPCResult{
             RPCResult::Type::ARR,
             "depends",
             "unconfirmed transactions used as inputs for this transaction",
             {RPCResult{RPCResult::Type::STR_HEX, "transactionid",
                        "parent transaction id"}}},
         RPCResult{
             RPCResult::Type::ARR,
             "spentby",
             "unconfirmed transactions spending outputs from this transaction",
             {RPCResult{RPCResult::Type::STR_HEX, "transactionid",
                        "child transaction id"}}},
         RPCResult{RPCResult::Type::BOOL, "unbroadcast",
                   "Whether this transaction is currently unbroadcast (initial "
                   "broadcast not yet acknowledged by any peers)"},
     };
 }
 
 static void entryToJSON(const CTxMemPool &pool, UniValue &info,
                         const CTxMemPoolEntry &e)
     EXCLUSIVE_LOCKS_REQUIRED(pool.cs) {
     AssertLockHeld(pool.cs);
 
     UniValue fees(UniValue::VOBJ);
     fees.pushKV("base", e.GetFee());
     fees.pushKV("modified", e.GetModifiedFee());
     fees.pushKV("ancestor", e.GetModFeesWithAncestors());
     fees.pushKV("descendant", e.GetModFeesWithDescendants());
     info.pushKV("fees", fees);
 
     info.pushKV("size", (int)e.GetTxSize());
     info.pushKV("fee", e.GetFee());
     info.pushKV("modifiedfee", e.GetModifiedFee());
     info.pushKV("time", count_seconds(e.GetTime()));
     info.pushKV("height", (int)e.GetHeight());
     info.pushKV("descendantcount", e.GetCountWithDescendants());
     info.pushKV("descendantsize", e.GetSizeWithDescendants());
     info.pushKV("descendantfees", e.GetModFeesWithDescendants() / SATOSHI);
     info.pushKV("ancestorcount", e.GetCountWithAncestors());
     info.pushKV("ancestorsize", e.GetSizeWithAncestors());
     info.pushKV("ancestorfees", e.GetModFeesWithAncestors() / SATOSHI);
     const CTransaction &tx = e.GetTx();
     std::set<std::string> setDepends;
     for (const CTxIn &txin : tx.vin) {
         if (pool.exists(txin.prevout.GetTxId())) {
             setDepends.insert(txin.prevout.GetTxId().ToString());
         }
     }
 
     UniValue depends(UniValue::VARR);
     for (const std::string &dep : setDepends) {
         depends.push_back(dep);
     }
 
     info.pushKV("depends", depends);
 
     UniValue spent(UniValue::VARR);
     const CTxMemPool::txiter &it = pool.mapTx.find(tx.GetId());
     const CTxMemPoolEntry::Children &children = it->GetMemPoolChildrenConst();
     for (const CTxMemPoolEntry &child : children) {
         spent.push_back(child.GetTx().GetId().ToString());
     }
 
     info.pushKV("spentby", spent);
     info.pushKV("unbroadcast", pool.IsUnbroadcastTx(tx.GetId()));
 }
 
 UniValue MempoolToJSON(const CTxMemPool &pool, bool verbose,
                        bool include_mempool_sequence) {
     if (verbose) {
         if (include_mempool_sequence) {
             throw JSONRPCError(
                 RPC_INVALID_PARAMETER,
                 "Verbose results cannot contain mempool sequence values.");
         }
         LOCK(pool.cs);
         UniValue o(UniValue::VOBJ);
         for (const CTxMemPoolEntry &e : pool.mapTx) {
             const uint256 &txid = e.GetTx().GetId();
             UniValue info(UniValue::VOBJ);
             entryToJSON(pool, info, e);
             // Mempool has unique entries so there is no advantage in using
             // UniValue::pushKV, which checks if the key already exists in O(N).
             // UniValue::__pushKV is used instead which currently is O(1).
             o.__pushKV(txid.ToString(), info);
         }
         return o;
     } else {
         uint64_t mempool_sequence;
         std::vector<uint256> vtxids;
         {
             LOCK(pool.cs);
             pool.queryHashes(vtxids);
             mempool_sequence = pool.GetSequence();
         }
         UniValue a(UniValue::VARR);
         for (const uint256 &txid : vtxids) {
             a.push_back(txid.ToString());
         }
 
         if (!include_mempool_sequence) {
             return a;
         } else {
             UniValue o(UniValue::VOBJ);
             o.pushKV("txids", a);
             o.pushKV("mempool_sequence", mempool_sequence);
             return o;
         }
     }
 }
 
 static RPCHelpMan getrawmempool() {
     return RPCHelpMan{
         "getrawmempool",
         "Returns all transaction ids in memory pool as a json array of "
         "string transaction ids.\n"
         "\nHint: use getmempoolentry to fetch a specific transaction from the "
         "mempool.\n",
         {
             {"verbose", RPCArg::Type::BOOL, /* default */ "false",
              "True for a json object, false for array of transaction ids"},
             {"mempool_sequence", RPCArg::Type::BOOL, /* default */ "false",
              "If verbose=false, returns a json object with transaction list "
              "and mempool sequence number attached."},
         },
         {
             RPCResult{"for verbose = false",
                       RPCResult::Type::ARR,
                       "",
                       "",
                       {
                           {RPCResult::Type::STR_HEX, "", "The transaction id"},
                       }},
             RPCResult{"for verbose = true",
                       RPCResult::Type::OBJ_DYN,
                       "",
                       "",
                       {
                           {RPCResult::Type::OBJ, "transactionid", "",
                            MempoolEntryDescription()},
                       }},
             RPCResult{
                 "for verbose = false and mempool_sequence = true",
                 RPCResult::Type::OBJ,
                 "",
                 "",
                 {
                     {RPCResult::Type::ARR,
                      "txids",
                      "",
                      {
                          {RPCResult::Type::STR_HEX, "", "The transaction id"},
                      }},
                     {RPCResult::Type::NUM, "mempool_sequence",
                      "The mempool sequence value."},
                 }},
         },
         RPCExamples{HelpExampleCli("getrawmempool", "true") +
                     HelpExampleRpc("getrawmempool", "true")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             bool fVerbose = false;
             if (!request.params[0].isNull()) {
                 fVerbose = request.params[0].get_bool();
             }
 
             bool include_mempool_sequence = false;
             if (!request.params[1].isNull()) {
                 include_mempool_sequence = request.params[1].get_bool();
             }
 
             return MempoolToJSON(EnsureMemPool(request.context), fVerbose,
                                  include_mempool_sequence);
         },
     };
 }
 
 static RPCHelpMan getmempoolancestors() {
     return RPCHelpMan{
         "getmempoolancestors",
         "If txid is in the mempool, returns all in-mempool ancestors.\n",
         {
             {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO,
              "The transaction id (must be in mempool)"},
             {"verbose", RPCArg::Type::BOOL, /* default */ "false",
              "True for a json object, false for array of transaction ids"},
         },
         {
             RPCResult{
                 "for verbose = false",
                 RPCResult::Type::ARR,
                 "",
                 "",
                 {{RPCResult::Type::STR_HEX, "",
                   "The transaction id of an in-mempool ancestor transaction"}}},
             RPCResult{"for verbose = true",
                       RPCResult::Type::OBJ_DYN,
                       "",
                       "",
                       {
                           {RPCResult::Type::OBJ, "transactionid", "",
                            MempoolEntryDescription()},
                       }},
         },
         RPCExamples{HelpExampleCli("getmempoolancestors", "\"mytxid\"") +
                     HelpExampleRpc("getmempoolancestors", "\"mytxid\"")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             bool fVerbose = false;
             if (!request.params[1].isNull()) {
                 fVerbose = request.params[1].get_bool();
             }
 
             TxId txid(ParseHashV(request.params[0], "parameter 1"));
 
             const CTxMemPool &mempool = EnsureMemPool(request.context);
             LOCK(mempool.cs);
 
             CTxMemPool::txiter it = mempool.mapTx.find(txid);
             if (it == mempool.mapTx.end()) {
                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
                                    "Transaction not in mempool");
             }
 
             CTxMemPool::setEntries setAncestors;
             uint64_t noLimit = std::numeric_limits<uint64_t>::max();
             std::string dummy;
             mempool.CalculateMemPoolAncestors(*it, setAncestors, noLimit,
                                               noLimit, noLimit, noLimit, dummy,
                                               false);
 
             if (!fVerbose) {
                 UniValue o(UniValue::VARR);
                 for (CTxMemPool::txiter ancestorIt : setAncestors) {
                     o.push_back(ancestorIt->GetTx().GetId().ToString());
                 }
                 return o;
             } else {
                 UniValue o(UniValue::VOBJ);
                 for (CTxMemPool::txiter ancestorIt : setAncestors) {
                     const CTxMemPoolEntry &e = *ancestorIt;
                     const TxId &_txid = e.GetTx().GetId();
                     UniValue info(UniValue::VOBJ);
                     entryToJSON(mempool, info, e);
                     o.pushKV(_txid.ToString(), info);
                 }
                 return o;
             }
         },
     };
 }
 
 static RPCHelpMan getmempooldescendants() {
     return RPCHelpMan{
         "getmempooldescendants",
         "If txid is in the mempool, returns all in-mempool descendants.\n",
         {
             {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO,
              "The transaction id (must be in mempool)"},
             {"verbose", RPCArg::Type::BOOL, /* default */ "false",
              "True for a json object, false for array of transaction ids"},
         },
         {
             RPCResult{"for verbose = false",
                       RPCResult::Type::ARR,
                       "",
                       "",
                       {{RPCResult::Type::STR_HEX, "",
                         "The transaction id of an in-mempool descendant "
                         "transaction"}}},
             RPCResult{"for verbose = true",
                       RPCResult::Type::OBJ_DYN,
                       "",
                       "",
                       {
                           {RPCResult::Type::OBJ, "transactionid", "",
                            MempoolEntryDescription()},
                       }},
         },
         RPCExamples{HelpExampleCli("getmempooldescendants", "\"mytxid\"") +
                     HelpExampleRpc("getmempooldescendants", "\"mytxid\"")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             bool fVerbose = false;
             if (!request.params[1].isNull()) {
                 fVerbose = request.params[1].get_bool();
             }
 
             TxId txid(ParseHashV(request.params[0], "parameter 1"));
 
             const CTxMemPool &mempool = EnsureMemPool(request.context);
             LOCK(mempool.cs);
 
             CTxMemPool::txiter it = mempool.mapTx.find(txid);
             if (it == mempool.mapTx.end()) {
                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
                                    "Transaction not in mempool");
             }
 
             CTxMemPool::setEntries setDescendants;
             mempool.CalculateDescendants(it, setDescendants);
             // CTxMemPool::CalculateDescendants will include the given tx
             setDescendants.erase(it);
 
             if (!fVerbose) {
                 UniValue o(UniValue::VARR);
                 for (CTxMemPool::txiter descendantIt : setDescendants) {
                     o.push_back(descendantIt->GetTx().GetId().ToString());
                 }
 
                 return o;
             } else {
                 UniValue o(UniValue::VOBJ);
                 for (CTxMemPool::txiter descendantIt : setDescendants) {
                     const CTxMemPoolEntry &e = *descendantIt;
                     const TxId &_txid = e.GetTx().GetId();
                     UniValue info(UniValue::VOBJ);
                     entryToJSON(mempool, info, e);
                     o.pushKV(_txid.ToString(), info);
                 }
                 return o;
             }
         },
     };
 }
 
 static RPCHelpMan getmempoolentry() {
     return RPCHelpMan{
         "getmempoolentry",
         "Returns mempool data for given transaction\n",
         {
             {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO,
              "The transaction id (must be in mempool)"},
         },
         RPCResult{RPCResult::Type::OBJ, "", "", MempoolEntryDescription()},
         RPCExamples{HelpExampleCli("getmempoolentry", "\"mytxid\"") +
                     HelpExampleRpc("getmempoolentry", "\"mytxid\"")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             TxId txid(ParseHashV(request.params[0], "parameter 1"));
 
             const CTxMemPool &mempool = EnsureMemPool(request.context);
             LOCK(mempool.cs);
 
             CTxMemPool::txiter it = mempool.mapTx.find(txid);
             if (it == mempool.mapTx.end()) {
                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
                                    "Transaction not in mempool");
             }
 
             const CTxMemPoolEntry &e = *it;
             UniValue info(UniValue::VOBJ);
             entryToJSON(mempool, info, e);
             return info;
         },
     };
 }
 
 static RPCHelpMan getblockhash() {
     return RPCHelpMan{
         "getblockhash",
         "Returns hash of block in best-block-chain at height provided.\n",
         {
             {"height", RPCArg::Type::NUM, RPCArg::Optional::NO,
              "The height index"},
         },
         RPCResult{RPCResult::Type::STR_HEX, "", "The block hash"},
         RPCExamples{HelpExampleCli("getblockhash", "1000") +
                     HelpExampleRpc("getblockhash", "1000")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             LOCK(cs_main);
 
             int nHeight = request.params[0].get_int();
             if (nHeight < 0 || nHeight > ::ChainActive().Height()) {
                 throw JSONRPCError(RPC_INVALID_PARAMETER,
                                    "Block height out of range");
             }
 
             CBlockIndex *pblockindex = ::ChainActive()[nHeight];
             return pblockindex->GetBlockHash().GetHex();
         },
     };
 }
 
 static RPCHelpMan getblockheader() {
     return RPCHelpMan{
         "getblockheader",
         "If verbose is false, returns a string that is serialized, hex-encoded "
         "data for blockheader 'hash'.\n"
         "If verbose is true, returns an Object with information about "
         "blockheader <hash>.\n",
         {
             {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO,
              "The block hash"},
             {"verbose", RPCArg::Type::BOOL, /* default */ "true",
              "true for a json object, false for the hex-encoded data"},
         },
         {
             RPCResult{
                 "for verbose = true",
                 RPCResult::Type::OBJ,
                 "",
                 "",
                 {
                     {RPCResult::Type::STR_HEX, "hash",
                      "the block hash (same as provided)"},
                     {RPCResult::Type::NUM, "confirmations",
                      "The number of confirmations, or -1 if the block is not "
                      "on the main chain"},
                     {RPCResult::Type::NUM, "height",
                      "The block height or index"},
                     {RPCResult::Type::NUM, "version", "The block version"},
                     {RPCResult::Type::STR_HEX, "versionHex",
                      "The block version formatted in hexadecimal"},
                     {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
                     {RPCResult::Type::NUM_TIME, "time",
                      "The block time expressed in " + UNIX_EPOCH_TIME},
                     {RPCResult::Type::NUM_TIME, "mediantime",
                      "The median block time expressed in " + UNIX_EPOCH_TIME},
                     {RPCResult::Type::NUM, "nonce", "The nonce"},
                     {RPCResult::Type::STR_HEX, "bits", "The bits"},
                     {RPCResult::Type::NUM, "difficulty", "The difficulty"},
                     {RPCResult::Type::STR_HEX, "chainwork",
                      "Expected number of hashes required to produce the "
                      "current chain"},
                     {RPCResult::Type::NUM, "nTx",
                      "The number of transactions in the block"},
                     {RPCResult::Type::STR_HEX, "previousblockhash",
                      "The hash of the previous block"},
                     {RPCResult::Type::STR_HEX, "nextblockhash",
                      "The hash of the next block"},
                 }},
             RPCResult{"for verbose=false", RPCResult::Type::STR_HEX, "",
                       "A string that is serialized, hex-encoded data for block "
                       "'hash'"},
         },
         RPCExamples{HelpExampleCli("getblockheader",
                                    "\"00000000c937983704a73af28acdec37b049d214a"
                                    "dbda81d7e2a3dd146f6ed09\"") +
                     HelpExampleRpc("getblockheader",
                                    "\"00000000c937983704a73af28acdec37b049d214a"
                                    "dbda81d7e2a3dd146f6ed09\"")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             BlockHash hash(ParseHashV(request.params[0], "hash"));
 
             bool fVerbose = true;
             if (!request.params[1].isNull()) {
                 fVerbose = request.params[1].get_bool();
             }
 
             const CBlockIndex *pblockindex;
             const CBlockIndex *tip;
             {
                 LOCK(cs_main);
                 pblockindex = LookupBlockIndex(hash);
                 tip = ::ChainActive().Tip();
             }
 
             if (!pblockindex) {
                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
                                    "Block not found");
             }
 
             if (!fVerbose) {
                 CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
                 ssBlock << pblockindex->GetBlockHeader();
                 std::string strHex = HexStr(ssBlock);
                 return strHex;
             }
 
             return blockheaderToJSON(tip, pblockindex);
         },
     };
 }
 
 static CBlock GetBlockChecked(const Config &config,
                               const CBlockIndex *pblockindex) {
     CBlock block;
     if (IsBlockPruned(pblockindex)) {
         throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
     }
 
     if (!ReadBlockFromDisk(block, pblockindex,
                            config.GetChainParams().GetConsensus())) {
         // Block not found on disk. This could be because we have the block
         // header in our index but not yet have the block or did not accept the
         // block.
         throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
     }
 
     return block;
 }
 
 static CBlockUndo GetUndoChecked(const CBlockIndex *pblockindex) {
     CBlockUndo blockUndo;
     if (IsBlockPruned(pblockindex)) {
         throw JSONRPCError(RPC_MISC_ERROR,
                            "Undo data not available (pruned data)");
     }
 
     if (!UndoReadFromDisk(blockUndo, pblockindex)) {
         throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk");
     }
 
     return blockUndo;
 }
 
 static RPCHelpMan getblock() {
     return RPCHelpMan{
         "getblock",
         "If verbosity is 0 or false, returns a string that is serialized, "
         "hex-encoded data for block 'hash'.\n"
         "If verbosity is 1 or true, returns an Object with information about "
         "block <hash>.\n"
         "If verbosity is 2, returns an Object with information about block "
         "<hash> and information about each transaction.\n",
         {
             {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO,
              "The block hash"},
             {"verbosity|verbose", RPCArg::Type::NUM, /* default */ "1",
              "0 for hex-encoded data, 1 for a json object, and 2 for json "
              "object with transaction data"},
         },
         {
             RPCResult{"for verbosity = 0", RPCResult::Type::STR_HEX, "",
                       "A string that is serialized, hex-encoded data for block "
                       "'hash'"},
             RPCResult{
                 "for verbosity = 1",
                 RPCResult::Type::OBJ,
                 "",
                 "",
                 {
                     {RPCResult::Type::STR_HEX, "hash",
                      "the block hash (same as provided)"},
                     {RPCResult::Type::NUM, "confirmations",
                      "The number of confirmations, or -1 if the block is not "
                      "on the main chain"},
                     {RPCResult::Type::NUM, "size", "The block size"},
                     {RPCResult::Type::NUM, "height",
                      "The block height or index"},
                     {RPCResult::Type::NUM, "version", "The block version"},
                     {RPCResult::Type::STR_HEX, "versionHex",
                      "The block version formatted in hexadecimal"},
                     {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
                     {RPCResult::Type::ARR,
                      "tx",
                      "The transaction ids",
                      {{RPCResult::Type::STR_HEX, "", "The transaction id"}}},
                     {RPCResult::Type::NUM_TIME, "time",
                      "The block time expressed in " + UNIX_EPOCH_TIME},
                     {RPCResult::Type::NUM_TIME, "mediantime",
                      "The median block time expressed in " + UNIX_EPOCH_TIME},
                     {RPCResult::Type::NUM, "nonce", "The nonce"},
                     {RPCResult::Type::STR_HEX, "bits", "The bits"},
                     {RPCResult::Type::NUM, "difficulty", "The difficulty"},
                     {RPCResult::Type::STR_HEX, "chainwork",
                      "Expected number of hashes required to produce the chain "
                      "up to this block (in hex)"},
                     {RPCResult::Type::NUM, "nTx",
                      "The number of transactions in the block"},
                     {RPCResult::Type::STR_HEX, "previousblockhash",
                      "The hash of the previous block"},
                     {RPCResult::Type::STR_HEX, "nextblockhash",
                      "The hash of the next block"},
                 }},
             RPCResult{"for verbosity = 2",
                       RPCResult::Type::OBJ,
                       "",
                       "",
                       {
                           {RPCResult::Type::ELISION, "",
                            "Same output as verbosity = 1"},
                           {RPCResult::Type::ARR,
                            "tx",
                            "",
                            {
                                {RPCResult::Type::OBJ,
                                 "",
                                 "",
                                 {
                                     {RPCResult::Type::ELISION, "",
                                      "The transactions in the format of the "
                                      "getrawtransaction RPC. Different from "
                                      "verbosity = 1 \"tx\" result"},
                                 }},
                            }},
                       }},
         },
         RPCExamples{
             HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d"
                                        "214adbda81d7e2a3dd146f6ed09\"") +
             HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d"
                                        "214adbda81d7e2a3dd146f6ed09\"")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             BlockHash hash(ParseHashV(request.params[0], "blockhash"));
 
             int verbosity = 1;
             if (!request.params[1].isNull()) {
                 if (request.params[1].isNum()) {
                     verbosity = request.params[1].get_int();
                 } else {
                     verbosity = request.params[1].get_bool() ? 1 : 0;
                 }
             }
 
             CBlock block;
             const CBlockIndex *pblockindex;
             const CBlockIndex *tip;
             {
                 LOCK(cs_main);
                 pblockindex = LookupBlockIndex(hash);
                 tip = ::ChainActive().Tip();
 
                 if (!pblockindex) {
                     throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
                                        "Block not found");
                 }
 
                 block = GetBlockChecked(config, pblockindex);
             }
 
             if (verbosity <= 0) {
                 CDataStream ssBlock(SER_NETWORK,
                                     PROTOCOL_VERSION | RPCSerializationFlags());
                 ssBlock << block;
                 std::string strHex = HexStr(ssBlock);
                 return strHex;
             }
 
             return blockToJSON(block, tip, pblockindex, verbosity >= 2);
         },
     };
 }
 
 static RPCHelpMan pruneblockchain() {
     return RPCHelpMan{
         "pruneblockchain",
         "",
         {
             {"height", RPCArg::Type::NUM, RPCArg::Optional::NO,
              "The block height to prune up to. May be set to a discrete "
              "height, or to a " +
                  UNIX_EPOCH_TIME +
                  "\n"
                  "                  to prune blocks whose block time is at "
                  "least 2 hours older than the provided timestamp."},
         },
         RPCResult{RPCResult::Type::NUM, "", "Height of the last block pruned"},
         RPCExamples{HelpExampleCli("pruneblockchain", "1000") +
                     HelpExampleRpc("pruneblockchain", "1000")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             if (!fPruneMode) {
                 throw JSONRPCError(
                     RPC_MISC_ERROR,
                     "Cannot prune blocks because node is not in prune mode.");
             }
 
             LOCK(cs_main);
 
             int heightParam = request.params[0].get_int();
             if (heightParam < 0) {
                 throw JSONRPCError(RPC_INVALID_PARAMETER,
                                    "Negative block height.");
             }
 
             // Height value more than a billion is too high to be a block
             // height, and too low to be a block time (corresponds to timestamp
             // from Sep 2001).
             if (heightParam > 1000000000) {
                 // Add a 2 hour buffer to include blocks which might have had
                 // old timestamps
                 CBlockIndex *pindex = ::ChainActive().FindEarliestAtLeast(
                     heightParam - TIMESTAMP_WINDOW, 0);
                 if (!pindex) {
                     throw JSONRPCError(RPC_INVALID_PARAMETER,
                                        "Could not find block with at least the "
                                        "specified timestamp.");
                 }
                 heightParam = pindex->nHeight;
             }
 
             unsigned int height = (unsigned int)heightParam;
             unsigned int chainHeight = (unsigned int)::ChainActive().Height();
             if (chainHeight < config.GetChainParams().PruneAfterHeight()) {
                 throw JSONRPCError(RPC_MISC_ERROR,
                                    "Blockchain is too short for pruning.");
             } else if (height > chainHeight) {
                 throw JSONRPCError(
                     RPC_INVALID_PARAMETER,
                     "Blockchain is shorter than the attempted prune height.");
             } else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) {
                 LogPrint(BCLog::RPC,
                          "Attempt to prune blocks close to the tip. "
                          "Retaining the minimum number of blocks.\n");
                 height = chainHeight - MIN_BLOCKS_TO_KEEP;
             }
 
             PruneBlockFilesManual(height);
             const CBlockIndex *block = ::ChainActive().Tip();
             CHECK_NONFATAL(block);
             while (block->pprev && (block->pprev->nStatus.hasData())) {
                 block = block->pprev;
             }
             return uint64_t(block->nHeight);
         },
     };
 }
 
 static RPCHelpMan gettxoutsetinfo() {
     return RPCHelpMan{
         "gettxoutsetinfo",
         "Returns statistics about the unspent transaction output set.\n"
         "Note this call may take some time.\n",
         {
             {"hash_type", RPCArg::Type::STR, /* default */ "hash_serialized",
              "Which UTXO set hash should be calculated. Options: "
              "'hash_serialized' (the legacy algorithm), 'none'."},
         },
         RPCResult{RPCResult::Type::OBJ,
                   "",
                   "",
                   {
                       {RPCResult::Type::NUM, "height",
                        "The current block height (index)"},
                       {RPCResult::Type::STR_HEX, "bestblock",
                        "The hash of the block at the tip of the chain"},
                       {RPCResult::Type::NUM, "transactions",
                        "The number of transactions with unspent outputs"},
                       {RPCResult::Type::NUM, "txouts",
                        "The number of unspent transaction outputs"},
                       {RPCResult::Type::NUM, "bogosize",
                        "A meaningless metric for UTXO set size"},
                       {RPCResult::Type::STR_HEX, "hash_serialized",
                        "The serialized hash (only present if 'hash_serialized' "
                        "hash_type is chosen)"},
                       {RPCResult::Type::NUM, "disk_size",
                        "The estimated size of the chainstate on disk"},
                       {RPCResult::Type::STR_AMOUNT, "total_amount",
                        "The total amount"},
                   }},
         RPCExamples{HelpExampleCli("gettxoutsetinfo", "") +
                     HelpExampleRpc("gettxoutsetinfo", "")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             UniValue ret(UniValue::VOBJ);
 
             CCoinsStats stats;
             ::ChainstateActive().ForceFlushStateToDisk();
 
             const CoinStatsHashType hash_type = ParseHashType(
                 request.params[0], CoinStatsHashType::HASH_SERIALIZED);
 
             CCoinsView *coins_view =
                 WITH_LOCK(cs_main, return &ChainstateActive().CoinsDB());
             NodeContext &node = EnsureNodeContext(request.context);
             if (GetUTXOStats(coins_view, stats, hash_type,
                              node.rpc_interruption_point)) {
                 ret.pushKV("height", int64_t(stats.nHeight));
                 ret.pushKV("bestblock", stats.hashBlock.GetHex());
                 ret.pushKV("transactions", int64_t(stats.nTransactions));
                 ret.pushKV("txouts", int64_t(stats.nTransactionOutputs));
                 ret.pushKV("bogosize", int64_t(stats.nBogoSize));
                 if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
                     ret.pushKV("hash_serialized",
                                stats.hashSerialized.GetHex());
                 }
                 ret.pushKV("disk_size", stats.nDiskSize);
                 ret.pushKV("total_amount", stats.nTotalAmount);
             } else {
                 throw JSONRPCError(RPC_INTERNAL_ERROR,
                                    "Unable to read UTXO set");
             }
             return ret;
         },
     };
 }
 
 RPCHelpMan gettxout() {
     return RPCHelpMan{
         "gettxout",
         "Returns details about an unspent transaction output.\n",
         {
             {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO,
              "The transaction id"},
             {"n", RPCArg::Type::NUM, RPCArg::Optional::NO, "vout number"},
             {"include_mempool", RPCArg::Type::BOOL, /* default */ "true",
              "Whether to include the mempool. Note that an unspent output that "
              "is spent in the mempool won't appear."},
         },
         RPCResult{
             RPCResult::Type::OBJ,
             "",
             "",
             {
                 {RPCResult::Type::STR_HEX, "bestblock",
                  "The hash of the block at the tip of the chain"},
                 {RPCResult::Type::NUM, "confirmations",
                  "The number of confirmations"},
                 {RPCResult::Type::STR_AMOUNT, "value",
                  "The transaction value in " + Currency::get().ticker},
                 {RPCResult::Type::OBJ,
                  "scriptPubKey",
                  "",
                  {
                      {RPCResult::Type::STR_HEX, "asm", ""},
                      {RPCResult::Type::STR_HEX, "hex", ""},
                      {RPCResult::Type::NUM, "reqSigs",
                       "Number of required signatures"},
                      {RPCResult::Type::STR_HEX, "type",
                       "The type, eg pubkeyhash"},
                      {RPCResult::Type::ARR,
                       "addresses",
                       "array of bitcoin addresses",
                       {{RPCResult::Type::STR, "address", "bitcoin address"}}},
                  }},
                 {RPCResult::Type::BOOL, "coinbase", "Coinbase or not"},
             }},
         RPCExamples{"\nGet unspent transactions\n" +
                     HelpExampleCli("listunspent", "") + "\nView the details\n" +
                     HelpExampleCli("gettxout", "\"txid\" 1") +
                     "\nAs a JSON-RPC call\n" +
                     HelpExampleRpc("gettxout", "\"txid\", 1")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             LOCK(cs_main);
 
             UniValue ret(UniValue::VOBJ);
 
             TxId txid(ParseHashV(request.params[0], "txid"));
             int n = request.params[1].get_int();
             COutPoint out(txid, n);
             bool fMempool = true;
             if (!request.params[2].isNull()) {
                 fMempool = request.params[2].get_bool();
             }
 
             Coin coin;
             CCoinsViewCache *coins_view = &::ChainstateActive().CoinsTip();
 
             if (fMempool) {
                 const CTxMemPool &mempool = EnsureMemPool(request.context);
                 LOCK(mempool.cs);
                 CCoinsViewMemPool view(coins_view, mempool);
                 if (!view.GetCoin(out, coin) || mempool.isSpent(out)) {
                     return NullUniValue;
                 }
             } else {
                 if (!coins_view->GetCoin(out, coin)) {
                     return NullUniValue;
                 }
             }
 
             const CBlockIndex *pindex =
                 LookupBlockIndex(coins_view->GetBestBlock());
             ret.pushKV("bestblock", pindex->GetBlockHash().GetHex());
             if (coin.GetHeight() == MEMPOOL_HEIGHT) {
                 ret.pushKV("confirmations", 0);
             } else {
                 ret.pushKV("confirmations",
                            int64_t(pindex->nHeight - coin.GetHeight() + 1));
             }
             ret.pushKV("value", coin.GetTxOut().nValue);
             UniValue o(UniValue::VOBJ);
             ScriptPubKeyToUniv(coin.GetTxOut().scriptPubKey, o, true);
             ret.pushKV("scriptPubKey", o);
             ret.pushKV("coinbase", coin.IsCoinBase());
 
             return ret;
         },
     };
 }
 
 static RPCHelpMan verifychain() {
     return RPCHelpMan{
         "verifychain",
         "Verifies blockchain database.\n",
         {
             {"checklevel", RPCArg::Type::NUM,
              /* default */ strprintf("%d, range=0-4", DEFAULT_CHECKLEVEL),
              strprintf("How thorough the block verification is:\n - %s",
                        Join(CHECKLEVEL_DOC, "\n- "))},
             {"nblocks", RPCArg::Type::NUM,
              /* default */ strprintf("%d, 0=all", DEFAULT_CHECKBLOCKS),
              "The number of blocks to check."},
         },
         RPCResult{RPCResult::Type::BOOL, "", "Verified or not"},
         RPCExamples{HelpExampleCli("verifychain", "") +
                     HelpExampleRpc("verifychain", "")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             const int check_level(request.params[0].isNull()
                                       ? DEFAULT_CHECKLEVEL
                                       : request.params[0].get_int());
             const int check_depth{request.params[1].isNull()
                                       ? DEFAULT_CHECKBLOCKS
                                       : request.params[1].get_int()};
 
             LOCK(cs_main);
 
             return CVerifyDB().VerifyDB(config,
                                         &::ChainstateActive().CoinsTip(),
                                         check_level, check_depth);
         },
     };
 }
 
 static void BIP9SoftForkDescPushBack(UniValue &softforks,
                                      const Consensus::Params &consensusParams,
                                      Consensus::DeploymentPos id)
     EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
     // For BIP9 deployments.
     // Deployments (e.g. testdummy) with timeout value before Jan 1, 2009 are
     // hidden. A timeout value of 0 guarantees a softfork will never be
     // activated. This is used when merging logic to implement a proposed
     // softfork without a specified deployment schedule.
     if (consensusParams.vDeployments[id].nTimeout <= 1230768000) {
         return;
     }
 
     UniValue bip9(UniValue::VOBJ);
     const ThresholdState thresholdState =
         VersionBitsTipState(consensusParams, id);
     switch (thresholdState) {
         case ThresholdState::DEFINED:
             bip9.pushKV("status", "defined");
             break;
         case ThresholdState::STARTED:
             bip9.pushKV("status", "started");
             break;
         case ThresholdState::LOCKED_IN:
             bip9.pushKV("status", "locked_in");
             break;
         case ThresholdState::ACTIVE:
             bip9.pushKV("status", "active");
             break;
         case ThresholdState::FAILED:
             bip9.pushKV("status", "failed");
             break;
     }
     if (ThresholdState::STARTED == thresholdState) {
         bip9.pushKV("bit", consensusParams.vDeployments[id].bit);
     }
     bip9.pushKV("start_time", consensusParams.vDeployments[id].nStartTime);
     bip9.pushKV("timeout", consensusParams.vDeployments[id].nTimeout);
     int64_t since_height = VersionBitsTipStateSinceHeight(consensusParams, id);
     bip9.pushKV("since", since_height);
     if (ThresholdState::STARTED == thresholdState) {
         UniValue statsUV(UniValue::VOBJ);
         BIP9Stats statsStruct = VersionBitsTipStatistics(consensusParams, id);
         statsUV.pushKV("period", statsStruct.period);
         statsUV.pushKV("threshold", statsStruct.threshold);
         statsUV.pushKV("elapsed", statsStruct.elapsed);
         statsUV.pushKV("count", statsStruct.count);
         statsUV.pushKV("possible", statsStruct.possible);
         bip9.pushKV("statistics", statsUV);
     }
 
     UniValue rv(UniValue::VOBJ);
     rv.pushKV("type", "bip9");
     rv.pushKV("bip9", bip9);
     if (ThresholdState::ACTIVE == thresholdState) {
         rv.pushKV("height", since_height);
     }
     rv.pushKV("active", ThresholdState::ACTIVE == thresholdState);
 
     softforks.pushKV(VersionBitsDeploymentInfo[id].name, rv);
 }
 
 RPCHelpMan getblockchaininfo() {
     return RPCHelpMan{
         "getblockchaininfo",
         "Returns an object containing various state info regarding blockchain "
         "processing.\n",
         {},
         RPCResult{
             RPCResult::Type::OBJ,
             "",
             "",
             {
                 {RPCResult::Type::STR, "chain",
                  "current network name (main, test, regtest)"},
                 {RPCResult::Type::NUM, "blocks",
                  "the height of the most-work fully-validated chain. The "
                  "genesis block has height 0"},
                 {RPCResult::Type::NUM, "headers",
                  "the current number of headers we have validated"},
                 {RPCResult::Type::STR, "bestblockhash",
                  "the hash of the currently best block"},
                 {RPCResult::Type::NUM, "difficulty", "the current difficulty"},
                 {RPCResult::Type::NUM, "mediantime",
                  "median time for the current best block"},
                 {RPCResult::Type::NUM, "verificationprogress",
                  "estimate of verification progress [0..1]"},
                 {RPCResult::Type::BOOL, "initialblockdownload",
                  "(debug information) estimate of whether this node is in "
                  "Initial Block Download mode"},
                 {RPCResult::Type::STR_HEX, "chainwork",
                  "total amount of work in active chain, in hexadecimal"},
                 {RPCResult::Type::NUM, "size_on_disk",
                  "the estimated size of the block and undo files on disk"},
                 {RPCResult::Type::BOOL, "pruned",
                  "if the blocks are subject to pruning"},
                 {RPCResult::Type::NUM, "pruneheight",
                  "lowest-height complete block stored (only present if pruning "
                  "is enabled)"},
                 {RPCResult::Type::BOOL, "automatic_pruning",
                  "whether automatic pruning is enabled (only present if "
                  "pruning is enabled)"},
                 {RPCResult::Type::NUM, "prune_target_size",
                  "the target size used by pruning (only present if automatic "
                  "pruning is enabled)"},
                 {RPCResult::Type::OBJ_DYN,
                  "softforks",
                  "status of softforks",
                  {
                      {RPCResult::Type::OBJ,
                       "xxxx",
                       "name of the softfork",
                       {
                           {RPCResult::Type::STR, "type",
                            "one of \"buried\", \"bip9\""},
                           {RPCResult::Type::OBJ,
                            "bip9",
                            "status of bip9 softforks (only for \"bip9\" type)",
                            {
                                {RPCResult::Type::STR, "status",
                                 "one of \"defined\", \"started\", "
                                 "\"locked_in\", \"active\", \"failed\""},
                                {RPCResult::Type::NUM, "bit",
                                 "the bit (0-28) in the block version field "
                                 "used to signal this softfork (only for "
                                 "\"started\" status)"},
                                {RPCResult::Type::NUM_TIME, "start_time",
                                 "the minimum median time past of a block at "
                                 "which the bit gains its meaning"},
                                {RPCResult::Type::NUM_TIME, "timeout",
                                 "the median time past of a block at which the "
                                 "deployment is considered failed if not yet "
                                 "locked in"},
                                {RPCResult::Type::NUM, "since",
                                 "height of the first block to which the status "
                                 "applies"},
                                {RPCResult::Type::OBJ,
                                 "statistics",
                                 "numeric statistics about BIP9 signalling for "
                                 "a softfork",
                                 {
                                     {RPCResult::Type::NUM, "period",
                                      "the length in blocks of the BIP9 "
                                      "signalling period"},
                                     {RPCResult::Type::NUM, "threshold",
                                      "the number of blocks with the version "
                                      "bit set required to activate the "
                                      "feature"},
                                     {RPCResult::Type::NUM, "elapsed",
                                      "the number of blocks elapsed since the "
                                      "beginning of the current period"},
                                     {RPCResult::Type::NUM, "count",
                                      "the number of blocks with the version "
                                      "bit set in the current period"},
                                     {RPCResult::Type::BOOL, "possible",
                                      "returns false if there are not enough "
                                      "blocks left in this period to pass "
                                      "activation threshold"},
                                 }},
                            }},
                           {RPCResult::Type::NUM, "height",
                            "height of the first block which the rules are or "
                            "will be enforced (only for \"buried\" type, or "
                            "\"bip9\" type with \"active\" status)"},
                           {RPCResult::Type::BOOL, "active",
                            "true if the rules are enforced for the mempool and "
                            "the next block"},
                       }},
                  }},
                 {RPCResult::Type::STR, "warnings",
                  "any network and blockchain warnings"},
             }},
         RPCExamples{HelpExampleCli("getblockchaininfo", "") +
                     HelpExampleRpc("getblockchaininfo", "")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             LOCK(cs_main);
 
             const CChainParams &chainparams = config.GetChainParams();
 
             const CBlockIndex *tip = ::ChainActive().Tip();
             UniValue obj(UniValue::VOBJ);
             obj.pushKV("chain", chainparams.NetworkIDString());
             obj.pushKV("blocks", int(::ChainActive().Height()));
             obj.pushKV("headers",
                        pindexBestHeader ? pindexBestHeader->nHeight : -1);
             obj.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
             obj.pushKV("difficulty", double(GetDifficulty(tip)));
             obj.pushKV("mediantime", int64_t(tip->GetMedianTimePast()));
             obj.pushKV("verificationprogress",
                        GuessVerificationProgress(Params().TxData(), tip));
             obj.pushKV("initialblockdownload",
                        ::ChainstateActive().IsInitialBlockDownload());
             obj.pushKV("chainwork", tip->nChainWork.GetHex());
             obj.pushKV("size_on_disk", CalculateCurrentUsage());
             obj.pushKV("pruned", fPruneMode);
 
             if (fPruneMode) {
                 const CBlockIndex *block = tip;
                 CHECK_NONFATAL(block);
                 while (block->pprev && (block->pprev->nStatus.hasData())) {
                     block = block->pprev;
                 }
 
                 obj.pushKV("pruneheight", block->nHeight);
 
                 // if 0, execution bypasses the whole if block.
                 bool automatic_pruning = (gArgs.GetArg("-prune", 0) != 1);
                 obj.pushKV("automatic_pruning", automatic_pruning);
                 if (automatic_pruning) {
                     obj.pushKV("prune_target_size", nPruneTarget);
                 }
             }
 
             UniValue softforks(UniValue::VOBJ);
             for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS;
                  i++) {
                 BIP9SoftForkDescPushBack(softforks, chainparams.GetConsensus(),
                                          Consensus::DeploymentPos(i));
             }
             obj.pushKV("softforks", softforks);
 
             obj.pushKV("warnings", GetWarnings(false).original);
             return obj;
         },
     };
 }
 
 /** Comparison function for sorting the getchaintips heads.  */
 struct CompareBlocksByHeight {
     bool operator()(const CBlockIndex *a, const CBlockIndex *b) const {
         // Make sure that unequal blocks with the same height do not compare
         // equal. Use the pointers themselves to make a distinction.
         if (a->nHeight != b->nHeight) {
             return (a->nHeight > b->nHeight);
         }
 
         return a < b;
     }
 };
 
 static RPCHelpMan getchaintips() {
     return RPCHelpMan{
         "getchaintips",
         "Return information about all known tips in the block tree, including "
         "the main chain as well as orphaned branches.\n",
         {},
         RPCResult{
             RPCResult::Type::ARR,
             "",
             "",
             {{RPCResult::Type::OBJ,
               "",
               "",
               {
                   {RPCResult::Type::NUM, "height", "height of the chain tip"},
                   {RPCResult::Type::STR_HEX, "hash", "block hash of the tip"},
                   {RPCResult::Type::NUM, "branchlen",
                    "zero for main chain, otherwise length of branch connecting "
                    "the tip to the main chain"},
                   {RPCResult::Type::STR, "status",
                    "status of the chain, \"active\" for the main chain\n"
                    "Possible values for status:\n"
                    "1.  \"invalid\"               This branch contains at "
                    "least one invalid block\n"
                    "2.  \"parked\"                This branch contains at "
                    "least one parked block\n"
                    "3.  \"headers-only\"          Not all blocks for this "
                    "branch are available, but the headers are valid\n"
                    "4.  \"valid-headers\"         All blocks are available for "
                    "this branch, but they were never fully validated\n"
                    "5.  \"valid-fork\"            This branch is not part of "
                    "the active chain, but is fully validated\n"
                    "6.  \"active\"                This is the tip of the "
                    "active main chain, which is certainly valid"},
               }}}},
         RPCExamples{HelpExampleCli("getchaintips", "") +
                     HelpExampleRpc("getchaintips", "")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             ChainstateManager &chainman = EnsureChainman(request.context);
             LOCK(cs_main);
 
             /**
              * Idea: The set of chain tips is the active chain tip, plus orphan
              * blocks which do not have another orphan building off of them.
              * Algorithm:
              *  - Make one pass through BlockIndex(), picking out the orphan
              * blocks, and also storing a set of the orphan block's pprev
              * pointers.
              *  - Iterate through the orphan blocks. If the block isn't pointed
              * to by another orphan, it is a chain tip.
              *  - Add the active chain tip
              */
             std::set<const CBlockIndex *, CompareBlocksByHeight> setTips;
             std::set<const CBlockIndex *> setOrphans;
             std::set<const CBlockIndex *> setPrevs;
 
             for (const std::pair<const BlockHash, CBlockIndex *> &item :
                  chainman.BlockIndex()) {
                 if (!chainman.ActiveChain().Contains(item.second)) {
                     setOrphans.insert(item.second);
                     setPrevs.insert(item.second->pprev);
                 }
             }
 
             for (std::set<const CBlockIndex *>::iterator it =
                      setOrphans.begin();
                  it != setOrphans.end(); ++it) {
                 if (setPrevs.erase(*it) == 0) {
                     setTips.insert(*it);
                 }
             }
 
             // Always report the currently active tip.
             setTips.insert(chainman.ActiveChain().Tip());
 
             /* Construct the output array.  */
             UniValue res(UniValue::VARR);
             for (const CBlockIndex *block : setTips) {
                 UniValue obj(UniValue::VOBJ);
                 obj.pushKV("height", block->nHeight);
                 obj.pushKV("hash", block->phashBlock->GetHex());
 
                 const int branchLen =
                     block->nHeight -
                     chainman.ActiveChain().FindFork(block)->nHeight;
                 obj.pushKV("branchlen", branchLen);
 
                 std::string status;
                 if (chainman.ActiveChain().Contains(block)) {
                     // This block is part of the currently active chain.
                     status = "active";
                 } else if (block->nStatus.isInvalid()) {
                     // This block or one of its ancestors is invalid.
                     status = "invalid";
                 } else if (block->nStatus.isOnParkedChain()) {
                     // This block or one of its ancestors is parked.
                     status = "parked";
                 } else if (!block->HaveTxsDownloaded()) {
                     // This block cannot be connected because full block data
                     // for it or one of its parents is missing.
                     status = "headers-only";
                 } else if (block->IsValid(BlockValidity::SCRIPTS)) {
                     // This block is fully validated, but no longer part of the
                     // active chain. It was probably the active block once, but
                     // was reorganized.
                     status = "valid-fork";
                 } else if (block->IsValid(BlockValidity::TREE)) {
                     // The headers for this block are valid, but it has not been
                     // validated. It was probably never part of the most-work
                     // chain.
                     status = "valid-headers";
                 } else {
                     // No clue.
                     status = "unknown";
                 }
                 obj.pushKV("status", status);
 
                 res.push_back(obj);
             }
 
             return res;
         },
     };
 }
 
 UniValue MempoolInfoToJSON(const CTxMemPool &pool) {
     // Make sure this call is atomic in the pool.
     LOCK(pool.cs);
     UniValue ret(UniValue::VOBJ);
     ret.pushKV("loaded", pool.IsLoaded());
     ret.pushKV("size", (int64_t)pool.size());
     ret.pushKV("bytes", (int64_t)pool.GetTotalTxSize());
     ret.pushKV("usage", (int64_t)pool.DynamicMemoryUsage());
     size_t maxmempool =
         gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
     ret.pushKV("maxmempool", (int64_t)maxmempool);
     ret.pushKV(
         "mempoolminfee",
         std::max(pool.GetMinFee(maxmempool), ::minRelayTxFee).GetFeePerK());
     ret.pushKV("minrelaytxfee", ::minRelayTxFee.GetFeePerK());
     ret.pushKV("unbroadcastcount", uint64_t{pool.GetUnbroadcastTxs().size()});
     return ret;
 }
 
 static RPCHelpMan getmempoolinfo() {
     return RPCHelpMan{
         "getmempoolinfo",
         "Returns details on the active state of the TX memory pool.\n",
         {},
         RPCResult{
             RPCResult::Type::OBJ,
             "",
             "",
             {
                 {RPCResult::Type::BOOL, "loaded",
                  "True if the mempool is fully loaded"},
                 {RPCResult::Type::NUM, "size", "Current tx count"},
                 {RPCResult::Type::NUM, "bytes", "Sum of all transaction sizes"},
                 {RPCResult::Type::NUM, "usage",
                  "Total memory usage for the mempool"},
                 {RPCResult::Type::NUM, "maxmempool",
                  "Maximum memory usage for the mempool"},
                 {RPCResult::Type::STR_AMOUNT, "mempoolminfee",
                  "Minimum fee rate in " + Currency::get().ticker +
                      "/kB for tx to be accepted. Is the maximum of "
                      "minrelaytxfee and minimum mempool fee"},
                 {RPCResult::Type::STR_AMOUNT, "minrelaytxfee",
                  "Current minimum relay fee for transactions"},
                 {RPCResult::Type::NUM, "unbroadcastcount",
                  "Current number of transactions that haven't passed initial "
                  "broadcast yet"},
             }},
         RPCExamples{HelpExampleCli("getmempoolinfo", "") +
                     HelpExampleRpc("getmempoolinfo", "")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             return MempoolInfoToJSON(EnsureMemPool(request.context));
         },
     };
 }
 
 static RPCHelpMan preciousblock() {
     return RPCHelpMan{
         "preciousblock",
         "Treats a block as if it were received before others with the same "
         "work.\n"
         "\nA later preciousblock call can override the effect of an earlier "
         "one.\n"
         "\nThe effects of preciousblock are not retained across restarts.\n",
         {
             {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO,
              "the hash of the block to mark as precious"},
         },
         RPCResult{RPCResult::Type::NONE, "", ""},
         RPCExamples{HelpExampleCli("preciousblock", "\"blockhash\"") +
                     HelpExampleRpc("preciousblock", "\"blockhash\"")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             BlockHash hash(ParseHashV(request.params[0], "blockhash"));
             CBlockIndex *pblockindex;
 
             {
                 LOCK(cs_main);
                 pblockindex = LookupBlockIndex(hash);
                 if (!pblockindex) {
                     throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
                                        "Block not found");
                 }
             }
 
             BlockValidationState state;
             PreciousBlock(config, state, pblockindex);
 
             if (!state.IsValid()) {
                 throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
             }
 
             return NullUniValue;
         },
     };
 }
 
 RPCHelpMan finalizeblock() {
     return RPCHelpMan{
         "finalizeblock",
         "Treats a block as final. It cannot be reorged. Any chain\n"
         "that does not contain this block is invalid. Used on a less\n"
         "work chain, it can effectively PUT YOU OUT OF CONSENSUS.\n"
         "USE WITH CAUTION!\n",
         {
             {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO,
              "the hash of the block to mark as invalid"},
         },
         RPCResult{RPCResult::Type::NONE, "", ""},
         RPCExamples{HelpExampleCli("finalizeblock", "\"blockhash\"") +
                     HelpExampleRpc("finalizeblock", "\"blockhash\"")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             std::string strHash = request.params[0].get_str();
             BlockHash hash(uint256S(strHash));
             BlockValidationState state;
 
             CBlockIndex *pblockindex = nullptr;
             {
                 LOCK(cs_main);
                 pblockindex = LookupBlockIndex(hash);
                 if (!pblockindex) {
                     throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
                                        "Block not found");
                 }
             } // end of locked cs_main scope
 
             ::ChainstateActive().FinalizeBlock(config, state, pblockindex);
 
             if (state.IsValid()) {
                 ActivateBestChain(config, state);
             }
 
             if (!state.IsValid()) {
                 throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
             }
 
             return NullUniValue;
         },
     };
 }
 
 static RPCHelpMan invalidateblock() {
     return RPCHelpMan{
         "invalidateblock",
         "Permanently marks a block as invalid, as if it violated a consensus "
         "rule.\n",
         {
             {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO,
              "the hash of the block to mark as invalid"},
         },
         RPCResult{RPCResult::Type::NONE, "", ""},
         RPCExamples{HelpExampleCli("invalidateblock", "\"blockhash\"") +
                     HelpExampleRpc("invalidateblock", "\"blockhash\"")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             const BlockHash hash(ParseHashV(request.params[0], "blockhash"));
             BlockValidationState state;
 
             CBlockIndex *pblockindex;
             {
                 LOCK(cs_main);
                 pblockindex = LookupBlockIndex(hash);
                 if (!pblockindex) {
                     throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
                                        "Block not found");
                 }
             }
             ::ChainstateActive().InvalidateBlock(config, state, pblockindex);
 
             if (state.IsValid()) {
                 ActivateBestChain(config, state);
             }
 
             if (!state.IsValid()) {
                 throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
             }
 
             return NullUniValue;
         },
     };
 }
 
 RPCHelpMan parkblock() {
     return RPCHelpMan{
         "parkblock",
         "Marks a block as parked.\n",
         {
             {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO,
              "the hash of the block to park"},
         },
         RPCResult{RPCResult::Type::NONE, "", ""},
         RPCExamples{HelpExampleCli("parkblock", "\"blockhash\"") +
                     HelpExampleRpc("parkblock", "\"blockhash\"")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             const std::string strHash = request.params[0].get_str();
             const BlockHash hash(uint256S(strHash));
             BlockValidationState state;
 
             CBlockIndex *pblockindex = nullptr;
             {
                 LOCK(cs_main);
                 pblockindex = LookupBlockIndex(hash);
                 if (!pblockindex) {
                     throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
                                        "Block not found");
                 }
             }
             ::ChainstateActive().ParkBlock(config, state, pblockindex);
 
             if (state.IsValid()) {
                 ActivateBestChain(config, state);
             }
 
             if (!state.IsValid()) {
                 throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
             }
 
             return NullUniValue;
         },
     };
 }
 
 static RPCHelpMan reconsiderblock() {
     return RPCHelpMan{
         "reconsiderblock",
         "Removes invalidity status of a block, its ancestors and its"
         "descendants, reconsider them for activation.\n"
         "This can be used to undo the effects of invalidateblock.\n",
         {
             {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO,
              "the hash of the block to reconsider"},
         },
         RPCResult{RPCResult::Type::NONE, "", ""},
         RPCExamples{HelpExampleCli("reconsiderblock", "\"blockhash\"") +
                     HelpExampleRpc("reconsiderblock", "\"blockhash\"")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             const BlockHash hash(ParseHashV(request.params[0], "blockhash"));
 
             {
                 LOCK(cs_main);
                 CBlockIndex *pblockindex = LookupBlockIndex(hash);
                 if (!pblockindex) {
                     throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
                                        "Block not found");
                 }
 
                 ResetBlockFailureFlags(pblockindex);
             }
 
             BlockValidationState state;
             ActivateBestChain(config, state);
 
             if (!state.IsValid()) {
                 throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
             }
 
             return NullUniValue;
         },
     };
 }
 
 RPCHelpMan unparkblock() {
     return RPCHelpMan{
         "unparkblock",
         "Removes parked status of a block and its descendants, reconsider "
         "them for activation.\n"
         "This can be used to undo the effects of parkblock.\n",
         {
             {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO,
              "the hash of the block to unpark"},
         },
         RPCResult{RPCResult::Type::NONE, "", ""},
         RPCExamples{HelpExampleCli("unparkblock", "\"blockhash\"") +
                     HelpExampleRpc("unparkblock", "\"blockhash\"")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             const std::string strHash = request.params[0].get_str();
             const BlockHash hash(uint256S(strHash));
 
             {
                 LOCK(cs_main);
 
                 CBlockIndex *pblockindex = LookupBlockIndex(hash);
                 if (!pblockindex) {
                     throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
                                        "Block not found");
                 }
 
                 UnparkBlockAndChildren(pblockindex);
             }
 
             BlockValidationState state;
             ActivateBestChain(config, state);
 
             if (!state.IsValid()) {
                 throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
             }
 
             return NullUniValue;
         },
     };
 }
 
 static RPCHelpMan getchaintxstats() {
     return RPCHelpMan{
         "getchaintxstats",
         "Compute statistics about the total number and rate of transactions "
         "in the chain.\n",
         {
             {"nblocks", RPCArg::Type::NUM, /* default */ "one month",
              "Size of the window in number of blocks"},
             {"blockhash", RPCArg::Type::STR_HEX, /* default */ "chain tip",
              "The hash of the block that ends the window."},
         },
         RPCResult{RPCResult::Type::OBJ,
                   "",
                   "",
                   {
                       {RPCResult::Type::NUM_TIME, "time",
                        "The timestamp for the final block in the window, "
                        "expressed in " +
                            UNIX_EPOCH_TIME},
                       {RPCResult::Type::NUM, "txcount",
                        "The total number of transactions in the chain up to "
                        "that point"},
                       {RPCResult::Type::STR_HEX, "window_final_block_hash",
                        "The hash of the final block in the window"},
                       {RPCResult::Type::NUM, "window_final_block_height",
                        "The height of the final block in the window."},
                       {RPCResult::Type::NUM, "window_block_count",
                        "Size of the window in number of blocks"},
                       {RPCResult::Type::NUM, "window_tx_count",
                        "The number of transactions in the window. Only "
                        "returned if \"window_block_count\" is > 0"},
                       {RPCResult::Type::NUM, "window_interval",
                        "The elapsed time in the window in seconds. Only "
                        "returned if \"window_block_count\" is > 0"},
                       {RPCResult::Type::NUM, "txrate",
                        "The average rate of transactions per second in the "
                        "window. Only returned if \"window_interval\" is > 0"},
                   }},
         RPCExamples{HelpExampleCli("getchaintxstats", "") +
                     HelpExampleRpc("getchaintxstats", "2016")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             const CBlockIndex *pindex;
 
             // By default: 1 month
             int blockcount =
                 30 * 24 * 60 * 60 /
                 config.GetChainParams().GetConsensus().nPowTargetSpacing;
 
             if (request.params[1].isNull()) {
                 LOCK(cs_main);
                 pindex = ::ChainActive().Tip();
             } else {
                 BlockHash hash(ParseHashV(request.params[1], "blockhash"));
                 LOCK(cs_main);
                 pindex = LookupBlockIndex(hash);
                 if (!pindex) {
                     throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
                                        "Block not found");
                 }
                 if (!::ChainActive().Contains(pindex)) {
                     throw JSONRPCError(RPC_INVALID_PARAMETER,
                                        "Block is not in main chain");
                 }
             }
 
             CHECK_NONFATAL(pindex != nullptr);
 
             if (request.params[0].isNull()) {
                 blockcount =
                     std::max(0, std::min(blockcount, pindex->nHeight - 1));
             } else {
                 blockcount = request.params[0].get_int();
 
                 if (blockcount < 0 ||
                     (blockcount > 0 && blockcount >= pindex->nHeight)) {
                     throw JSONRPCError(RPC_INVALID_PARAMETER,
                                        "Invalid block count: "
                                        "should be between 0 and "
                                        "the block's height - 1");
                 }
             }
 
             const CBlockIndex *pindexPast =
                 pindex->GetAncestor(pindex->nHeight - blockcount);
             int nTimeDiff =
                 pindex->GetMedianTimePast() - pindexPast->GetMedianTimePast();
             int nTxDiff =
                 pindex->GetChainTxCount() - pindexPast->GetChainTxCount();
 
             UniValue ret(UniValue::VOBJ);
             ret.pushKV("time", pindex->GetBlockTime());
             ret.pushKV("txcount", pindex->GetChainTxCount());
             ret.pushKV("window_final_block_hash",
                        pindex->GetBlockHash().GetHex());
             ret.pushKV("window_final_block_height", pindex->nHeight);
             ret.pushKV("window_block_count", blockcount);
             if (blockcount > 0) {
                 ret.pushKV("window_tx_count", nTxDiff);
                 ret.pushKV("window_interval", nTimeDiff);
                 if (nTimeDiff > 0) {
                     ret.pushKV("txrate", double(nTxDiff) / nTimeDiff);
                 }
             }
 
             return ret;
         },
     };
 }
 
 template <typename T>
 static T CalculateTruncatedMedian(std::vector<T> &scores) {
     size_t size = scores.size();
     if (size == 0) {
         return T();
     }
 
     std::sort(scores.begin(), scores.end());
     if (size % 2 == 0) {
         return (scores[size / 2 - 1] + scores[size / 2]) / 2;
     } else {
         return scores[size / 2];
     }
 }
 
 template <typename T> static inline bool SetHasKeys(const std::set<T> &set) {
     return false;
 }
 template <typename T, typename Tk, typename... Args>
 static inline bool SetHasKeys(const std::set<T> &set, const Tk &key,
-                              const Args &... args) {
+                              const Args &...args) {
     return (set.count(key) != 0) || SetHasKeys(set, args...);
 }
 
 // outpoint (needed for the utxo index) + nHeight + fCoinBase
 static constexpr size_t PER_UTXO_OVERHEAD =
     sizeof(COutPoint) + sizeof(uint32_t) + sizeof(bool);
 
 static RPCHelpMan getblockstats() {
     const auto &ticker = Currency::get().ticker;
     return RPCHelpMan{
         "getblockstats",
         "Compute per block statistics for a given window. All amounts are "
         "in " +
             ticker +
             ".\n"
             "It won't work for some heights with pruning.\n",
         {
             {"hash_or_height",
              RPCArg::Type::NUM,
              RPCArg::Optional::NO,
              "The block hash or height of the target block",
              "",
              {"", "string or numeric"}},
             {"stats",
              RPCArg::Type::ARR,
              /* default */ "all values",
              "Values to plot (see result below)",
              {
                  {"height", RPCArg::Type::STR, RPCArg::Optional::OMITTED,
                   "Selected statistic"},
                  {"time", RPCArg::Type::STR, RPCArg::Optional::OMITTED,
                   "Selected statistic"},
              },
              "stats"},
         },
         RPCResult{
             RPCResult::Type::OBJ,
             "",
             "",
             {
                 {RPCResult::Type::NUM, "avgfee", "Average fee in the block"},
                 {RPCResult::Type::NUM, "avgfeerate",
                  "Average feerate (in satoshis per virtual byte)"},
                 {RPCResult::Type::NUM, "avgtxsize", "Average transaction size"},
                 {RPCResult::Type::STR_HEX, "blockhash",
                  "The block hash (to check for potential reorgs)"},
                 {RPCResult::Type::NUM, "height", "The height of the block"},
                 {RPCResult::Type::NUM, "ins",
                  "The number of inputs (excluding coinbase)"},
                 {RPCResult::Type::NUM, "maxfee", "Maximum fee in the block"},
                 {RPCResult::Type::NUM, "maxfeerate",
                  "Maximum feerate (in satoshis per virtual byte)"},
                 {RPCResult::Type::NUM, "maxtxsize", "Maximum transaction size"},
                 {RPCResult::Type::NUM, "medianfee",
                  "Truncated median fee in the block"},
                 {RPCResult::Type::NUM, "medianfeerate",
                  "Truncated median feerate (in " + ticker + " per byte)"},
                 {RPCResult::Type::NUM, "mediantime",
                  "The block median time past"},
                 {RPCResult::Type::NUM, "mediantxsize",
                  "Truncated median transaction size"},
                 {RPCResult::Type::NUM, "minfee", "Minimum fee in the block"},
                 {RPCResult::Type::NUM, "minfeerate",
                  "Minimum feerate (in satoshis per virtual byte)"},
                 {RPCResult::Type::NUM, "mintxsize", "Minimum transaction size"},
                 {RPCResult::Type::NUM, "outs", "The number of outputs"},
                 {RPCResult::Type::NUM, "subsidy", "The block subsidy"},
                 {RPCResult::Type::NUM, "time", "The block time"},
                 {RPCResult::Type::NUM, "total_out",
                  "Total amount in all outputs (excluding coinbase and thus "
                  "reward [ie subsidy + totalfee])"},
                 {RPCResult::Type::NUM, "total_size",
                  "Total size of all non-coinbase transactions"},
                 {RPCResult::Type::NUM, "totalfee", "The fee total"},
                 {RPCResult::Type::NUM, "txs",
                  "The number of transactions (including coinbase)"},
                 {RPCResult::Type::NUM, "utxo_increase",
                  "The increase/decrease in the number of unspent outputs"},
                 {RPCResult::Type::NUM, "utxo_size_inc",
                  "The increase/decrease in size for the utxo index (not "
                  "discounting op_return and similar)"},
             }},
         RPCExamples{
             HelpExampleCli(
                 "getblockstats",
                 R"('"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"' '["minfeerate","avgfeerate"]')") +
             HelpExampleCli("getblockstats",
                            R"(1000 '["minfeerate","avgfeerate"]')") +
             HelpExampleRpc(
                 "getblockstats",
                 R"("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", ["minfeerate","avgfeerate"])") +
             HelpExampleRpc("getblockstats",
                            R"(1000, ["minfeerate","avgfeerate"])")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             LOCK(cs_main);
 
             CBlockIndex *pindex;
             if (request.params[0].isNum()) {
                 const int height = request.params[0].get_int();
                 const int current_tip = ::ChainActive().Height();
                 if (height < 0) {
                     throw JSONRPCError(
                         RPC_INVALID_PARAMETER,
                         strprintf("Target block height %d is negative",
                                   height));
                 }
                 if (height > current_tip) {
                     throw JSONRPCError(
                         RPC_INVALID_PARAMETER,
                         strprintf("Target block height %d after current tip %d",
                                   height, current_tip));
                 }
 
                 pindex = ::ChainActive()[height];
             } else {
                 const BlockHash hash(
                     ParseHashV(request.params[0], "hash_or_height"));
                 pindex = LookupBlockIndex(hash);
                 if (!pindex) {
                     throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
                                        "Block not found");
                 }
                 if (!::ChainActive().Contains(pindex)) {
                     throw JSONRPCError(RPC_INVALID_PARAMETER,
                                        strprintf("Block is not in chain %s",
                                                  Params().NetworkIDString()));
                 }
             }
 
             CHECK_NONFATAL(pindex != nullptr);
 
             std::set<std::string> stats;
             if (!request.params[1].isNull()) {
                 const UniValue stats_univalue = request.params[1].get_array();
                 for (unsigned int i = 0; i < stats_univalue.size(); i++) {
                     const std::string stat = stats_univalue[i].get_str();
                     stats.insert(stat);
                 }
             }
 
             const CBlock block = GetBlockChecked(config, pindex);
             const CBlockUndo blockUndo = GetUndoChecked(pindex);
 
             // Calculate everything if nothing selected (default)
             const bool do_all = stats.size() == 0;
             const bool do_mediantxsize =
                 do_all || stats.count("mediantxsize") != 0;
             const bool do_medianfee = do_all || stats.count("medianfee") != 0;
             const bool do_medianfeerate =
                 do_all || stats.count("medianfeerate") != 0;
             const bool loop_inputs =
                 do_all || do_medianfee || do_medianfeerate ||
                 SetHasKeys(stats, "utxo_size_inc", "totalfee", "avgfee",
                            "avgfeerate", "minfee", "maxfee", "minfeerate",
                            "maxfeerate");
             const bool loop_outputs =
                 do_all || loop_inputs || stats.count("total_out");
             const bool do_calculate_size =
                 do_mediantxsize || loop_inputs ||
                 SetHasKeys(stats, "total_size", "avgtxsize", "mintxsize",
                            "maxtxsize");
 
             const int64_t blockMaxSize = config.GetMaxBlockSize();
             Amount maxfee = Amount::zero();
             Amount maxfeerate = Amount::zero();
             Amount minfee = MAX_MONEY;
             Amount minfeerate = MAX_MONEY;
             Amount total_out = Amount::zero();
             Amount totalfee = Amount::zero();
             int64_t inputs = 0;
             int64_t maxtxsize = 0;
             int64_t mintxsize = blockMaxSize;
             int64_t outputs = 0;
             int64_t total_size = 0;
             int64_t utxo_size_inc = 0;
             std::vector<Amount> fee_array;
             std::vector<Amount> feerate_array;
             std::vector<int64_t> txsize_array;
 
             for (size_t i = 0; i < block.vtx.size(); ++i) {
                 const auto &tx = block.vtx.at(i);
                 outputs += tx->vout.size();
                 Amount tx_total_out = Amount::zero();
                 if (loop_outputs) {
                     for (const CTxOut &out : tx->vout) {
                         tx_total_out += out.nValue;
                         utxo_size_inc +=
                             GetSerializeSize(out, PROTOCOL_VERSION) +
                             PER_UTXO_OVERHEAD;
                     }
                 }
 
                 if (tx->IsCoinBase()) {
                     continue;
                 }
 
                 // Don't count coinbase's fake input
                 inputs += tx->vin.size();
                 // Don't count coinbase reward
                 total_out += tx_total_out;
 
                 int64_t tx_size = 0;
                 if (do_calculate_size) {
                     tx_size = tx->GetTotalSize();
                     if (do_mediantxsize) {
                         txsize_array.push_back(tx_size);
                     }
                     maxtxsize = std::max(maxtxsize, tx_size);
                     mintxsize = std::min(mintxsize, tx_size);
                     total_size += tx_size;
                 }
 
                 if (loop_inputs) {
                     Amount tx_total_in = Amount::zero();
                     const auto &txundo = blockUndo.vtxundo.at(i - 1);
                     for (const Coin &coin : txundo.vprevout) {
                         const CTxOut &prevoutput = coin.GetTxOut();
 
                         tx_total_in += prevoutput.nValue;
                         utxo_size_inc -=
                             GetSerializeSize(prevoutput, PROTOCOL_VERSION) +
                             PER_UTXO_OVERHEAD;
                     }
 
                     Amount txfee = tx_total_in - tx_total_out;
                     CHECK_NONFATAL(MoneyRange(txfee));
                     if (do_medianfee) {
                         fee_array.push_back(txfee);
                     }
                     maxfee = std::max(maxfee, txfee);
                     minfee = std::min(minfee, txfee);
                     totalfee += txfee;
 
                     Amount feerate = txfee / tx_size;
                     if (do_medianfeerate) {
                         feerate_array.push_back(feerate);
                     }
                     maxfeerate = std::max(maxfeerate, feerate);
                     minfeerate = std::min(minfeerate, feerate);
                 }
             }
 
             UniValue ret_all(UniValue::VOBJ);
             ret_all.pushKV("avgfee",
                            block.vtx.size() > 1
                                ? (totalfee / int((block.vtx.size() - 1)))
                                : Amount::zero());
             ret_all.pushKV("avgfeerate", total_size > 0
                                              ? (totalfee / total_size)
                                              : Amount::zero());
             ret_all.pushKV("avgtxsize",
                            (block.vtx.size() > 1)
                                ? total_size / (block.vtx.size() - 1)
                                : 0);
             ret_all.pushKV("blockhash", pindex->GetBlockHash().GetHex());
             ret_all.pushKV("height", (int64_t)pindex->nHeight);
             ret_all.pushKV("ins", inputs);
             ret_all.pushKV("maxfee", maxfee);
             ret_all.pushKV("maxfeerate", maxfeerate);
             ret_all.pushKV("maxtxsize", maxtxsize);
             ret_all.pushKV("medianfee", CalculateTruncatedMedian(fee_array));
             ret_all.pushKV("medianfeerate",
                            CalculateTruncatedMedian(feerate_array));
             ret_all.pushKV("mediantime", pindex->GetMedianTimePast());
             ret_all.pushKV("mediantxsize",
                            CalculateTruncatedMedian(txsize_array));
             ret_all.pushKV("minfee",
                            minfee == MAX_MONEY ? Amount::zero() : minfee);
             ret_all.pushKV("minfeerate", minfeerate == MAX_MONEY
                                              ? Amount::zero()
                                              : minfeerate);
             ret_all.pushKV("mintxsize",
                            mintxsize == blockMaxSize ? 0 : mintxsize);
             ret_all.pushKV("outs", outputs);
             ret_all.pushKV("subsidy", GetBlockSubsidy(pindex->nHeight,
                                                       Params().GetConsensus()));
             ret_all.pushKV("time", pindex->GetBlockTime());
             ret_all.pushKV("total_out", total_out);
             ret_all.pushKV("total_size", total_size);
             ret_all.pushKV("totalfee", totalfee);
             ret_all.pushKV("txs", (int64_t)block.vtx.size());
             ret_all.pushKV("utxo_increase", outputs - inputs);
             ret_all.pushKV("utxo_size_inc", utxo_size_inc);
 
             if (do_all) {
                 return ret_all;
             }
 
             UniValue ret(UniValue::VOBJ);
             for (const std::string &stat : stats) {
                 const UniValue &value = ret_all[stat];
                 if (value.isNull()) {
                     throw JSONRPCError(
                         RPC_INVALID_PARAMETER,
                         strprintf("Invalid selected statistic %s", stat));
                 }
                 ret.pushKV(stat, value);
             }
             return ret;
         },
     };
 }
 
 static RPCHelpMan savemempool() {
     return RPCHelpMan{
         "savemempool",
         "Dumps the mempool to disk. It will fail until the previous dump is "
         "fully loaded.\n",
         {},
         RPCResult{RPCResult::Type::NONE, "", ""},
         RPCExamples{HelpExampleCli("savemempool", "") +
                     HelpExampleRpc("savemempool", "")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             const CTxMemPool &mempool = EnsureMemPool(request.context);
 
             if (!mempool.IsLoaded()) {
                 throw JSONRPCError(RPC_MISC_ERROR,
                                    "The mempool was not loaded yet");
             }
 
             if (!DumpMempool(mempool)) {
                 throw JSONRPCError(RPC_MISC_ERROR,
                                    "Unable to dump mempool to disk");
             }
 
             return NullUniValue;
         },
     };
 }
 
 namespace {
 //! Search for a given set of pubkey scripts
 static bool FindScriptPubKey(std::atomic<int> &scan_progress,
                              const std::atomic<bool> &should_abort,
                              int64_t &count, CCoinsViewCursor *cursor,
                              const std::set<CScript> &needles,
                              std::map<COutPoint, Coin> &out_results,
                              std::function<void()> &interruption_point) {
     scan_progress = 0;
     count = 0;
     while (cursor->Valid()) {
         COutPoint key;
         Coin coin;
         if (!cursor->GetKey(key) || !cursor->GetValue(coin)) {
             return false;
         }
         if (++count % 8192 == 0) {
             interruption_point();
             if (should_abort) {
                 // allow to abort the scan via the abort reference
                 return false;
             }
         }
         if (count % 256 == 0) {
             // update progress reference every 256 item
             const TxId &txid = key.GetTxId();
             uint32_t high = 0x100 * *txid.begin() + *(txid.begin() + 1);
             scan_progress = int(high * 100.0 / 65536.0 + 0.5);
         }
         if (needles.count(coin.GetTxOut().scriptPubKey)) {
             out_results.emplace(key, coin);
         }
         cursor->Next();
     }
     scan_progress = 100;
     return true;
 }
 } // namespace
 
 /** RAII object to prevent concurrency issue when scanning the txout set */
 static std::atomic<int> g_scan_progress;
 static std::atomic<bool> g_scan_in_progress;
 static std::atomic<bool> g_should_abort_scan;
 class CoinsViewScanReserver {
 private:
     bool m_could_reserve;
 
 public:
     explicit CoinsViewScanReserver() : m_could_reserve(false) {}
 
     bool reserve() {
         CHECK_NONFATAL(!m_could_reserve);
         if (g_scan_in_progress.exchange(true)) {
             return false;
         }
         m_could_reserve = true;
         return true;
     }
 
     ~CoinsViewScanReserver() {
         if (m_could_reserve) {
             g_scan_in_progress = false;
         }
     }
 };
 
 static RPCHelpMan scantxoutset() {
     const auto &ticker = Currency::get().ticker;
     return RPCHelpMan{
         "scantxoutset",
         "EXPERIMENTAL warning: this call may be removed or changed in future "
         "releases.\n"
         "\nScans the unspent transaction output set for entries that match "
         "certain output descriptors.\n"
         "Examples of output descriptors are:\n"
         "    addr(<address>)                      Outputs whose scriptPubKey "
         "corresponds to the specified address (does not include P2PK)\n"
         "    raw(<hex script>)                    Outputs whose scriptPubKey "
         "equals the specified hex scripts\n"
         "    combo(<pubkey>)                      P2PK and P2PKH outputs for "
         "the given pubkey\n"
         "    pkh(<pubkey>)                        P2PKH outputs for the given "
         "pubkey\n"
         "    sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for "
         "the given threshold and pubkeys\n"
         "\nIn the above, <pubkey> either refers to a fixed public key in "
         "hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
         "or more path elements separated by \"/\", and optionally ending in "
         "\"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n"
         "unhardened or hardened child keys.\n"
         "In the latter case, a range needs to be specified by below if "
         "different from 1000.\n"
         "For more information on output descriptors, see the documentation in "
         "the doc/descriptors.md file.\n",
         {
             {"action", RPCArg::Type::STR, RPCArg::Optional::NO,
              "The action to execute\n"
              "                                      \"start\" for starting a "
              "scan\n"
              "                                      \"abort\" for aborting the "
              "current scan (returns true when abort was successful)\n"
              "                                      \"status\" for "
              "progress report (in %) of the current scan"},
             {"scanobjects",
              RPCArg::Type::ARR,
              RPCArg::Optional::OMITTED,
              "Array of scan objects. Required for \"start\" action\n"
              "                                  Every scan object is either a "
              "string descriptor or an object:",
              {
                  {"descriptor", RPCArg::Type::STR, RPCArg::Optional::OMITTED,
                   "An output descriptor"},
                  {
                      "",
                      RPCArg::Type::OBJ,
                      RPCArg::Optional::OMITTED,
                      "An object with output descriptor and metadata",
                      {
                          {"desc", RPCArg::Type::STR, RPCArg::Optional::NO,
                           "An output descriptor"},
                          {"range", RPCArg::Type::RANGE, /* default */ "1000",
                           "The range of HD chain indexes to explore (either "
                           "end or [begin,end])"},
                      },
                  },
              },
              "[scanobjects,...]"},
         },
         RPCResult{
             RPCResult::Type::OBJ,
             "",
             "",
             {
                 {RPCResult::Type::BOOL, "success",
                  "Whether the scan was completed"},
                 {RPCResult::Type::NUM, "txouts",
                  "The number of unspent transaction outputs scanned"},
                 {RPCResult::Type::NUM, "height",
                  "The current block height (index)"},
                 {RPCResult::Type::STR_HEX, "bestblock",
                  "The hash of the block at the tip of the chain"},
                 {RPCResult::Type::ARR,
                  "unspents",
                  "",
                  {
                      {RPCResult::Type::OBJ,
                       "",
                       "",
                       {
                           {RPCResult::Type::STR_HEX, "txid",
                            "The transaction id"},
                           {RPCResult::Type::NUM, "vout", "The vout value"},
                           {RPCResult::Type::STR_HEX, "scriptPubKey",
                            "The script key"},
                           {RPCResult::Type::STR, "desc",
                            "A specialized descriptor for the matched "
                            "scriptPubKey"},
                           {RPCResult::Type::STR_AMOUNT, "amount",
                            "The total amount in " + ticker +
                                " of the unspent output"},
                           {RPCResult::Type::NUM, "height",
                            "Height of the unspent transaction output"},
                       }},
                  }},
                 {RPCResult::Type::STR_AMOUNT, "total_amount",
                  "The total amount of all found unspent outputs in " + ticker},
             }},
         RPCExamples{""},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR});
 
             UniValue result(UniValue::VOBJ);
             if (request.params[0].get_str() == "status") {
                 CoinsViewScanReserver reserver;
                 if (reserver.reserve()) {
                     // no scan in progress
                     return NullUniValue;
                 }
                 result.pushKV("progress", g_scan_progress.load());
                 return result;
             } else if (request.params[0].get_str() == "abort") {
                 CoinsViewScanReserver reserver;
                 if (reserver.reserve()) {
                     // reserve was possible which means no scan was running
                     return false;
                 }
                 // set the abort flag
                 g_should_abort_scan = true;
                 return true;
             } else if (request.params[0].get_str() == "start") {
                 CoinsViewScanReserver reserver;
                 if (!reserver.reserve()) {
                     throw JSONRPCError(RPC_INVALID_PARAMETER,
                                        "Scan already in progress, use action "
                                        "\"abort\" or \"status\"");
                 }
 
                 if (request.params.size() < 2) {
                     throw JSONRPCError(RPC_MISC_ERROR,
                                        "scanobjects argument is required for "
                                        "the start action");
                 }
 
                 std::set<CScript> needles;
                 std::map<CScript, std::string> descriptors;
                 Amount total_in = Amount::zero();
 
                 // loop through the scan objects
                 for (const UniValue &scanobject :
                      request.params[1].get_array().getValues()) {
                     FlatSigningProvider provider;
                     auto scripts =
                         EvalDescriptorStringOrObject(scanobject, provider);
                     for (const auto &script : scripts) {
                         std::string inferred =
                             InferDescriptor(script, provider)->ToString();
                         needles.emplace(script);
                         descriptors.emplace(std::move(script),
                                             std::move(inferred));
                     }
                 }
 
                 // Scan the unspent transaction output set for inputs
                 UniValue unspents(UniValue::VARR);
                 std::vector<CTxOut> input_txos;
                 std::map<COutPoint, Coin> coins;
                 g_should_abort_scan = false;
                 g_scan_progress = 0;
                 int64_t count = 0;
                 std::unique_ptr<CCoinsViewCursor> pcursor;
                 CBlockIndex *tip;
                 {
                     LOCK(cs_main);
                     ::ChainstateActive().ForceFlushStateToDisk();
                     pcursor = std::unique_ptr<CCoinsViewCursor>(
                         ::ChainstateActive().CoinsDB().Cursor());
                     CHECK_NONFATAL(pcursor);
                     tip = ::ChainActive().Tip();
                     CHECK_NONFATAL(tip);
                 }
                 NodeContext &node = EnsureNodeContext(request.context);
                 bool res = FindScriptPubKey(
                     g_scan_progress, g_should_abort_scan, count, pcursor.get(),
                     needles, coins, node.rpc_interruption_point);
                 result.pushKV("success", res);
                 result.pushKV("txouts", count);
                 result.pushKV("height", tip->nHeight);
                 result.pushKV("bestblock", tip->GetBlockHash().GetHex());
 
                 for (const auto &it : coins) {
                     const COutPoint &outpoint = it.first;
                     const Coin &coin = it.second;
                     const CTxOut &txo = coin.GetTxOut();
                     input_txos.push_back(txo);
                     total_in += txo.nValue;
 
                     UniValue unspent(UniValue::VOBJ);
                     unspent.pushKV("txid", outpoint.GetTxId().GetHex());
                     unspent.pushKV("vout", int32_t(outpoint.GetN()));
                     unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey));
                     unspent.pushKV("desc", descriptors[txo.scriptPubKey]);
                     unspent.pushKV("amount", txo.nValue);
                     unspent.pushKV("height", int32_t(coin.GetHeight()));
 
                     unspents.push_back(unspent);
                 }
                 result.pushKV("unspents", unspents);
                 result.pushKV("total_amount", total_in);
             } else {
                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid command");
             }
             return result;
         },
     };
 }
 
 static RPCHelpMan getblockfilter() {
     return RPCHelpMan{
         "getblockfilter",
         "Retrieve a BIP 157 content filter for a particular block.\n",
         {
             {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO,
              "The hash of the block"},
             {"filtertype", RPCArg::Type::STR, /*default*/ "basic",
              "The type name of the filter"},
         },
         RPCResult{RPCResult::Type::OBJ,
                   "",
                   "",
                   {
                       {RPCResult::Type::STR_HEX, "filter",
                        "the hex-encoded filter data"},
                       {RPCResult::Type::STR_HEX, "header",
                        "the hex-encoded filter header"},
                   }},
         RPCExamples{
             HelpExampleCli("getblockfilter",
                            "\"00000000c937983704a73af28acdec37b049d214a"
                            "dbda81d7e2a3dd146f6ed09\" \"basic\"") +
             HelpExampleRpc("getblockfilter",
                            "\"00000000c937983704a73af28acdec37b049d214adbda81d7"
                            "e2a3dd146f6ed09\", \"basic\"")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             const BlockHash block_hash(
                 ParseHashV(request.params[0], "blockhash"));
             std::string filtertype_name = "basic";
             if (!request.params[1].isNull()) {
                 filtertype_name = request.params[1].get_str();
             }
 
             BlockFilterType filtertype;
             if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
                                    "Unknown filtertype");
             }
 
             BlockFilterIndex *index = GetBlockFilterIndex(filtertype);
             if (!index) {
                 throw JSONRPCError(RPC_MISC_ERROR,
                                    "Index is not enabled for filtertype " +
                                        filtertype_name);
             }
 
             const CBlockIndex *block_index;
             bool block_was_connected;
             {
                 LOCK(cs_main);
                 block_index = LookupBlockIndex(block_hash);
                 if (!block_index) {
                     throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
                                        "Block not found");
                 }
                 block_was_connected =
                     block_index->IsValid(BlockValidity::SCRIPTS);
             }
 
             bool index_ready = index->BlockUntilSyncedToCurrentChain();
 
             BlockFilter filter;
             uint256 filter_header;
             if (!index->LookupFilter(block_index, filter) ||
                 !index->LookupFilterHeader(block_index, filter_header)) {
                 int err_code;
                 std::string errmsg = "Filter not found.";
 
                 if (!block_was_connected) {
                     err_code = RPC_INVALID_ADDRESS_OR_KEY;
                     errmsg += " Block was not connected to active chain.";
                 } else if (!index_ready) {
                     err_code = RPC_MISC_ERROR;
                     errmsg += " Block filters are still in the process of "
                               "being indexed.";
                 } else {
                     err_code = RPC_INTERNAL_ERROR;
                     errmsg += " This error is unexpected and indicates index "
                               "corruption.";
                 }
 
                 throw JSONRPCError(err_code, errmsg);
             }
 
             UniValue ret(UniValue::VOBJ);
             ret.pushKV("filter", HexStr(filter.GetEncodedFilter()));
             ret.pushKV("header", filter_header.GetHex());
             return ret;
         },
     };
 }
 
 /**
  * Serialize the UTXO set to a file for loading elsewhere.
  *
  * @see SnapshotMetadata
  */
 static RPCHelpMan dumptxoutset() {
     return RPCHelpMan{
         "dumptxoutset",
         "Write the serialized UTXO set to disk.\n",
         {
             {"path", RPCArg::Type::STR, RPCArg::Optional::NO,
              "path to the output file. If relative, will be prefixed by "
              "datadir."},
         },
         RPCResult{RPCResult::Type::OBJ,
                   "",
                   "",
                   {
                       {RPCResult::Type::NUM, "coins_written",
                        "the number of coins written in the snapshot"},
                       {RPCResult::Type::STR_HEX, "base_hash",
                        "the hash of the base of the snapshot"},
                       {RPCResult::Type::NUM, "base_height",
                        "the height of the base of the snapshot"},
                       {RPCResult::Type::STR, "path",
                        "the absolute path that the snapshot was written to"},
                   }},
         RPCExamples{HelpExampleCli("dumptxoutset", "utxo.dat")},
         [&](const RPCHelpMan &self, const Config &config,
             const JSONRPCRequest &request) -> UniValue {
             fs::path path = fs::absolute(
                 fs::u8path(request.params[0].get_str()), GetDataDir());
             // Write to a temporary path and then move into `path` on completion
             // to avoid confusion due to an interruption.
             fs::path temppath = fs::absolute(
                 fs::u8path(request.params[0].get_str() + ".incomplete"),
                 GetDataDir());
 
             if (fs::exists(path)) {
                 throw JSONRPCError(RPC_INVALID_PARAMETER,
                                    path.u8string() +
                                        " already exists. If you are sure this "
                                        "is what you want, "
                                        "move it out of the way first");
             }
 
             FILE *file{fsbridge::fopen(temppath, "wb")};
             CAutoFile afile{file, SER_DISK, CLIENT_VERSION};
             std::unique_ptr<CCoinsViewCursor> pcursor;
             CCoinsStats stats;
             CBlockIndex *tip;
             NodeContext &node = EnsureNodeContext(request.context);
 
             {
                 // We need to lock cs_main to ensure that the coinsdb isn't
                 // written to between (i) flushing coins cache to disk
                 // (coinsdb), (ii) getting stats based upon the coinsdb, and
                 // (iii) constructing a cursor to the coinsdb for use below this
                 // block.
                 //
                 // Cursors returned by leveldb iterate over snapshots, so the
                 // contents of the pcursor will not be affected by simultaneous
                 // writes during use below this block.
                 //
                 // See discussion here:
                 //   https://github.com/bitcoin/bitcoin/pull/15606#discussion_r274479369
                 //
                 LOCK(::cs_main);
 
                 ::ChainstateActive().ForceFlushStateToDisk();
 
                 if (!GetUTXOStats(&::ChainstateActive().CoinsDB(), stats,
                                   CoinStatsHashType::NONE,
                                   node.rpc_interruption_point)) {
                     throw JSONRPCError(RPC_INTERNAL_ERROR,
                                        "Unable to read UTXO set");
                 }
 
                 pcursor = std::unique_ptr<CCoinsViewCursor>(
                     ::ChainstateActive().CoinsDB().Cursor());
                 tip = LookupBlockIndex(stats.hashBlock);
                 CHECK_NONFATAL(tip);
             }
 
             SnapshotMetadata metadata{tip->GetBlockHash(), stats.coins_count,
                                       uint64_t(tip->GetChainTxCount())};
 
             afile << metadata;
 
             COutPoint key;
             Coin coin;
             unsigned int iter{0};
 
             while (pcursor->Valid()) {
                 if (iter % 5000 == 0) {
                     node.rpc_interruption_point();
                 }
                 ++iter;
                 if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
                     afile << key;
                     afile << coin;
                 }
 
                 pcursor->Next();
             }
 
             afile.fclose();
             fs::rename(temppath, path);
 
             UniValue result(UniValue::VOBJ);
             result.pushKV("coins_written", stats.coins_count);
             result.pushKV("base_hash", tip->GetBlockHash().ToString());
             result.pushKV("base_height", tip->nHeight);
             result.pushKV("path", path.u8string());
             return result;
         },
     };
 }
 
 void RegisterBlockchainRPCCommands(CRPCTable &t) {
     // clang-format off
     static const CRPCCommand commands[] = {
         //  category            actor (function)
         //  ------------------  ----------------------
         { "blockchain",         getbestblockhash,                  },
         { "blockchain",         getblock,                          },
         { "blockchain",         getblockchaininfo,                 },
         { "blockchain",         getblockcount,                     },
         { "blockchain",         getblockhash,                      },
         { "blockchain",         getblockheader,                    },
         { "blockchain",         getblockstats,                     },
         { "blockchain",         getchaintips,                      },
         { "blockchain",         getchaintxstats,                   },
         { "blockchain",         getdifficulty,                     },
         { "blockchain",         getmempoolancestors,               },
         { "blockchain",         getmempooldescendants,             },
         { "blockchain",         getmempoolentry,                   },
         { "blockchain",         getmempoolinfo,                    },
         { "blockchain",         getrawmempool,                     },
         { "blockchain",         gettxout,                          },
         { "blockchain",         gettxoutsetinfo,                   },
         { "blockchain",         pruneblockchain,                   },
         { "blockchain",         savemempool,                       },
         { "blockchain",         verifychain,                       },
         { "blockchain",         preciousblock,                     },
         { "blockchain",         scantxoutset,                      },
         { "blockchain",         getblockfilter,                    },
 
         /* Not shown in help */
         { "hidden",             getfinalizedblockhash,             },
         { "hidden",             finalizeblock,                     },
         { "hidden",             invalidateblock,                   },
         { "hidden",             parkblock,                         },
         { "hidden",             reconsiderblock,                   },
         { "hidden",             syncwithvalidationinterfacequeue,  },
         { "hidden",             dumptxoutset,                      },
         { "hidden",             unparkblock,                       },
         { "hidden",             waitfornewblock,                   },
         { "hidden",             waitforblock,                      },
         { "hidden",             waitforblockheight,                },
     };
     // clang-format on
     for (const auto &c : commands) {
         t.appendCommand(c.name, &c);
     }
 }
diff --git a/src/script/sign.h b/src/script/sign.h
index f2841867e..adde49c0b 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -1,202 +1,202 @@
 // Copyright (c) 2009-2010 Satoshi Nakamoto
 // Copyright (c) 2009-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.
 
 #ifndef BITCOIN_SCRIPT_SIGN_H
 #define BITCOIN_SCRIPT_SIGN_H
 
 #include <coins.h>
 #include <hash.h>
 #include <pubkey.h>
 #include <script/interpreter.h>
 #include <script/keyorigin.h>
 #include <script/sighashtype.h>
 #include <streams.h>
 
 class CKey;
 class CKeyID;
 class CMutableTransaction;
 class CScript;
 class CScriptID;
 class CTransaction;
 class SigningProvider;
 
 /** Interface for signature creators. */
 class BaseSignatureCreator {
 public:
     virtual ~BaseSignatureCreator() {}
     virtual const BaseSignatureChecker &Checker() const = 0;
 
     /** Create a singular (non-script) signature. */
     virtual bool CreateSig(const SigningProvider &provider,
                            std::vector<uint8_t> &vchSig, const CKeyID &keyid,
                            const CScript &scriptCode) const = 0;
 };
 
 /** A signature creator for transactions. */
 class MutableTransactionSignatureCreator : public BaseSignatureCreator {
     const CMutableTransaction *txTo;
     unsigned int nIn;
     Amount amount;
     SigHashType sigHashType;
     const MutableTransactionSignatureChecker checker;
 
 public:
     MutableTransactionSignatureCreator(
         const CMutableTransaction *txToIn, unsigned int nInIn,
         const Amount &amountIn, SigHashType sigHashTypeIn = SigHashType());
     const BaseSignatureChecker &Checker() const override { return checker; }
     bool CreateSig(const SigningProvider &provider,
                    std::vector<uint8_t> &vchSig, const CKeyID &keyid,
                    const CScript &scriptCode) const override;
 };
 
 /** A signature creator that just produces 71-byte empty signatures. */
 extern const BaseSignatureCreator &DUMMY_SIGNATURE_CREATOR;
 /** A signature creator that just produces 72-byte empty signatures. */
 extern const BaseSignatureCreator &DUMMY_MAXIMUM_SIGNATURE_CREATOR;
 
 typedef std::pair<CPubKey, std::vector<uint8_t>> SigPair;
 
 // This struct contains information from a transaction input and also contains
 // signatures for that input. The information contained here can be used to
 // create a signature and is also filled by ProduceSignature in order to
 // construct final scriptSigs.
 struct SignatureData {
     /// Stores whether the scriptSig are complete.
     bool complete = false;
     /// The scriptSig of an input. Contains complete signatures or the
     /// traditional partial signatures format.
     CScript scriptSig;
     /// The redeemScript (if any) for the input.
     CScript redeem_script;
     /// BIP 174 style partial signatures for the input. May contain all
     /// signatures necessary for producing a final scriptSig.
     std::map<CKeyID, SigPair> signatures;
     std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> misc_pubkeys;
     /// KeyIDs of pubkeys which could not be found
     std::vector<CKeyID> missing_pubkeys;
     /// KeyIDs of pubkeys for signatures which could not be found
     std::vector<CKeyID> missing_sigs;
     /// ScriptID of the missing redeemScript (if any)
     uint160 missing_redeem_script;
 
     SignatureData() {}
     explicit SignatureData(const CScript &script) : scriptSig(script) {}
     void MergeSignatureData(SignatureData sigdata);
 };
 
 // Takes a stream and multiple arguments and serializes them as if first
 // serialized into a vector and then into the stream. The resulting output into
 // the stream has the total serialized length of all of the objects followed by
 // all objects concatenated with each other.
 template <typename Stream, typename... X>
-void SerializeToVector(Stream &s, const X &... args) {
+void SerializeToVector(Stream &s, const X &...args) {
     WriteCompactSize(s, GetSerializeSizeMany(s.GetVersion(), args...));
     SerializeMany(s, args...);
 }
 
 // Takes a stream and multiple arguments and unserializes them first as a vector
 // then each object individually in the order provided in the arguments.
 template <typename Stream, typename... X>
-void UnserializeFromVector(Stream &s, X &... args) {
+void UnserializeFromVector(Stream &s, X &...args) {
     size_t expected_size = ReadCompactSize(s);
     size_t remaining_before = s.size();
     UnserializeMany(s, args...);
     size_t remaining_after = s.size();
     if (remaining_after + expected_size != remaining_before) {
         throw std::ios_base::failure("Size of value was not the stated size");
     }
 }
 
 // Deserialize HD keypaths into a map
 template <typename Stream>
 void DeserializeHDKeypaths(Stream &s, const std::vector<uint8_t> &key,
                            std::map<CPubKey, KeyOriginInfo> &hd_keypaths) {
     // Make sure that the key is the size of pubkey + 1
     if (key.size() != CPubKey::SIZE + 1 &&
         key.size() != CPubKey::COMPRESSED_SIZE + 1) {
         throw std::ios_base::failure(
             "Size of key was not the expected size for the type BIP32 keypath");
     }
     // Read in the pubkey from key
     CPubKey pubkey(key.begin() + 1, key.end());
     if (!pubkey.IsFullyValid()) {
         throw std::ios_base::failure("Invalid pubkey");
     }
     if (hd_keypaths.count(pubkey) > 0) {
         throw std::ios_base::failure(
             "Duplicate Key, pubkey derivation path already provided");
     }
 
     // Read in key path
     uint64_t value_len = ReadCompactSize(s);
     if (value_len % 4 || value_len == 0) {
         throw std::ios_base::failure("Invalid length for HD key path");
     }
 
     KeyOriginInfo keypath;
     s >> keypath.fingerprint;
     for (unsigned int i = 4; i < value_len; i += sizeof(uint32_t)) {
         uint32_t index;
         s >> index;
         keypath.path.push_back(index);
     }
 
     // Add to map
     hd_keypaths.emplace(pubkey, std::move(keypath));
 }
 
 // Serialize HD keypaths to a stream from a map
 template <typename Stream>
 void SerializeHDKeypaths(Stream &s,
                          const std::map<CPubKey, KeyOriginInfo> &hd_keypaths,
                          uint8_t type) {
     for (auto keypath_pair : hd_keypaths) {
         if (!keypath_pair.first.IsValid()) {
             throw std::ios_base::failure("Invalid CPubKey being serialized");
         }
         SerializeToVector(s, type, MakeSpan(keypath_pair.first));
         WriteCompactSize(s, (keypath_pair.second.path.size() + 1) *
                                 sizeof(uint32_t));
         s << keypath_pair.second.fingerprint;
         for (const auto &path : keypath_pair.second.path) {
             s << path;
         }
     }
 }
 
 /** Produce a script signature using a generic signature creator. */
 bool ProduceSignature(const SigningProvider &provider,
                       const BaseSignatureCreator &creator,
                       const CScript &scriptPubKey, SignatureData &sigdata);
 
 /** Produce a script signature for a transaction. */
 bool SignSignature(const SigningProvider &provider, const CScript &fromPubKey,
                    CMutableTransaction &txTo, unsigned int nIn,
                    const Amount amount, SigHashType sigHashType);
 bool SignSignature(const SigningProvider &provider, const CTransaction &txFrom,
                    CMutableTransaction &txTo, unsigned int nIn,
                    SigHashType sigHashType);
 
 /** Extract signature data from a transaction input, and insert it. */
 SignatureData DataFromTransaction(const CMutableTransaction &tx,
                                   unsigned int nIn, const CTxOut &txout);
 void UpdateInput(CTxIn &input, const SignatureData &data);
 
 /**
  * Check whether we know how to sign for an output like this, assuming we have
  * all private keys. While this function does not need private keys, the passed
  * keystore is used to look up public keys and redeemscripts by hash.
  * Solvability is unrelated to whether we consider this output to be ours.
  */
 bool IsSolvable(const SigningProvider &provider, const CScript &script);
 
 /** Sign the CMutableTransaction */
 bool SignTransaction(CMutableTransaction &mtx, const SigningProvider *provider,
                      const std::map<COutPoint, Coin> &coins,
                      SigHashType sigHashType,
                      std::map<int, std::string> &input_errors);
 
 #endif // BITCOIN_SCRIPT_SIGN_H
diff --git a/src/seeder/messagewriter.h b/src/seeder/messagewriter.h
index 782507137..fbe423188 100644
--- a/src/seeder/messagewriter.h
+++ b/src/seeder/messagewriter.h
@@ -1,37 +1,37 @@
 // Copyright (c) 2020 The Bitcoin developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #ifndef BITCOIN_SEEDER_MESSAGEWRITER_H
 #define BITCOIN_SEEDER_MESSAGEWRITER_H
 
 #include <config.h>
 #include <net.h>
 #include <netmessagemaker.h>
 
 namespace MessageWriter {
 
 template <typename... Args>
 static void WriteMessage(CDataStream &stream, std::string command,
-                         Args &&... args) {
+                         Args &&...args) {
     CSerializedNetMsg payload = CNetMsgMaker(stream.GetVersion())
                                     .Make(command, std::forward<Args>(args)...);
     size_t nMessageSize = payload.data.size();
 
     // Serialize header
     std::vector<uint8_t> serializedHeader;
     V1TransportSerializer serializer = V1TransportSerializer();
     serializer.prepareForTransport(GetConfig(), payload, serializedHeader);
 
     // Write message header + payload to outgoing stream
     stream.write(reinterpret_cast<const char *>(serializedHeader.data()),
                  serializedHeader.size());
     if (nMessageSize) {
         stream.write(reinterpret_cast<const char *>(payload.data.data()),
                      nMessageSize);
     }
 }
 
 } // namespace MessageWriter
 
 #endif // BITCOIN_SEEDER_MESSAGEWRITER_H
diff --git a/src/seeder/test/message_writer_tests.cpp b/src/seeder/test/message_writer_tests.cpp
index 4bb2b20b7..e7480acd1 100644
--- a/src/seeder/test/message_writer_tests.cpp
+++ b/src/seeder/test/message_writer_tests.cpp
@@ -1,94 +1,94 @@
 // Copyright (c) 2020 The Bitcoin developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <hash.h>
 #include <primitives/block.h>
 #include <protocol.h>
 #include <seeder/messagewriter.h>
 #include <streams.h>
 #include <version.h>
 
 #include <boost/test/unit_test.hpp>
 
 #include <string>
 #include <vector>
 
 BOOST_AUTO_TEST_SUITE(message_writer_tests)
 
 template <typename... Args>
 static void CheckMessage(CDataStream &expectedMessage, std::string command,
-                         Args &&... args) {
+                         Args &&...args) {
     CDataStream message(SER_NETWORK, PROTOCOL_VERSION);
     MessageWriter::WriteMessage(message, command, std::forward<Args>(args)...);
     BOOST_CHECK_EQUAL(message.size(), expectedMessage.size());
     for (size_t i = 0; i < message.size(); i++) {
         BOOST_CHECK_EQUAL(message[i], expectedMessage[i]);
     }
 }
 
 BOOST_AUTO_TEST_CASE(simple_header_and_payload_message_writer_test) {
     SelectParams(CBaseChainParams::MAIN);
     int64_t now = GetTime();
     uint64_t nonce = 0;
     uint64_t serviceFlags = uint64_t(ServiceFlags(NODE_NETWORK));
     CService service;
     CAddress addrTo(service, ServiceFlags(NODE_NETWORK));
     CAddress addrFrom(service, ServiceFlags(NODE_NETWORK));
     std::string user_agent = "/Bitcoin ABC:0.0.0(seeder)/";
     int start_height = 1;
 
     CDataStream versionPayload(SER_NETWORK, PROTOCOL_VERSION);
     versionPayload << PROTOCOL_VERSION << serviceFlags << now << addrTo
                    << addrFrom << nonce << user_agent << start_height;
 
     CMessageHeader versionhdr(Params().NetMagic(), NetMsgType::VERSION,
                               versionPayload.size());
     uint256 hash = Hash(versionPayload);
     memcpy(versionhdr.pchChecksum, hash.begin(), CMessageHeader::CHECKSUM_SIZE);
 
     CDataStream expectedVersion(SER_NETWORK, PROTOCOL_VERSION);
     expectedVersion << versionhdr;
     expectedVersion += versionPayload;
 
     CheckMessage(expectedVersion, NetMsgType::VERSION, PROTOCOL_VERSION,
                  serviceFlags, now, addrTo, addrFrom, nonce, user_agent,
                  start_height);
 }
 
 BOOST_AUTO_TEST_CASE(header_empty_payload_message_writer_test) {
     SelectParams(CBaseChainParams::MAIN);
     CMessageHeader verackHeader(Params().NetMagic(), NetMsgType::VERACK, 0);
     CDataStream expectedVerack(SER_NETWORK, PROTOCOL_VERSION);
     // This is an empty payload, but is still necessary for the checksum
     std::vector<uint8_t> payload;
     uint256 hash = Hash(payload);
     memcpy(verackHeader.pchChecksum, hash.begin(),
            CMessageHeader::CHECKSUM_SIZE);
     expectedVerack << verackHeader;
 
     CheckMessage(expectedVerack, NetMsgType::VERACK);
 }
 
 BOOST_AUTO_TEST_CASE(write_getheaders_message_test) {
     SelectParams(CBaseChainParams::MAIN);
     CDataStream payload(SER_NETWORK, PROTOCOL_VERSION);
     BlockHash bhash(uint256S(
         "0000000099f5509b5f36b1926bcf82b21d936ebeadee811030dfbbb7fae915d7"));
     std::vector<BlockHash> vlocator(1, bhash);
     CBlockLocator locatorhash(vlocator);
     payload << locatorhash << uint256();
     uint256 hash = Hash(payload);
 
     CMessageHeader msgHeader(Params().NetMagic(), NetMsgType::GETHEADERS,
                              payload.size());
     memcpy(msgHeader.pchChecksum, hash.begin(), CMessageHeader::CHECKSUM_SIZE);
 
     CDataStream expectedMsg(SER_NETWORK, PROTOCOL_VERSION);
     expectedMsg << msgHeader;
     expectedMsg += payload;
 
     CheckMessage(expectedMsg, NetMsgType::GETHEADERS, locatorhash, uint256());
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/serialize.h b/src/serialize.h
index aab557da4..3550b7443 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -1,1193 +1,1193 @@
 // Copyright (c) 2009-2010 Satoshi Nakamoto
 // Copyright (c) 2009-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.
 
 #ifndef BITCOIN_SERIALIZE_H
 #define BITCOIN_SERIALIZE_H
 
 #include <compat/endian.h>
 #include <prevector.h>
 #include <span.h>
 
 #include <algorithm>
 #include <array>
 #include <cstdint>
 #include <cstring>
 #include <ios>
 #include <limits>
 #include <map>
 #include <memory>
 #include <set>
 #include <string>
 #include <utility>
 #include <vector>
 
 /**
  * The maximum size of a serialized object in bytes or number of elements
  * (for eg vectors) when the size is encoded as CompactSize.
  */
 static constexpr uint64_t MAX_SIZE = 0x02000000;
 
 /**
  * Maximum amount of memory (in bytes) to allocate at once when deserializing
  * vectors.
  */
 static const unsigned int MAX_VECTOR_ALLOCATE = 5000000;
 
 /**
  * Dummy data type to identify deserializing constructors.
  *
  * By convention, a constructor of a type T with signature
  *
  *   template <typename Stream> T::T(deserialize_type, Stream& s)
  *
  * is a deserializing constructor, which builds the type by deserializing it
  * from s. If T contains const fields, this is likely the only way to do so.
  */
 struct deserialize_type {};
 constexpr deserialize_type deserialize{};
 
 //! Safely convert odd char pointer types to standard ones.
 inline char *CharCast(char *c) {
     return c;
 }
 inline char *CharCast(uint8_t *c) {
     return (char *)c;
 }
 inline const char *CharCast(const char *c) {
     return c;
 }
 inline const char *CharCast(const uint8_t *c) {
     return (const char *)c;
 }
 
 /**
  * Lowest-level serialization and conversion.
  * @note Sizes of these types are verified in the tests
  */
 template <typename Stream> inline void ser_writedata8(Stream &s, uint8_t obj) {
     s.write((char *)&obj, 1);
 }
 template <typename Stream>
 inline void ser_writedata16(Stream &s, uint16_t obj) {
     obj = htole16(obj);
     s.write((char *)&obj, 2);
 }
 template <typename Stream>
 inline void ser_writedata16be(Stream &s, uint16_t obj) {
     obj = htobe16(obj);
     s.write((char *)&obj, 2);
 }
 template <typename Stream>
 inline void ser_writedata32(Stream &s, uint32_t obj) {
     obj = htole32(obj);
     s.write((char *)&obj, 4);
 }
 template <typename Stream>
 inline void ser_writedata32be(Stream &s, uint32_t obj) {
     obj = htobe32(obj);
     s.write((char *)&obj, 4);
 }
 template <typename Stream>
 inline void ser_writedata64(Stream &s, uint64_t obj) {
     obj = htole64(obj);
     s.write((char *)&obj, 8);
 }
 template <typename Stream> inline uint8_t ser_readdata8(Stream &s) {
     uint8_t obj;
     s.read((char *)&obj, 1);
     return obj;
 }
 template <typename Stream> inline uint16_t ser_readdata16(Stream &s) {
     uint16_t obj;
     s.read((char *)&obj, 2);
     return le16toh(obj);
 }
 template <typename Stream> inline uint16_t ser_readdata16be(Stream &s) {
     uint16_t obj;
     s.read((char *)&obj, 2);
     return be16toh(obj);
 }
 template <typename Stream> inline uint32_t ser_readdata32(Stream &s) {
     uint32_t obj;
     s.read((char *)&obj, 4);
     return le32toh(obj);
 }
 template <typename Stream> inline uint32_t ser_readdata32be(Stream &s) {
     uint32_t obj;
     s.read((char *)&obj, 4);
     return be32toh(obj);
 }
 template <typename Stream> inline uint64_t ser_readdata64(Stream &s) {
     uint64_t obj;
     s.read((char *)&obj, 8);
     return le64toh(obj);
 }
 inline uint64_t ser_double_to_uint64(double x) {
     uint64_t tmp;
     std::memcpy(&tmp, &x, sizeof(x));
     static_assert(sizeof(tmp) == sizeof(x),
                   "double and uint64_t assumed to have the same size");
     return tmp;
 }
 inline uint32_t ser_float_to_uint32(float x) {
     uint32_t tmp;
     std::memcpy(&tmp, &x, sizeof(x));
     static_assert(sizeof(tmp) == sizeof(x),
                   "float and uint32_t assumed to have the same size");
     return tmp;
 }
 inline double ser_uint64_to_double(uint64_t y) {
     double tmp;
     std::memcpy(&tmp, &y, sizeof(y));
     static_assert(sizeof(tmp) == sizeof(y),
                   "double and uint64_t assumed to have the same size");
     return tmp;
 }
 inline float ser_uint32_to_float(uint32_t y) {
     float tmp;
     std::memcpy(&tmp, &y, sizeof(y));
     static_assert(sizeof(tmp) == sizeof(y),
                   "float and uint32_t assumed to have the same size");
     return tmp;
 }
 
 /////////////////////////////////////////////////////////////////
 //
 // Templates for serializing to anything that looks like a stream,
 // i.e. anything that supports .read(char*, size_t) and .write(char*, size_t)
 //
 class CSizeComputer;
 
 enum {
     // primary actions
     SER_NETWORK = (1 << 0),
     SER_DISK = (1 << 1),
     SER_GETHASH = (1 << 2),
 };
 
 //! Convert the reference base type to X, without changing constness or
 //! reference type.
 template <typename X> X &ReadWriteAsHelper(X &x) {
     return x;
 }
 template <typename X> const X &ReadWriteAsHelper(const X &x) {
     return x;
 }
 
 #define READWRITE(...) (::SerReadWriteMany(s, ser_action, __VA_ARGS__))
 #define READWRITEAS(type, obj)                                                 \
     (::SerReadWriteMany(s, ser_action, ReadWriteAsHelper<type>(obj)))
 #define SER_READ(obj, code)                                                    \
     ::SerRead(                                                                 \
         s, ser_action, obj,                                                    \
         [&](Stream &s, typename std::remove_const<Type>::type &obj) { code; })
 #define SER_WRITE(obj, code)                                                   \
     ::SerWrite(s, ser_action, obj, [&](Stream &s, const Type &obj) { code; })
 
 /**
  * Implement the Ser and Unser methods needed for implementing a formatter
  * (see Using below).
  *
  * Both Ser and Unser are delegated to a single static method SerializationOps,
  * which is polymorphic in the serialized/deserialized type (allowing it to be
  * const when serializing, and non-const when deserializing).
  *
  * Example use:
  *   struct FooFormatter {
  *     FORMATTER_METHODS(Class, obj) { READWRITE(obj.val1, VARINT(obj.val2)); }
  *   }
  * would define a class FooFormatter that defines a serialization of Class
  * objects consisting of serializing its val1 member using the default
  * serialization, and its val2 member using VARINT serialization. That
  * FooFormatter can then be used in statements like
  *   READWRITE(Using<FooFormatter>(obj.bla)).
  */
 #define FORMATTER_METHODS(cls, obj)                                            \
     template <typename Stream> static void Ser(Stream &s, const cls &obj) {    \
         SerializationOps(obj, s, CSerActionSerialize());                       \
     }                                                                          \
     template <typename Stream> static void Unser(Stream &s, cls &obj) {        \
         SerializationOps(obj, s, CSerActionUnserialize());                     \
     }                                                                          \
     template <typename Stream, typename Type, typename Operation>              \
     static inline void SerializationOps(Type &obj, Stream &s,                  \
                                         Operation ser_action)
 
 /**
  * Implement the Serialize and Unserialize methods by delegating to a
  * single templated static method that takes the to-be-(de)serialized
  * object as a parameter. This approach has the advantage that the
  * constness of the object becomes a template parameter, and thus
  * allows a single implementation that sees the object as const for
  * serializing and non-const for deserializing, without casts.
  */
 #define SERIALIZE_METHODS(cls, obj)                                            \
     template <typename Stream> void Serialize(Stream &s) const {               \
         static_assert(std::is_same<const cls &, decltype(*this)>::value,       \
                       "Serialize type mismatch");                              \
         Ser(s, *this);                                                         \
     }                                                                          \
     template <typename Stream> void Unserialize(Stream &s) {                   \
         static_assert(std::is_same<cls &, decltype(*this)>::value,             \
                       "Unserialize type mismatch");                            \
         Unser(s, *this);                                                       \
     }                                                                          \
     FORMATTER_METHODS(cls, obj)
 
 #ifndef CHAR_EQUALS_INT8
 // TODO Get rid of bare char
 template <typename Stream> inline void Serialize(Stream &s, char a) {
     ser_writedata8(s, a);
 }
 #endif
 template <typename Stream> inline void Serialize(Stream &s, int8_t a) {
     ser_writedata8(s, a);
 }
 template <typename Stream> inline void Serialize(Stream &s, uint8_t a) {
     ser_writedata8(s, a);
 }
 template <typename Stream> inline void Serialize(Stream &s, int16_t a) {
     ser_writedata16(s, a);
 }
 template <typename Stream> inline void Serialize(Stream &s, uint16_t a) {
     ser_writedata16(s, a);
 }
 template <typename Stream> inline void Serialize(Stream &s, int32_t a) {
     ser_writedata32(s, a);
 }
 template <typename Stream> inline void Serialize(Stream &s, uint32_t a) {
     ser_writedata32(s, a);
 }
 template <typename Stream> inline void Serialize(Stream &s, int64_t a) {
     ser_writedata64(s, a);
 }
 template <typename Stream> inline void Serialize(Stream &s, uint64_t a) {
     ser_writedata64(s, a);
 }
 template <typename Stream> inline void Serialize(Stream &s, float a) {
     ser_writedata32(s, ser_float_to_uint32(a));
 }
 template <typename Stream> inline void Serialize(Stream &s, double a) {
     ser_writedata64(s, ser_double_to_uint64(a));
 }
 template <typename Stream, size_t N>
 inline void Serialize(Stream &s, const int8_t (&a)[N]) {
     s.write(a, N);
 }
 template <typename Stream, size_t N>
 inline void Serialize(Stream &s, const uint8_t (&a)[N]) {
     s.write(CharCast(a), N);
 }
 template <typename Stream, size_t N>
 inline void Serialize(Stream &s, const std::array<int8_t, N> &a) {
     s.write(a.data(), N);
 }
 template <typename Stream, size_t N>
 inline void Serialize(Stream &s, const std::array<uint8_t, N> &a) {
     s.write(CharCast(a.data()), N);
 }
 #ifndef CHAR_EQUALS_INT8
 // TODO Get rid of bare char
 template <typename Stream> inline void Unserialize(Stream &s, char &a) {
     a = ser_readdata8(s);
 }
 template <typename Stream, size_t N>
 inline void Serialize(Stream &s, const char (&a)[N]) {
     s.write(a, N);
 }
 template <typename Stream, size_t N>
 inline void Serialize(Stream &s, const std::array<char, N> &a) {
     s.write(a.data(), N);
 }
 #endif
 template <typename Stream>
 inline void Serialize(Stream &s, const Span<const uint8_t> &span) {
     s.write(CharCast(span.data()), span.size());
 }
 template <typename Stream>
 inline void Serialize(Stream &s, const Span<uint8_t> &span) {
     s.write(CharCast(span.data()), span.size());
 }
 template <typename Stream> inline void Unserialize(Stream &s, int8_t &a) {
     a = ser_readdata8(s);
 }
 template <typename Stream> inline void Unserialize(Stream &s, uint8_t &a) {
     a = ser_readdata8(s);
 }
 template <typename Stream> inline void Unserialize(Stream &s, int16_t &a) {
     a = ser_readdata16(s);
 }
 template <typename Stream> inline void Unserialize(Stream &s, uint16_t &a) {
     a = ser_readdata16(s);
 }
 template <typename Stream> inline void Unserialize(Stream &s, int32_t &a) {
     a = ser_readdata32(s);
 }
 template <typename Stream> inline void Unserialize(Stream &s, uint32_t &a) {
     a = ser_readdata32(s);
 }
 template <typename Stream> inline void Unserialize(Stream &s, int64_t &a) {
     a = ser_readdata64(s);
 }
 template <typename Stream> inline void Unserialize(Stream &s, uint64_t &a) {
     a = ser_readdata64(s);
 }
 template <typename Stream> inline void Unserialize(Stream &s, float &a) {
     a = ser_uint32_to_float(ser_readdata32(s));
 }
 template <typename Stream> inline void Unserialize(Stream &s, double &a) {
     a = ser_uint64_to_double(ser_readdata64(s));
 }
 template <typename Stream, size_t N>
 inline void Unserialize(Stream &s, int8_t (&a)[N]) {
     s.read(a, N);
 }
 template <typename Stream, size_t N>
 inline void Unserialize(Stream &s, uint8_t (&a)[N]) {
     s.read(CharCast(a), N);
 }
 template <typename Stream, size_t N>
 inline void Unserialize(Stream &s, std::array<int8_t, N> &a) {
     s.read(a.data(), N);
 }
 template <typename Stream, size_t N>
 inline void Unserialize(Stream &s, std::array<uint8_t, N> &a) {
     s.read(CharCast(a.data()), N);
 }
 #ifndef CHAR_EQUALS_INT8
 template <typename Stream, size_t N>
 inline void Unserialize(Stream &s, char (&a)[N]) {
     s.read(CharCast(a), N);
 }
 template <typename Stream, size_t N>
 inline void Unserialize(Stream &s, std::array<char, N> &a) {
     s.read(CharCast(a.data()), N);
 }
 #endif
 
 template <typename Stream> inline void Serialize(Stream &s, bool a) {
     char f = a;
     ser_writedata8(s, f);
 }
 template <typename Stream> inline void Unserialize(Stream &s, bool &a) {
     char f = ser_readdata8(s);
     a = f;
 }
 template <typename Stream>
 inline void Unserialize(Stream &s, Span<uint8_t> &span) {
     s.read(CharCast(span.data()), span.size());
 }
 
 /**
  * Compact Size
  * size <  253        -- 1 byte
  * size <= USHRT_MAX  -- 3 bytes  (253 + 2 bytes)
  * size <= UINT_MAX   -- 5 bytes  (254 + 4 bytes)
  * size >  UINT_MAX   -- 9 bytes  (255 + 8 bytes)
  */
 inline uint32_t GetSizeOfCompactSize(uint64_t nSize) {
     if (nSize < 253) {
         return sizeof(uint8_t);
     }
     if (nSize <= std::numeric_limits<uint16_t>::max()) {
         return sizeof(uint8_t) + sizeof(uint16_t);
     }
     if (nSize <= std::numeric_limits<uint32_t>::max()) {
         return sizeof(uint8_t) + sizeof(uint32_t);
     }
 
     return sizeof(uint8_t) + sizeof(uint64_t);
 }
 
 inline void WriteCompactSize(CSizeComputer &os, uint64_t nSize);
 
 template <typename Stream> void WriteCompactSize(Stream &os, uint64_t nSize) {
     if (nSize < 253) {
         ser_writedata8(os, nSize);
     } else if (nSize <= std::numeric_limits<uint16_t>::max()) {
         ser_writedata8(os, 253);
         ser_writedata16(os, nSize);
     } else if (nSize <= std::numeric_limits<uint32_t>::max()) {
         ser_writedata8(os, 254);
         ser_writedata32(os, nSize);
     } else {
         ser_writedata8(os, 255);
         ser_writedata64(os, nSize);
     }
     return;
 }
 
 /**
  * Decode a CompactSize-encoded variable-length integer.
  *
  * As these are primarily used to encode the size of vector-like serializations,
  * by default a range check is performed. When used as a generic number
  * encoding, range_check should be set to false.
  */
 template <typename Stream>
 uint64_t ReadCompactSize(Stream &is, bool range_check = true) {
     uint8_t chSize = ser_readdata8(is);
     uint64_t nSizeRet = 0;
     if (chSize < 253) {
         nSizeRet = chSize;
     } else if (chSize == 253) {
         nSizeRet = ser_readdata16(is);
         if (nSizeRet < 253) {
             throw std::ios_base::failure("non-canonical ReadCompactSize()");
         }
     } else if (chSize == 254) {
         nSizeRet = ser_readdata32(is);
         if (nSizeRet < 0x10000u) {
             throw std::ios_base::failure("non-canonical ReadCompactSize()");
         }
     } else {
         nSizeRet = ser_readdata64(is);
         if (nSizeRet < 0x100000000ULL) {
             throw std::ios_base::failure("non-canonical ReadCompactSize()");
         }
     }
     if (range_check && nSizeRet > MAX_SIZE) {
         throw std::ios_base::failure("ReadCompactSize(): size too large");
     }
     return nSizeRet;
 }
 
 /**
  * Variable-length integers: bytes are a MSB base-128 encoding of the number.
  * The high bit in each byte signifies whether another digit follows. To make
  * sure the encoding is one-to-one, one is subtracted from all but the last
  * digit. Thus, the byte sequence a[] with length len, where all but the last
  * byte has bit 128 set, encodes the number:
  *
  *  (a[len-1] & 0x7F) + sum(i=1..len-1, 128^i*((a[len-i-1] & 0x7F)+1))
  *
  * Properties:
  * * Very small (0-127: 1 byte, 128-16511: 2 bytes, 16512-2113663: 3 bytes)
  * * Every integer has exactly one encoding
  * * Encoding does not depend on size of original integer type
  * * No redundancy: every (infinite) byte sequence corresponds to a list
  *   of encoded integers.
  *
  * 0:         [0x00]  256:        [0x81 0x00]
  * 1:         [0x01]  16383:      [0xFE 0x7F]
  * 127:       [0x7F]  16384:      [0xFF 0x00]
  * 128:  [0x80 0x00]  16511:      [0xFF 0x7F]
  * 255:  [0x80 0x7F]  65535: [0x82 0xFE 0x7F]
  * 2^32:           [0x8E 0xFE 0xFE 0xFF 0x00]
  */
 
 /**
  * Mode for encoding VarInts.
  *
  * Currently there is no support for signed encodings. The default mode will not
  * compile with signed values, and the legacy "nonnegative signed" mode will
  * accept signed values, but improperly encode and decode them if they are
  * negative. In the future, the DEFAULT mode could be extended to support
  * negative numbers in a backwards compatible way, and additional modes could be
  * added to support different varint formats (e.g. zigzag encoding).
  */
 enum class VarIntMode { DEFAULT, NONNEGATIVE_SIGNED };
 
 template <VarIntMode Mode, typename I> struct CheckVarIntMode {
     constexpr CheckVarIntMode() {
         static_assert(Mode != VarIntMode::DEFAULT || std::is_unsigned<I>::value,
                       "Unsigned type required with mode DEFAULT.");
         static_assert(Mode != VarIntMode::NONNEGATIVE_SIGNED ||
                           std::is_signed<I>::value,
                       "Signed type required with mode NONNEGATIVE_SIGNED.");
     }
 };
 
 template <VarIntMode Mode, typename I>
 inline unsigned int GetSizeOfVarInt(I n) {
     CheckVarIntMode<Mode, I>();
     int nRet = 0;
     while (true) {
         nRet++;
         if (n <= 0x7F) {
             return nRet;
         }
         n = (n >> 7) - 1;
     }
 }
 
 template <typename I> inline void WriteVarInt(CSizeComputer &os, I n);
 
 template <typename Stream, VarIntMode Mode, typename I>
 void WriteVarInt(Stream &os, I n) {
     CheckVarIntMode<Mode, I>();
     uint8_t tmp[(sizeof(n) * 8 + 6) / 7];
     int len = 0;
     while (true) {
         tmp[len] = (n & 0x7F) | (len ? 0x80 : 0x00);
         if (n <= 0x7F) {
             break;
         }
         n = (n >> 7) - 1;
         len++;
     }
     do {
         ser_writedata8(os, tmp[len]);
     } while (len--);
 }
 
 template <typename Stream, VarIntMode Mode, typename I>
 I ReadVarInt(Stream &is) {
     CheckVarIntMode<Mode, I>();
     I n = 0;
     while (true) {
         uint8_t chData = ser_readdata8(is);
         if (n > (std::numeric_limits<I>::max() >> 7)) {
             throw std::ios_base::failure("ReadVarInt(): size too large");
         }
         n = (n << 7) | (chData & 0x7F);
         if ((chData & 0x80) == 0) {
             return n;
         }
         if (n == std::numeric_limits<I>::max()) {
             throw std::ios_base::failure("ReadVarInt(): size too large");
         }
         n++;
     }
 }
 
 /**
  * Simple wrapper class to serialize objects using a formatter; used by
  * Using().
  */
 template <typename Formatter, typename T> class Wrapper {
     static_assert(std::is_lvalue_reference<T>::value,
                   "Wrapper needs an lvalue reference type T");
 
 protected:
     T m_object;
 
 public:
     explicit Wrapper(T obj) : m_object(obj) {}
     template <typename Stream> void Serialize(Stream &s) const {
         Formatter().Ser(s, m_object);
     }
     template <typename Stream> void Unserialize(Stream &s) {
         Formatter().Unser(s, m_object);
     }
 };
 
 /**
  * Cause serialization/deserialization of an object to be done using a
  * specified formatter class.
  *
  * To use this, you need a class Formatter that has public functions Ser(stream,
  * const object&) for serialization, and Unser(stream, object&) for
  * deserialization. Serialization routines (inside READWRITE, or directly with
  * << and >> operators), can then use Using<Formatter>(object).
  *
  * This works by constructing a Wrapper<Formatter, T>-wrapped version of object,
  * where T is const during serialization, and non-const during deserialization,
  * which maintains const correctness.
  */
 template <typename Formatter, typename T>
 static inline Wrapper<Formatter, T &> Using(T &&t) {
     return Wrapper<Formatter, T &>(t);
 }
 
 #define VARINT_MODE(obj, mode) Using<VarIntFormatter<mode>>(obj)
 #define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj)
 #define COMPACTSIZE(obj) Using<CompactSizeFormatter<true>>(obj)
 #define LIMITED_STRING(obj, n) Using<LimitedStringFormatter<n>>(obj)
 
 /**
  * Serialization wrapper class for integers in VarInt format.
  */
 template <VarIntMode Mode> struct VarIntFormatter {
     template <typename Stream, typename I> void Ser(Stream &s, I v) {
         WriteVarInt<Stream, Mode, typename std::remove_cv<I>::type>(s, v);
     }
 
     template <typename Stream, typename I> void Unser(Stream &s, I &v) {
         v = ReadVarInt<Stream, Mode, typename std::remove_cv<I>::type>(s);
     }
 };
 
 /**
  * Serialization wrapper class for custom integers and enums.
  *
  * It permits specifying the serialized size (1 to 8 bytes) and endianness.
  *
  * Use the big endian mode for values that are stored in memory in native
  * byte order, but serialized in big endian notation. This is only intended
  * to implement serializers that are compatible with existing formats, and
  * its use is not recommended for new data structures.
  */
 template <int Bytes, bool BigEndian = false> struct CustomUintFormatter {
     static_assert(Bytes > 0 && Bytes <= 8,
                   "CustomUintFormatter Bytes out of range");
     static constexpr uint64_t MAX = 0xffffffffffffffff >> (8 * (8 - Bytes));
 
     template <typename Stream, typename I> void Ser(Stream &s, I v) {
         if (v < 0 || v > MAX) {
             throw std::ios_base::failure(
                 "CustomUintFormatter value out of range");
         }
         if (BigEndian) {
             uint64_t raw = htobe64(v);
             s.write(((const char *)&raw) + 8 - Bytes, Bytes);
         } else {
             uint64_t raw = htole64(v);
             s.write((const char *)&raw, Bytes);
         }
     }
 
     template <typename Stream, typename I> void Unser(Stream &s, I &v) {
         using U = typename std::conditional<std::is_enum<I>::value,
                                             std::underlying_type<I>,
                                             std::common_type<I>>::type::type;
         static_assert(std::numeric_limits<U>::max() >= MAX &&
                           std::numeric_limits<U>::min() <= 0,
                       "Assigned type too small");
         uint64_t raw = 0;
         if (BigEndian) {
             s.read(((char *)&raw) + 8 - Bytes, Bytes);
             v = static_cast<I>(be64toh(raw));
         } else {
             s.read((char *)&raw, Bytes);
             v = static_cast<I>(le64toh(raw));
         }
     }
 };
 
 template <int Bytes>
 using BigEndianFormatter = CustomUintFormatter<Bytes, true>;
 
 /** Formatter for integers in CompactSize format. */
 template <bool RangeCheck> struct CompactSizeFormatter {
     template <typename Stream, typename I> void Unser(Stream &s, I &v) {
         uint64_t n = ReadCompactSize<Stream>(s, RangeCheck);
         if (n < std::numeric_limits<I>::min() ||
             n > std::numeric_limits<I>::max()) {
             throw std::ios_base::failure("CompactSize exceeds limit of type");
         }
         v = n;
     }
 
     template <typename Stream, typename I> void Ser(Stream &s, I v) {
         static_assert(std::is_unsigned<I>::value,
                       "CompactSize only supported for unsigned integers");
         static_assert(std::numeric_limits<I>::max() <=
                           std::numeric_limits<uint64_t>::max(),
                       "CompactSize only supports 64-bit integers and below");
 
         WriteCompactSize<Stream>(s, v);
     }
 };
 
 template <size_t Limit> struct LimitedStringFormatter {
     template <typename Stream> void Unser(Stream &s, std::string &v) {
         size_t size = ReadCompactSize(s);
         if (size > Limit) {
             throw std::ios_base::failure("String length limit exceeded");
         }
         v.resize(size);
         if (size != 0) {
             s.read((char *)v.data(), size);
         }
     }
 
     template <typename Stream> void Ser(Stream &s, const std::string &v) {
         s << v;
     }
 };
 
 /**
  * Formatter to serialize/deserialize vector elements using another formatter
  *
  * Example:
  *   struct X {
  *     std::vector<uint64_t> v;
  *     SERIALIZE_METHODS(X, obj) {
  *       READWRITE(Using<VectorFormatter<VarInt>>(obj.v));
  *     }
  *   };
  * will define a struct that contains a vector of uint64_t, which is serialized
  * as a vector of VarInt-encoded integers.
  *
  * V is not required to be an std::vector type. It works for any class that
  * exposes a value_type, size, reserve, emplace_back, back, and const iterators.
  */
 template <class Formatter> struct VectorFormatter {
     template <typename Stream, typename V> void Ser(Stream &s, const V &v) {
         Formatter formatter;
         WriteCompactSize(s, v.size());
         for (const typename V::value_type &elem : v) {
             formatter.Ser(s, elem);
         }
     }
 
     template <typename Stream, typename V> void Unser(Stream &s, V &v) {
         Formatter formatter;
         v.clear();
         size_t size = ReadCompactSize(s);
         size_t allocated = 0;
         while (allocated < size) {
             // For DoS prevention, do not blindly allocate as much as the stream
             // claims to contain. Instead, allocate in 5MiB batches, so that an
             // attacker actually needs to provide X MiB of data to make us
             // allocate X+5 Mib.
             static_assert(sizeof(typename V::value_type) <= MAX_VECTOR_ALLOCATE,
                           "Vector element size too large");
             allocated =
                 std::min(size, allocated + MAX_VECTOR_ALLOCATE /
                                                sizeof(typename V::value_type));
             v.reserve(allocated);
             while (v.size() < allocated) {
                 v.emplace_back();
                 formatter.Unser(s, v.back());
             }
         }
     };
 };
 
 /**
  * Forward declarations
  */
 
 /**
  * string
  */
 template <typename Stream, typename C>
 void Serialize(Stream &os, const std::basic_string<C> &str);
 template <typename Stream, typename C>
 void Unserialize(Stream &is, std::basic_string<C> &str);
 
 /**
  * prevector
  * prevectors of uint8_t are a special case and are intended to be serialized as
  * a single opaque blob.
  */
 template <typename Stream, unsigned int N, typename T>
 void Serialize_impl(Stream &os, const prevector<N, T> &v, const uint8_t &);
 template <typename Stream, unsigned int N, typename T, typename V>
 void Serialize_impl(Stream &os, const prevector<N, T> &v, const V &);
 template <typename Stream, unsigned int N, typename T>
 inline void Serialize(Stream &os, const prevector<N, T> &v);
 template <typename Stream, unsigned int N, typename T>
 void Unserialize_impl(Stream &is, prevector<N, T> &v, const uint8_t &);
 template <typename Stream, unsigned int N, typename T, typename V>
 void Unserialize_impl(Stream &is, prevector<N, T> &v, const V &);
 template <typename Stream, unsigned int N, typename T>
 inline void Unserialize(Stream &is, prevector<N, T> &v);
 
 /**
  * vector
  * vectors of uint8_t are a special case and are intended to be serialized as a
  * single opaque blob.
  */
 template <typename Stream, typename T, typename A>
 void Serialize_impl(Stream &os, const std::vector<T, A> &v, const uint8_t &);
 template <typename Stream, typename T, typename A>
 void Serialize_impl(Stream &os, const std::vector<T, A> &v, const bool &);
 template <typename Stream, typename T, typename A, typename V>
 void Serialize_impl(Stream &os, const std::vector<T, A> &v, const V &);
 template <typename Stream, typename T, typename A>
 inline void Serialize(Stream &os, const std::vector<T, A> &v);
 template <typename Stream, typename T, typename A>
 void Unserialize_impl(Stream &is, std::vector<T, A> &v, const uint8_t &);
 template <typename Stream, typename T, typename A, typename V>
 void Unserialize_impl(Stream &is, std::vector<T, A> &v, const V &);
 template <typename Stream, typename T, typename A>
 inline void Unserialize(Stream &is, std::vector<T, A> &v);
 
 /**
  * pair
  */
 template <typename Stream, typename K, typename T>
 void Serialize(Stream &os, const std::pair<K, T> &item);
 template <typename Stream, typename K, typename T>
 void Unserialize(Stream &is, std::pair<K, T> &item);
 
 /**
  * map
  */
 template <typename Stream, typename K, typename T, typename Pred, typename A>
 void Serialize(Stream &os, const std::map<K, T, Pred, A> &m);
 template <typename Stream, typename K, typename T, typename Pred, typename A>
 void Unserialize(Stream &is, std::map<K, T, Pred, A> &m);
 
 /**
  * set
  */
 template <typename Stream, typename K, typename Pred, typename A>
 void Serialize(Stream &os, const std::set<K, Pred, A> &m);
 template <typename Stream, typename K, typename Pred, typename A>
 void Unserialize(Stream &is, std::set<K, Pred, A> &m);
 
 /**
  * shared_ptr
  */
 template <typename Stream, typename T>
 void Serialize(Stream &os, const std::shared_ptr<const T> &p);
 template <typename Stream, typename T>
 void Unserialize(Stream &os, std::shared_ptr<const T> &p);
 
 /**
  * unique_ptr
  */
 template <typename Stream, typename T>
 void Serialize(Stream &os, const std::unique_ptr<const T> &p);
 template <typename Stream, typename T>
 void Unserialize(Stream &os, std::unique_ptr<const T> &p);
 
 /**
  * If none of the specialized versions above matched, default to calling member
  * function.
  */
 template <typename Stream, typename T>
 inline void Serialize(Stream &os, const T &a) {
     a.Serialize(os);
 }
 
 template <typename Stream, typename T>
 inline void Unserialize(Stream &is, T &&a) {
     a.Unserialize(is);
 }
 
 /**
  * Default formatter. Serializes objects as themselves.
  *
  * The vector/prevector serialization code passes this to VectorFormatter
  * to enable reusing that logic. It shouldn't be needed elsewhere.
  */
 struct DefaultFormatter {
     template <typename Stream, typename T>
     static void Ser(Stream &s, const T &t) {
         Serialize(s, t);
     }
 
     template <typename Stream, typename T> static void Unser(Stream &s, T &t) {
         Unserialize(s, t);
     }
 };
 
 /**
  * string
  */
 template <typename Stream, typename C>
 void Serialize(Stream &os, const std::basic_string<C> &str) {
     WriteCompactSize(os, str.size());
     if (!str.empty()) {
         os.write((char *)str.data(), str.size() * sizeof(C));
     }
 }
 
 template <typename Stream, typename C>
 void Unserialize(Stream &is, std::basic_string<C> &str) {
     size_t nSize = ReadCompactSize(is);
     str.resize(nSize);
     if (nSize != 0) {
         is.read((char *)str.data(), nSize * sizeof(C));
     }
 }
 
 /**
  * prevector
  */
 template <typename Stream, unsigned int N, typename T>
 void Serialize_impl(Stream &os, const prevector<N, T> &v, const uint8_t &) {
     WriteCompactSize(os, v.size());
     if (!v.empty()) {
         os.write((char *)v.data(), v.size() * sizeof(T));
     }
 }
 
 template <typename Stream, unsigned int N, typename T, typename V>
 void Serialize_impl(Stream &os, const prevector<N, T> &v, const V &) {
     Serialize(os, Using<VectorFormatter<DefaultFormatter>>(v));
 }
 
 template <typename Stream, unsigned int N, typename T>
 inline void Serialize(Stream &os, const prevector<N, T> &v) {
     Serialize_impl(os, v, T());
 }
 
 template <typename Stream, unsigned int N, typename T>
 void Unserialize_impl(Stream &is, prevector<N, T> &v, const uint8_t &) {
     // Limit size per read so bogus size value won't cause out of memory
     v.clear();
     size_t nSize = ReadCompactSize(is);
     size_t i = 0;
     while (i < nSize) {
         size_t blk = std::min(nSize - i, size_t(1 + 4999999 / sizeof(T)));
         v.resize_uninitialized(i + blk);
         is.read((char *)&v[i], blk * sizeof(T));
         i += blk;
     }
 }
 
 template <typename Stream, unsigned int N, typename T, typename V>
 void Unserialize_impl(Stream &is, prevector<N, T> &v, const V &) {
     Unserialize(is, Using<VectorFormatter<DefaultFormatter>>(v));
 }
 
 template <typename Stream, unsigned int N, typename T>
 inline void Unserialize(Stream &is, prevector<N, T> &v) {
     Unserialize_impl(is, v, T());
 }
 
 /**
  * vector
  */
 template <typename Stream, typename T, typename A>
 void Serialize_impl(Stream &os, const std::vector<T, A> &v, const uint8_t &) {
     WriteCompactSize(os, v.size());
     if (!v.empty()) {
         os.write((char *)v.data(), v.size() * sizeof(T));
     }
 }
 
 template <typename Stream, typename T, typename A>
 void Serialize_impl(Stream &os, const std::vector<T, A> &v, const bool &) {
     // A special case for std::vector<bool>, as dereferencing
     // std::vector<bool>::const_iterator does not result in a const bool&
     // due to std::vector's special casing for bool arguments.
     WriteCompactSize(os, v.size());
     for (bool elem : v) {
         ::Serialize(os, elem);
     }
 }
 
 template <typename Stream, typename T, typename A, typename V>
 void Serialize_impl(Stream &os, const std::vector<T, A> &v, const V &) {
     Serialize(os, Using<VectorFormatter<DefaultFormatter>>(v));
 }
 
 template <typename Stream, typename T, typename A>
 inline void Serialize(Stream &os, const std::vector<T, A> &v) {
     Serialize_impl(os, v, T());
 }
 
 template <typename Stream, typename T, typename A>
 void Unserialize_impl(Stream &is, std::vector<T, A> &v, const uint8_t &) {
     // Limit size per read so bogus size value won't cause out of memory
     v.clear();
     size_t nSize = ReadCompactSize(is);
     size_t i = 0;
     while (i < nSize) {
         size_t blk = std::min(nSize - i, size_t(1 + 4999999 / sizeof(T)));
         v.resize(i + blk);
         is.read((char *)&v[i], blk * sizeof(T));
         i += blk;
     }
 }
 
 template <typename Stream, typename T, typename A, typename V>
 void Unserialize_impl(Stream &is, std::vector<T, A> &v, const V &) {
     Unserialize(is, Using<VectorFormatter<DefaultFormatter>>(v));
 }
 
 template <typename Stream, typename T, typename A>
 inline void Unserialize(Stream &is, std::vector<T, A> &v) {
     Unserialize_impl(is, v, T());
 }
 
 /**
  * pair
  */
 template <typename Stream, typename K, typename T>
 void Serialize(Stream &os, const std::pair<K, T> &item) {
     Serialize(os, item.first);
     Serialize(os, item.second);
 }
 
 template <typename Stream, typename K, typename T>
 void Unserialize(Stream &is, std::pair<K, T> &item) {
     Unserialize(is, item.first);
     Unserialize(is, item.second);
 }
 
 /**
  * map
  */
 template <typename Stream, typename K, typename T, typename Pred, typename A>
 void Serialize(Stream &os, const std::map<K, T, Pred, A> &m) {
     WriteCompactSize(os, m.size());
     for (const auto &entry : m) {
         Serialize(os, entry);
     }
 }
 
 template <typename Stream, typename K, typename T, typename Pred, typename A>
 void Unserialize(Stream &is, std::map<K, T, Pred, A> &m) {
     m.clear();
     size_t nSize = ReadCompactSize(is);
     typename std::map<K, T, Pred, A>::iterator mi = m.begin();
     for (size_t i = 0; i < nSize; i++) {
         std::pair<K, T> item;
         Unserialize(is, item);
         mi = m.insert(mi, item);
     }
 }
 
 /**
  * set
  */
 template <typename Stream, typename K, typename Pred, typename A>
 void Serialize(Stream &os, const std::set<K, Pred, A> &m) {
     WriteCompactSize(os, m.size());
     for (const K &i : m) {
         Serialize(os, i);
     }
 }
 
 template <typename Stream, typename K, typename Pred, typename A>
 void Unserialize(Stream &is, std::set<K, Pred, A> &m) {
     m.clear();
     size_t nSize = ReadCompactSize(is);
     typename std::set<K, Pred, A>::iterator it = m.begin();
     for (size_t i = 0; i < nSize; i++) {
         K key;
         Unserialize(is, key);
         it = m.insert(it, key);
     }
 }
 
 /**
  * unique_ptr
  */
 template <typename Stream, typename T>
 void Serialize(Stream &os, const std::unique_ptr<const T> &p) {
     Serialize(os, *p);
 }
 
 template <typename Stream, typename T>
 void Unserialize(Stream &is, std::unique_ptr<const T> &p) {
     p.reset(new T(deserialize, is));
 }
 
 /**
  * shared_ptr
  */
 template <typename Stream, typename T>
 void Serialize(Stream &os, const std::shared_ptr<const T> &p) {
     Serialize(os, *p);
 }
 
 template <typename Stream, typename T>
 void Unserialize(Stream &is, std::shared_ptr<const T> &p) {
     p = std::make_shared<const T>(deserialize, is);
 }
 
 /**
  * Support for SERIALIZE_METHODS and READWRITE macro.
  */
 struct CSerActionSerialize {
     constexpr bool ForRead() const { return false; }
 };
 struct CSerActionUnserialize {
     constexpr bool ForRead() const { return true; }
 };
 
 /**
  * ::GetSerializeSize implementations
  *
  * Computing the serialized size of objects is done through a special stream
  * object of type CSizeComputer, which only records the number of bytes written
  * to it.
  *
  * If your Serialize or SerializationOp method has non-trivial overhead for
  * serialization, it may be worthwhile to implement a specialized version for
  * CSizeComputer, which uses the s.seek() method to record bytes that would
  * be written instead.
  */
 class CSizeComputer {
 protected:
     size_t nSize;
 
     const int nVersion;
 
 public:
     explicit CSizeComputer(int nVersionIn) : nSize(0), nVersion(nVersionIn) {}
 
     void write(const char *psz, size_t _nSize) { this->nSize += _nSize; }
 
     /** Pretend _nSize bytes are written, without specifying them. */
     void seek(size_t _nSize) { this->nSize += _nSize; }
 
     template <typename T> CSizeComputer &operator<<(const T &obj) {
         ::Serialize(*this, obj);
         return (*this);
     }
 
     size_t size() const { return nSize; }
 
     int GetVersion() const { return nVersion; }
 };
 
 template <typename Stream> void SerializeMany(Stream &s) {}
 
 template <typename Stream, typename Arg, typename... Args>
-void SerializeMany(Stream &s, const Arg &arg, const Args &... args) {
+void SerializeMany(Stream &s, const Arg &arg, const Args &...args) {
     ::Serialize(s, arg);
     ::SerializeMany(s, args...);
 }
 
 template <typename Stream> inline void UnserializeMany(Stream &s) {}
 
 template <typename Stream, typename Arg, typename... Args>
-inline void UnserializeMany(Stream &s, Arg &&arg, Args &&... args) {
+inline void UnserializeMany(Stream &s, Arg &&arg, Args &&...args) {
     ::Unserialize(s, arg);
     ::UnserializeMany(s, args...);
 }
 
 template <typename Stream, typename... Args>
 inline void SerReadWriteMany(Stream &s, CSerActionSerialize ser_action,
-                             const Args &... args) {
+                             const Args &...args) {
     ::SerializeMany(s, args...);
 }
 
 template <typename Stream, typename... Args>
 inline void SerReadWriteMany(Stream &s, CSerActionUnserialize ser_action,
-                             Args &&... args) {
+                             Args &&...args) {
     ::UnserializeMany(s, args...);
 }
 
 template <typename Stream, typename Type, typename Fn>
 inline void SerRead(Stream &s, CSerActionSerialize ser_action, Type &&, Fn &&) {
 }
 
 template <typename Stream, typename Type, typename Fn>
 inline void SerRead(Stream &s, CSerActionUnserialize ser_action, Type &&obj,
                     Fn &&fn) {
     fn(s, std::forward<Type>(obj));
 }
 
 template <typename Stream, typename Type, typename Fn>
 inline void SerWrite(Stream &s, CSerActionSerialize ser_action, Type &&obj,
                      Fn &&fn) {
     fn(s, std::forward<Type>(obj));
 }
 
 template <typename Stream, typename Type, typename Fn>
 inline void SerWrite(Stream &s, CSerActionUnserialize ser_action, Type &&,
                      Fn &&) {}
 
 template <typename I> inline void WriteVarInt(CSizeComputer &s, I n) {
     s.seek(GetSizeOfVarInt<I>(n));
 }
 
 inline void WriteCompactSize(CSizeComputer &s, uint64_t nSize) {
     s.seek(GetSizeOfCompactSize(nSize));
 }
 
 template <typename T> size_t GetSerializeSize(const T &t, int nVersion = 0) {
     return (CSizeComputer(nVersion) << t).size();
 }
 
 template <typename... T>
-size_t GetSerializeSizeMany(int nVersion, const T &... t) {
+size_t GetSerializeSizeMany(int nVersion, const T &...t) {
     CSizeComputer sc(nVersion);
     SerializeMany(sc, t...);
     return sc.size();
 }
 
 #endif // BITCOIN_SERIALIZE_H
diff --git a/src/streams.h b/src/streams.h
index ba76db67b..fa6f8b4b1 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -1,849 +1,849 @@
 // Copyright (c) 2009-2010 Satoshi Nakamoto
 // Copyright (c) 2009-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.
 
 #ifndef BITCOIN_STREAMS_H
 #define BITCOIN_STREAMS_H
 
 #include <serialize.h>
 #include <support/allocators/zeroafterfree.h>
 
 #include <algorithm>
 #include <cassert>
 #include <cstdint>
 #include <cstdio>
 #include <cstring>
 #include <ios>
 #include <limits>
 #include <string>
 #include <utility>
 #include <vector>
 
 template <typename Stream> class OverrideStream {
     Stream *stream;
 
     const int nType;
     const int nVersion;
 
 public:
     OverrideStream(Stream *stream_, int nType_, int nVersion_)
         : stream(stream_), nType(nType_), nVersion(nVersion_) {}
 
     template <typename T> OverrideStream<Stream> &operator<<(const T &obj) {
         // Serialize to this stream
         ::Serialize(*this, obj);
         return (*this);
     }
 
     template <typename T> OverrideStream<Stream> &operator>>(T &&obj) {
         // Unserialize from this stream
         ::Unserialize(*this, obj);
         return (*this);
     }
 
     void write(const char *pch, size_t nSize) { stream->write(pch, nSize); }
 
     void read(char *pch, size_t nSize) { stream->read(pch, nSize); }
 
     int GetVersion() const { return nVersion; }
     int GetType() const { return nType; }
     void ignore(size_t size) { return stream->ignore(size); }
 };
 
 template <typename S> OverrideStream<S> WithOrVersion(S *s, int nVersionFlag) {
     return OverrideStream<S>(s, s->GetType(), s->GetVersion() | nVersionFlag);
 }
 
 /**
  * Minimal stream for overwriting and/or appending to an existing byte vector.
  *
  * The referenced vector will grow as necessary.
  */
 class CVectorWriter {
 public:
     /**
      * @param[in]  nTypeIn Serialization Type
      * @param[in]  nVersionIn Serialization Version (including any flags)
      * @param[in]  vchDataIn  Referenced byte vector to overwrite/append
      * @param[in]  nPosIn Starting position. Vector index where writes should
      * start. The vector will initially grow as necessary to  max(nPosIn,
      * vec.size()). So to append, use vec.size().
      */
     CVectorWriter(int nTypeIn, int nVersionIn, std::vector<uint8_t> &vchDataIn,
                   size_t nPosIn)
         : nType(nTypeIn), nVersion(nVersionIn), vchData(vchDataIn),
           nPos(nPosIn) {
         if (nPos > vchData.size()) {
             vchData.resize(nPos);
         }
     }
     /**
      * (other params same as above)
      * @param[in]  args  A list of items to serialize starting at nPosIn.
      */
     template <typename... Args>
     CVectorWriter(int nTypeIn, int nVersionIn, std::vector<uint8_t> &vchDataIn,
-                  size_t nPosIn, Args &&... args)
+                  size_t nPosIn, Args &&...args)
         : CVectorWriter(nTypeIn, nVersionIn, vchDataIn, nPosIn) {
         ::SerializeMany(*this, std::forward<Args>(args)...);
     }
     void write(const char *pch, size_t nSize) {
         assert(nPos <= vchData.size());
         size_t nOverwrite = std::min(nSize, vchData.size() - nPos);
         if (nOverwrite) {
             memcpy(vchData.data() + nPos,
                    reinterpret_cast<const uint8_t *>(pch), nOverwrite);
         }
         if (nOverwrite < nSize) {
             vchData.insert(vchData.end(),
                            reinterpret_cast<const uint8_t *>(pch) + nOverwrite,
                            reinterpret_cast<const uint8_t *>(pch) + nSize);
         }
         nPos += nSize;
     }
     template <typename T> CVectorWriter &operator<<(const T &obj) {
         // Serialize to this stream
         ::Serialize(*this, obj);
         return (*this);
     }
     int GetVersion() const { return nVersion; }
     int GetType() const { return nType; }
     void seek(size_t nSize) {
         nPos += nSize;
         if (nPos > vchData.size()) {
             vchData.resize(nPos);
         }
     }
 
 private:
     const int nType;
     const int nVersion;
     std::vector<uint8_t> &vchData;
     size_t nPos;
 };
 
 /**
  * Minimal stream for reading from an existing vector by reference
  */
 class VectorReader {
 private:
     const int m_type;
     const int m_version;
     const std::vector<uint8_t> &m_data;
     size_t m_pos = 0;
 
 public:
     /**
      * @param[in]  type Serialization Type
      * @param[in]  version Serialization Version (including any flags)
      * @param[in]  data Referenced byte vector to overwrite/append
      * @param[in]  pos Starting position. Vector index where reads should start.
      */
     VectorReader(int type, int version, const std::vector<uint8_t> &data,
                  size_t pos)
         : m_type(type), m_version(version), m_data(data), m_pos(pos) {
         if (m_pos > m_data.size()) {
             throw std::ios_base::failure(
                 "VectorReader(...): end of data (m_pos > m_data.size())");
         }
     }
 
     /**
      * (other params same as above)
      * @param[in]  args  A list of items to deserialize starting at pos.
      */
     template <typename... Args>
     VectorReader(int type, int version, const std::vector<uint8_t> &data,
-                 size_t pos, Args &&... args)
+                 size_t pos, Args &&...args)
         : VectorReader(type, version, data, pos) {
         ::UnserializeMany(*this, std::forward<Args>(args)...);
     }
 
     template <typename T> VectorReader &operator>>(T &obj) {
         // Unserialize from this stream
         ::Unserialize(*this, obj);
         return (*this);
     }
 
     int GetVersion() const { return m_version; }
     int GetType() const { return m_type; }
 
     size_t size() const { return m_data.size() - m_pos; }
     bool empty() const { return m_data.size() == m_pos; }
 
     void read(char *dst, size_t n) {
         if (n == 0) {
             return;
         }
 
         // Read from the beginning of the buffer
         size_t pos_next = m_pos + n;
         if (pos_next > m_data.size()) {
             throw std::ios_base::failure("VectorReader::read(): end of data");
         }
         memcpy(dst, m_data.data() + m_pos, n);
         m_pos = pos_next;
     }
 };
 
 /**
  * Double ended buffer combining vector and stream-like interfaces.
  *
  * >> and << read and write unformatted data using the above serialization
  * templates. Fills with data in linear time; some stringstream implementations
  * take N^2 time.
  */
 class CDataStream {
 protected:
     typedef CSerializeData vector_type;
     vector_type vch;
     unsigned int nReadPos;
 
     int nType;
     int nVersion;
 
 public:
     typedef vector_type::allocator_type allocator_type;
     typedef vector_type::size_type size_type;
     typedef vector_type::difference_type difference_type;
     typedef vector_type::reference reference;
     typedef vector_type::const_reference const_reference;
     typedef vector_type::value_type value_type;
     typedef vector_type::iterator iterator;
     typedef vector_type::const_iterator const_iterator;
     typedef vector_type::reverse_iterator reverse_iterator;
 
     explicit CDataStream(int nTypeIn, int nVersionIn) {
         Init(nTypeIn, nVersionIn);
     }
 
     CDataStream(const_iterator pbegin, const_iterator pend, int nTypeIn,
                 int nVersionIn)
         : vch(pbegin, pend) {
         Init(nTypeIn, nVersionIn);
     }
 
     CDataStream(const char *pbegin, const char *pend, int nTypeIn,
                 int nVersionIn)
         : vch(pbegin, pend) {
         Init(nTypeIn, nVersionIn);
     }
 
     CDataStream(const vector_type &vchIn, int nTypeIn, int nVersionIn)
         : vch(vchIn.begin(), vchIn.end()) {
         Init(nTypeIn, nVersionIn);
     }
 
     CDataStream(const std::vector<char> &vchIn, int nTypeIn, int nVersionIn)
         : vch(vchIn.begin(), vchIn.end()) {
         Init(nTypeIn, nVersionIn);
     }
 
     CDataStream(const std::vector<uint8_t> &vchIn, int nTypeIn, int nVersionIn)
         : vch(vchIn.begin(), vchIn.end()) {
         Init(nTypeIn, nVersionIn);
     }
 
     template <typename... Args>
-    CDataStream(int nTypeIn, int nVersionIn, Args &&... args) {
+    CDataStream(int nTypeIn, int nVersionIn, Args &&...args) {
         Init(nTypeIn, nVersionIn);
         ::SerializeMany(*this, std::forward<Args>(args)...);
     }
 
     void Init(int nTypeIn, int nVersionIn) {
         nReadPos = 0;
         nType = nTypeIn;
         nVersion = nVersionIn;
     }
 
     CDataStream &operator+=(const CDataStream &b) {
         vch.insert(vch.end(), b.begin(), b.end());
         return *this;
     }
 
     friend CDataStream operator+(const CDataStream &a, const CDataStream &b) {
         CDataStream ret = a;
         ret += b;
         return (ret);
     }
 
     std::string str() const { return (std::string(begin(), end())); }
 
     //
     // Vector subset
     //
     const_iterator begin() const { return vch.begin() + nReadPos; }
     iterator begin() { return vch.begin() + nReadPos; }
     const_iterator end() const { return vch.end(); }
     iterator end() { return vch.end(); }
     size_type size() const { return vch.size() - nReadPos; }
     bool empty() const { return vch.size() == nReadPos; }
     void resize(size_type n, value_type c = 0) { vch.resize(n + nReadPos, c); }
     void reserve(size_type n) { vch.reserve(n + nReadPos); }
     const_reference operator[](size_type pos) const {
         return vch[pos + nReadPos];
     }
     reference operator[](size_type pos) { return vch[pos + nReadPos]; }
     void clear() {
         vch.clear();
         nReadPos = 0;
     }
     iterator insert(iterator it, const char x = char()) {
         return vch.insert(it, x);
     }
     void insert(iterator it, size_type n, const char x) {
         vch.insert(it, n, x);
     }
     value_type *data() { return vch.data() + nReadPos; }
     const value_type *data() const { return vch.data() + nReadPos; }
 
     void insert(iterator it, std::vector<char>::const_iterator first,
                 std::vector<char>::const_iterator last) {
         if (last == first) {
             return;
         }
 
         assert(last - first > 0);
         if (it == vch.begin() + nReadPos &&
             (unsigned int)(last - first) <= nReadPos) {
             // special case for inserting at the front when there's room
             nReadPos -= (last - first);
             memcpy(&vch[nReadPos], &first[0], last - first);
         } else {
             vch.insert(it, first, last);
         }
     }
 
     void insert(iterator it, const char *first, const char *last) {
         if (last == first) {
             return;
         }
 
         assert(last - first > 0);
         if (it == vch.begin() + nReadPos &&
             (unsigned int)(last - first) <= nReadPos) {
             // special case for inserting at the front when there's room
             nReadPos -= (last - first);
             memcpy(&vch[nReadPos], &first[0], last - first);
         } else {
             vch.insert(it, first, last);
         }
     }
 
     iterator erase(iterator it) {
         if (it == vch.begin() + nReadPos) {
             // special case for erasing from the front
             if (++nReadPos >= vch.size()) {
                 // whenever we reach the end, we take the opportunity to clear
                 // the buffer
                 nReadPos = 0;
                 return vch.erase(vch.begin(), vch.end());
             }
             return vch.begin() + nReadPos;
         } else {
             return vch.erase(it);
         }
     }
 
     iterator erase(iterator first, iterator last) {
         if (first == vch.begin() + nReadPos) {
             // special case for erasing from the front
             if (last == vch.end()) {
                 nReadPos = 0;
                 return vch.erase(vch.begin(), vch.end());
             } else {
                 nReadPos = (last - vch.begin());
                 return last;
             }
         } else
             return vch.erase(first, last);
     }
 
     inline void Compact() {
         vch.erase(vch.begin(), vch.begin() + nReadPos);
         nReadPos = 0;
     }
 
     bool Rewind(size_type n) {
         // Rewind by n characters if the buffer hasn't been compacted yet
         if (n > nReadPos) {
             return false;
         }
         nReadPos -= n;
         return true;
     }
 
     //
     // Stream subset
     //
     bool eof() const { return size() == 0; }
     CDataStream *rdbuf() { return this; }
     int in_avail() const { return size(); }
 
     void SetType(int n) { nType = n; }
     int GetType() const { return nType; }
     void SetVersion(int n) { nVersion = n; }
     int GetVersion() const { return nVersion; }
 
     void read(char *pch, size_t nSize) {
         if (nSize == 0) {
             return;
         }
 
         // Read from the beginning of the buffer
         unsigned int nReadPosNext = nReadPos + nSize;
         if (nReadPosNext > vch.size()) {
             throw std::ios_base::failure("CDataStream::read(): end of data");
         }
         memcpy(pch, &vch[nReadPos], nSize);
         if (nReadPosNext == vch.size()) {
             nReadPos = 0;
             vch.clear();
             return;
         }
         nReadPos = nReadPosNext;
     }
 
     void ignore(int nSize) {
         // Ignore from the beginning of the buffer
         if (nSize < 0) {
             throw std::ios_base::failure(
                 "CDataStream::ignore(): nSize negative");
         }
         unsigned int nReadPosNext = nReadPos + nSize;
         if (nReadPosNext >= vch.size()) {
             if (nReadPosNext > vch.size()) {
                 throw std::ios_base::failure(
                     "CDataStream::ignore(): end of data");
             }
             nReadPos = 0;
             vch.clear();
             return;
         }
         nReadPos = nReadPosNext;
     }
 
     void write(const char *pch, size_t nSize) {
         // Write to the end of the buffer
         vch.insert(vch.end(), pch, pch + nSize);
     }
 
     template <typename Stream> void Serialize(Stream &s) const {
         // Special case: stream << stream concatenates like stream += stream
         if (!vch.empty()) {
             s.write((char *)vch.data(), vch.size() * sizeof(value_type));
         }
     }
 
     template <typename T> CDataStream &operator<<(const T &obj) {
         // Serialize to this stream
         ::Serialize(*this, obj);
         return (*this);
     }
 
     template <typename T> CDataStream &operator>>(T &&obj) {
         // Unserialize from this stream
         ::Unserialize(*this, obj);
         return (*this);
     }
 
     void GetAndClear(CSerializeData &d) {
         d.insert(d.end(), begin(), end());
         clear();
     }
 
     /**
      * XOR the contents of this stream with a certain key.
      *
      * @param[in] key    The key used to XOR the data in this stream.
      */
     void Xor(const std::vector<uint8_t> &key) {
         if (key.size() == 0) {
             return;
         }
 
         for (size_type i = 0, j = 0; i != size(); i++) {
             vch[i] ^= key[j++];
 
             // This potentially acts on very many bytes of data, so it's
             // important that we calculate `j`, i.e. the `key` index in this way
             // instead of doing a %, which would effectively be a division for
             // each byte Xor'd -- much slower than need be.
             if (j == key.size()) j = 0;
         }
     }
 };
 
 template <typename IStream> class BitStreamReader {
 private:
     IStream &m_istream;
 
     /// Buffered byte read in from the input stream. A new byte is read into the
     /// buffer when m_offset reaches 8.
     uint8_t m_buffer{0};
 
     /// Number of high order bits in m_buffer already returned by previous
     /// Read() calls. The next bit to be returned is at this offset from the
     /// most significant bit position.
     int m_offset{8};
 
 public:
     explicit BitStreamReader(IStream &istream) : m_istream(istream) {}
 
     /**
      * Read the specified number of bits from the stream. The data is returned
      * in the nbits least significant bits of a 64-bit uint.
      */
     uint64_t Read(int nbits) {
         if (nbits < 0 || nbits > 64) {
             throw std::out_of_range("nbits must be between 0 and 64");
         }
 
         uint64_t data = 0;
         while (nbits > 0) {
             if (m_offset == 8) {
                 m_istream >> m_buffer;
                 m_offset = 0;
             }
 
             int bits = std::min(8 - m_offset, nbits);
             data <<= bits;
             data |= static_cast<uint8_t>(m_buffer << m_offset) >> (8 - bits);
             m_offset += bits;
             nbits -= bits;
         }
         return data;
     }
 };
 
 template <typename OStream> class BitStreamWriter {
 private:
     OStream &m_ostream;
 
     /// Buffered byte waiting to be written to the output stream. The byte is
     /// written buffer when m_offset reaches 8 or Flush() is called.
     uint8_t m_buffer{0};
 
     /// Number of high order bits in m_buffer already written by previous
     /// Write() calls and not yet flushed to the stream. The next bit to be
     /// written to is at this offset from the most significant bit position.
     int m_offset{0};
 
 public:
     explicit BitStreamWriter(OStream &ostream) : m_ostream(ostream) {}
 
     ~BitStreamWriter() { Flush(); }
 
     /**
      * Write the nbits least significant bits of a 64-bit int to the output
      * stream. Data is buffered until it completes an octet.
      */
     void Write(uint64_t data, int nbits) {
         if (nbits < 0 || nbits > 64) {
             throw std::out_of_range("nbits must be between 0 and 64");
         }
 
         while (nbits > 0) {
             int bits = std::min(8 - m_offset, nbits);
             m_buffer |= (data << (64 - nbits)) >> (64 - 8 + m_offset);
             m_offset += bits;
             nbits -= bits;
 
             if (m_offset == 8) {
                 Flush();
             }
         }
     }
 
     /**
      * Flush any unwritten bits to the output stream, padding with 0's to the
      * next byte boundary.
      */
     void Flush() {
         if (m_offset == 0) {
             return;
         }
 
         m_ostream << m_buffer;
         m_buffer = 0;
         m_offset = 0;
     }
 };
 
 /**
  * Non-refcounted RAII wrapper for FILE*
  *
  * Will automatically close the file when it goes out of scope if not null. If
  * you're returning the file pointer, return file.release(). If you need to
  * close the file early, use file.fclose() instead of fclose(file).
  */
 class CAutoFile {
 private:
     const int nType;
     const int nVersion;
 
     FILE *file;
 
 public:
     CAutoFile(FILE *filenew, int nTypeIn, int nVersionIn)
         : nType(nTypeIn), nVersion(nVersionIn) {
         file = filenew;
     }
 
     ~CAutoFile() { fclose(); }
 
     // Disallow copies
     CAutoFile(const CAutoFile &) = delete;
     CAutoFile &operator=(const CAutoFile &) = delete;
 
     void fclose() {
         if (file) {
             ::fclose(file);
             file = nullptr;
         }
     }
 
     /**
      * Get wrapped FILE* with transfer of ownership.
      * @note This will invalidate the CAutoFile object, and makes it the
      * responsibility of the caller of this function to clean up the returned
      * FILE*.
      */
     FILE *release() {
         FILE *ret = file;
         file = nullptr;
         return ret;
     }
 
     /**
      * Get wrapped FILE* without transfer of ownership.
      * @note Ownership of the FILE* will remain with this class. Use this only
      * if the scope of the CAutoFile outlives use of the passed pointer.
      */
     FILE *Get() const { return file; }
 
     /** Return true if the wrapped FILE* is nullptr, false otherwise. */
     bool IsNull() const { return (file == nullptr); }
 
     //
     // Stream subset
     //
     int GetType() const { return nType; }
     int GetVersion() const { return nVersion; }
 
     void read(char *pch, size_t nSize) {
         if (!file) {
             throw std::ios_base::failure(
                 "CAutoFile::read: file handle is nullptr");
         }
         if (fread(pch, 1, nSize, file) != nSize) {
             throw std::ios_base::failure(feof(file)
                                              ? "CAutoFile::read: end of file"
                                              : "CAutoFile::read: fread failed");
         }
     }
 
     void ignore(size_t nSize) {
         if (!file) {
             throw std::ios_base::failure(
                 "CAutoFile::ignore: file handle is nullptr");
         }
         uint8_t data[4096];
         while (nSize > 0) {
             size_t nNow = std::min<size_t>(nSize, sizeof(data));
             if (fread(data, 1, nNow, file) != nNow) {
                 throw std::ios_base::failure(
                     feof(file) ? "CAutoFile::ignore: end of file"
                                : "CAutoFile::read: fread failed");
             }
             nSize -= nNow;
         }
     }
 
     void write(const char *pch, size_t nSize) {
         if (!file) {
             throw std::ios_base::failure(
                 "CAutoFile::write: file handle is nullptr");
         }
         if (fwrite(pch, 1, nSize, file) != nSize) {
             throw std::ios_base::failure("CAutoFile::write: write failed");
         }
     }
 
     template <typename T> CAutoFile &operator<<(const T &obj) {
         // Serialize to this stream
         if (!file) {
             throw std::ios_base::failure(
                 "CAutoFile::operator<<: file handle is nullptr");
         }
         ::Serialize(*this, obj);
         return (*this);
     }
 
     template <typename T> CAutoFile &operator>>(T &&obj) {
         // Unserialize from this stream
         if (!file) {
             throw std::ios_base::failure(
                 "CAutoFile::operator>>: file handle is nullptr");
         }
         ::Unserialize(*this, obj);
         return (*this);
     }
 };
 
 /**
  * Non-refcounted RAII wrapper around a FILE* that implements a ring buffer to
  * deserialize from. It guarantees the ability to rewind a given number of
  * bytes.
  *
  * Will automatically close the file when it goes out of scope if not null. If
  * you need to close the file early, use file.fclose() instead of fclose(file).
  */
 class CBufferedFile {
 private:
     const int nType;
     const int nVersion;
 
     //! source file
     FILE *src;
     //! how many bytes have been read from source
     uint64_t nSrcPos;
     //! how many bytes have been read from this
     uint64_t nReadPos;
     //! up to which position we're allowed to read
     uint64_t nReadLimit;
     //! how many bytes we guarantee to rewind
     uint64_t nRewind;
     //! the buffer
     std::vector<char> vchBuf;
 
 protected:
     //! read data from the source to fill the buffer
     bool Fill() {
         unsigned int pos = nSrcPos % vchBuf.size();
         unsigned int readNow = vchBuf.size() - pos;
         unsigned int nAvail = vchBuf.size() - (nSrcPos - nReadPos) - nRewind;
         if (nAvail < readNow) {
             readNow = nAvail;
         }
         if (readNow == 0) {
             return false;
         }
         size_t nBytes = fread((void *)&vchBuf[pos], 1, readNow, src);
         if (nBytes == 0) {
             throw std::ios_base::failure(
                 feof(src) ? "CBufferedFile::Fill: end of file"
                           : "CBufferedFile::Fill: fread failed");
         }
         nSrcPos += nBytes;
         return true;
     }
 
 public:
     CBufferedFile(FILE *fileIn, uint64_t nBufSize, uint64_t nRewindIn,
                   int nTypeIn, int nVersionIn)
         : nType(nTypeIn), nVersion(nVersionIn), nSrcPos(0), nReadPos(0),
           nReadLimit(std::numeric_limits<uint64_t>::max()), nRewind(nRewindIn),
           vchBuf(nBufSize, 0) {
         if (nRewindIn >= nBufSize) {
             throw std::ios_base::failure(
                 "Rewind limit must be less than buffer size");
         }
         src = fileIn;
     }
 
     ~CBufferedFile() { fclose(); }
 
     // Disallow copies
     CBufferedFile(const CBufferedFile &) = delete;
     CBufferedFile &operator=(const CBufferedFile &) = delete;
 
     int GetVersion() const { return nVersion; }
     int GetType() const { return nType; }
 
     void fclose() {
         if (src) {
             ::fclose(src);
             src = nullptr;
         }
     }
 
     //! check whether we're at the end of the source file
     bool eof() const { return nReadPos == nSrcPos && feof(src); }
 
     //! read a number of bytes
     void read(char *pch, size_t nSize) {
         if (nSize + nReadPos > nReadLimit) {
             throw std::ios_base::failure("Read attempted past buffer limit");
         }
         while (nSize > 0) {
             if (nReadPos == nSrcPos) {
                 Fill();
             }
             unsigned int pos = nReadPos % vchBuf.size();
             size_t nNow = nSize;
             if (nNow + pos > vchBuf.size()) {
                 nNow = vchBuf.size() - pos;
             }
             if (nNow + nReadPos > nSrcPos) {
                 nNow = nSrcPos - nReadPos;
             }
             memcpy(pch, &vchBuf[pos], nNow);
             nReadPos += nNow;
             pch += nNow;
             nSize -= nNow;
         }
     }
 
     //! return the current reading position
     uint64_t GetPos() const { return nReadPos; }
 
     //! rewind to a given reading position
     bool SetPos(uint64_t nPos) {
         size_t bufsize = vchBuf.size();
         if (nPos + bufsize < nSrcPos) {
             // rewinding too far, rewind as far as possible
             nReadPos = nSrcPos - bufsize;
             return false;
         }
         if (nPos > nSrcPos) {
             // can't go this far forward, go as far as possible
             nReadPos = nSrcPos;
             return false;
         }
         nReadPos = nPos;
         return true;
     }
 
     //! Prevent reading beyond a certain position. No argument removes the
     //! limit.
     bool SetLimit(uint64_t nPos = std::numeric_limits<uint64_t>::max()) {
         if (nPos < nReadPos) {
             return false;
         }
         nReadLimit = nPos;
         return true;
     }
 
     template <typename T> CBufferedFile &operator>>(T &&obj) {
         // Unserialize from this stream
         ::Unserialize(*this, obj);
         return (*this);
     }
 
     //! search for a given byte in the stream, and remain positioned on it
     void FindByte(char ch) {
         while (true) {
             if (nReadPos == nSrcPos) {
                 Fill();
             }
             if (vchBuf[nReadPos % vchBuf.size()] == ch) {
                 break;
             }
             nReadPos++;
         }
     }
 };
 
 #endif // BITCOIN_STREAMS_H
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index 38462bfc2..8271cd6e9 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -1,940 +1,940 @@
 // Copyright (c) 2014-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.
 
 #include <coins.h>
 
 #include <attributes.h>
 #include <clientversion.h>
 #include <script/standard.h>
 #include <streams.h>
 #include <txdb.h>
 #include <undo.h>
 #include <util/strencodings.h>
 
 #include <test/util/setup_common.h>
 
 #include <boost/test/unit_test.hpp>
 
 #include <map>
 #include <vector>
 
 void UpdateCoins(CCoinsViewCache &inputs, const CTransaction &tx,
                  CTxUndo &txundo, int nHeight);
 
 namespace {
 
 //! equality test
 bool operator==(const Coin &a, const Coin &b) {
     // Empty Coin objects are always equal.
     if (a.IsSpent() && b.IsSpent()) {
         return true;
     }
 
     return a.IsCoinBase() == b.IsCoinBase() && a.GetHeight() == b.GetHeight() &&
            a.GetTxOut() == b.GetTxOut();
 }
 
 class CCoinsViewTest : public CCoinsView {
     BlockHash hashBestBlock_;
     std::map<COutPoint, Coin> map_;
 
 public:
     [[nodiscard]] bool GetCoin(const COutPoint &outpoint,
                                Coin &coin) const override {
         std::map<COutPoint, Coin>::const_iterator it = map_.find(outpoint);
         if (it == map_.end()) {
             return false;
         }
         coin = it->second;
         if (coin.IsSpent() && InsecureRandBool() == 0) {
             // Randomly return false in case of an empty entry.
             return false;
         }
         return true;
     }
 
     BlockHash GetBestBlock() const override { return hashBestBlock_; }
 
     bool BatchWrite(CCoinsMap &mapCoins, const BlockHash &hashBlock) override {
         for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
             if (it->second.flags & CCoinsCacheEntry::DIRTY) {
                 // Same optimization used in CCoinsViewDB is to only write dirty
                 // entries.
                 map_[it->first] = it->second.coin;
                 if (it->second.coin.IsSpent() && InsecureRandRange(3) == 0) {
                     // Randomly delete empty entries on write.
                     map_.erase(it->first);
                 }
             }
             mapCoins.erase(it++);
         }
         if (!hashBlock.IsNull()) {
             hashBestBlock_ = hashBlock;
         }
         return true;
     }
 };
 
 class CCoinsViewCacheTest : public CCoinsViewCache {
 public:
     explicit CCoinsViewCacheTest(CCoinsView *_base) : CCoinsViewCache(_base) {}
 
     void SelfTest() const {
         // Manually recompute the dynamic usage of the whole data, and compare
         // it.
         size_t ret = memusage::DynamicUsage(cacheCoins);
         size_t count = 0;
         for (const auto &entry : cacheCoins) {
             ret += entry.second.coin.DynamicMemoryUsage();
             count++;
         }
         BOOST_CHECK_EQUAL(GetCacheSize(), count);
         BOOST_CHECK_EQUAL(DynamicMemoryUsage(), ret);
     }
 
     CCoinsMap &map() const { return cacheCoins; }
     size_t &usage() const { return cachedCoinsUsage; }
 };
 } // namespace
 
 BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup)
 
 static const unsigned int NUM_SIMULATION_ITERATIONS = 40000;
 
 // This is a large randomized insert/remove simulation test on a variable-size
 // stack of caches on top of CCoinsViewTest.
 //
 // It will randomly create/update/delete Coin entries to a tip of caches, with
 // txids picked from a limited list of random 256-bit hashes. Occasionally, a
 // new tip is added to the stack of caches, or the tip is flushed and removed.
 //
 // During the process, booleans are kept to make sure that the randomized
 // operation hits all branches.
 //
 // If fake_best_block is true, assign a random BlockHash to mock the recording
 // of best block on flush. This is necessary when using CCoinsViewDB as the
 // base, otherwise we'll hit an assertion in BatchWrite.
 //
 void SimulationTest(CCoinsView *base, bool fake_best_block) {
     // Various coverage trackers.
     bool removed_all_caches = false;
     bool reached_4_caches = false;
     bool added_an_entry = false;
     bool added_an_unspendable_entry = false;
     bool removed_an_entry = false;
     bool updated_an_entry = false;
     bool found_an_entry = false;
     bool missed_an_entry = false;
     bool uncached_an_entry = false;
 
     // A simple map to track what we expect the cache stack to represent.
     std::map<COutPoint, Coin> result;
 
     // The cache stack.
     // A stack of CCoinsViewCaches on top.
     std::vector<CCoinsViewCacheTest *> stack;
     // Start with one cache.
     stack.push_back(new CCoinsViewCacheTest(base));
 
     // Use a limited set of random transaction ids, so we do test overwriting
     // entries.
     std::vector<TxId> txids;
     txids.resize(NUM_SIMULATION_ITERATIONS / 8);
     for (size_t i = 0; i < txids.size(); i++) {
         txids[i] = TxId(InsecureRand256());
     }
 
     for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) {
         // Do a random modification.
         {
             // txid we're going to modify in this iteration.
             const TxId txid = txids[InsecureRandRange(txids.size())];
             Coin &coin = result[COutPoint(txid, 0)];
             // Determine whether to test HaveCoin before or after Access* (or
             // both). As these functions can influence each other's behaviour by
             // pulling things into the cache, all combinations are tested.
             bool test_havecoin_before = InsecureRandBits(2) == 0;
             bool test_havecoin_after = InsecureRandBits(2) == 0;
 
             bool result_havecoin =
                 test_havecoin_before
                     ? stack.back()->HaveCoin(COutPoint(txid, 0))
                     : false;
             const Coin &entry =
                 (InsecureRandRange(500) == 0)
                     ? AccessByTxid(*stack.back(), txid)
                     : stack.back()->AccessCoin(COutPoint(txid, 0));
             BOOST_CHECK(coin == entry);
             BOOST_CHECK(!test_havecoin_before ||
                         result_havecoin == !entry.IsSpent());
 
             if (test_havecoin_after) {
                 bool ret = stack.back()->HaveCoin(COutPoint(txid, 0));
                 BOOST_CHECK(ret == !entry.IsSpent());
             }
 
             if (InsecureRandRange(5) == 0 || coin.IsSpent()) {
                 CTxOut txout;
                 txout.nValue = int64_t(InsecureRand32()) * SATOSHI;
                 if (InsecureRandRange(16) == 0 && coin.IsSpent()) {
                     txout.scriptPubKey.assign(1 + InsecureRandBits(6),
                                               OP_RETURN);
                     BOOST_CHECK(txout.scriptPubKey.IsUnspendable());
                     added_an_unspendable_entry = true;
                 } else {
                     // Random sizes so we can test memory usage accounting
                     txout.scriptPubKey.assign(InsecureRandBits(6), 0);
                     (coin.IsSpent() ? added_an_entry : updated_an_entry) = true;
                     coin = Coin(txout, 1, false);
                 }
 
                 Coin newcoin(txout, 1, false);
                 stack.back()->AddCoin(COutPoint(txid, 0), newcoin,
                                       !coin.IsSpent() || InsecureRand32() & 1);
             } else {
                 removed_an_entry = true;
                 coin.Clear();
                 BOOST_CHECK(stack.back()->SpendCoin(COutPoint(txid, 0)));
             }
         }
 
         // One every 10 iterations, remove a random entry from the cache
         if (InsecureRandRange(10) == 0) {
             COutPoint out(txids[InsecureRand32() % txids.size()], 0);
             int cacheid = InsecureRand32() % stack.size();
             stack[cacheid]->Uncache(out);
             uncached_an_entry |= !stack[cacheid]->HaveCoinInCache(out);
         }
 
         // Once every 1000 iterations and at the end, verify the full cache.
         if (InsecureRandRange(1000) == 1 ||
             i == NUM_SIMULATION_ITERATIONS - 1) {
             for (const auto &entry : result) {
                 bool have = stack.back()->HaveCoin(entry.first);
                 const Coin &coin = stack.back()->AccessCoin(entry.first);
                 BOOST_CHECK(have == !coin.IsSpent());
                 BOOST_CHECK(coin == entry.second);
                 if (coin.IsSpent()) {
                     missed_an_entry = true;
                 } else {
                     BOOST_CHECK(stack.back()->HaveCoinInCache(entry.first));
                     found_an_entry = true;
                 }
             }
             for (const CCoinsViewCacheTest *test : stack) {
                 test->SelfTest();
             }
         }
 
         // Every 100 iterations, flush an intermediate cache
         if (InsecureRandRange(100) == 0) {
             if (stack.size() > 1 && InsecureRandBool() == 0) {
                 unsigned int flushIndex = InsecureRandRange(stack.size() - 1);
                 if (fake_best_block) {
                     stack[flushIndex]->SetBestBlock(
                         BlockHash(InsecureRand256()));
                 }
                 BOOST_CHECK(stack[flushIndex]->Flush());
             }
         }
         if (InsecureRandRange(100) == 0) {
             // Every 100 iterations, change the cache stack.
             if (stack.size() > 0 && InsecureRandBool() == 0) {
                 // Remove the top cache
                 if (fake_best_block) {
                     stack.back()->SetBestBlock(BlockHash(InsecureRand256()));
                 }
                 BOOST_CHECK(stack.back()->Flush());
                 delete stack.back();
                 stack.pop_back();
             }
             if (stack.size() == 0 || (stack.size() < 4 && InsecureRandBool())) {
                 // Add a new cache
                 CCoinsView *tip = base;
                 if (stack.size() > 0) {
                     tip = stack.back();
                 } else {
                     removed_all_caches = true;
                 }
                 stack.push_back(new CCoinsViewCacheTest(tip));
                 if (stack.size() == 4) {
                     reached_4_caches = true;
                 }
             }
         }
     }
 
     // Clean up the stack.
     while (stack.size() > 0) {
         delete stack.back();
         stack.pop_back();
     }
 
     // Verify coverage.
     BOOST_CHECK(removed_all_caches);
     BOOST_CHECK(reached_4_caches);
     BOOST_CHECK(added_an_entry);
     BOOST_CHECK(added_an_unspendable_entry);
     BOOST_CHECK(removed_an_entry);
     BOOST_CHECK(updated_an_entry);
     BOOST_CHECK(found_an_entry);
     BOOST_CHECK(missed_an_entry);
     BOOST_CHECK(uncached_an_entry);
 }
 
 // Run the above simulation for multiple base types.
 BOOST_AUTO_TEST_CASE(coins_cache_simulation_test) {
     CCoinsViewTest base;
     SimulationTest(&base, false);
 
     CCoinsViewDB db_base{"test", /*nCacheSize*/ 1 << 23, /*fMemory*/ true,
                          /*fWipe*/ false};
     SimulationTest(&db_base, true);
 }
 
 // Store of all necessary tx and undo data for next test
 typedef std::map<COutPoint, std::tuple<CTransaction, CTxUndo, Coin>> UtxoData;
 UtxoData utxoData;
 
 UtxoData::iterator FindRandomFrom(const std::set<COutPoint> &utxoSet) {
     assert(utxoSet.size());
     auto utxoSetIt = utxoSet.lower_bound(COutPoint(TxId(InsecureRand256()), 0));
     if (utxoSetIt == utxoSet.end()) {
         utxoSetIt = utxoSet.begin();
     }
     auto utxoDataIt = utxoData.find(*utxoSetIt);
     assert(utxoDataIt != utxoData.end());
     return utxoDataIt;
 }
 
 // This test is similar to the previous test except the emphasis is on testing
 // the functionality of UpdateCoins random txs are created and UpdateCoins is
 // used to update the cache stack. In particular it is tested that spending a
 // duplicate coinbase tx has the expected effect (the other duplicate is
 // overwritten at all cache levels)
 BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) {
     SeedInsecureRand(SeedRand::ZEROS);
     g_mock_deterministic_tests = true;
 
     bool spent_a_duplicate_coinbase = false;
     // A simple map to track what we expect the cache stack to represent.
     std::map<COutPoint, Coin> result;
 
     // The cache stack.
     // A CCoinsViewTest at the bottom.
     CCoinsViewTest base;
     // A stack of CCoinsViewCaches on top.
     std::vector<CCoinsViewCacheTest *> stack;
     // Start with one cache.
     stack.push_back(new CCoinsViewCacheTest(&base));
 
     // Track the txids we've used in various sets
     std::set<COutPoint> coinbase_coins;
     std::set<COutPoint> disconnected_coins;
     std::set<COutPoint> duplicate_coins;
     std::set<COutPoint> utxoset;
 
     for (int64_t i = 0; i < NUM_SIMULATION_ITERATIONS; i++) {
         uint32_t randiter = InsecureRand32();
 
         // 19/20 txs add a new transaction
         if (randiter % 20 < 19) {
             CMutableTransaction tx;
             tx.vin.resize(1);
             tx.vout.resize(1);
             // Keep txs unique unless intended to duplicate.
             tx.vout[0].nValue = i * SATOSHI;
             // Random sizes so we can test memory usage accounting
             tx.vout[0].scriptPubKey.assign(InsecureRand32() & 0x3F, 0);
             unsigned int height = InsecureRand32();
             Coin old_coin;
 
             // 2/20 times create a new coinbase
             if (randiter % 20 < 2 || coinbase_coins.size() < 10) {
                 // 1/10 of those times create a duplicate coinbase
                 if (InsecureRandRange(10) == 0 && coinbase_coins.size()) {
                     auto utxod = FindRandomFrom(coinbase_coins);
                     // Reuse the exact same coinbase
                     tx = CMutableTransaction{std::get<0>(utxod->second)};
                     // shouldn't be available for reconnection if it's been
                     // duplicated
                     disconnected_coins.erase(utxod->first);
 
                     duplicate_coins.insert(utxod->first);
                 } else {
                     coinbase_coins.insert(COutPoint(tx.GetId(), 0));
                 }
                 assert(CTransaction(tx).IsCoinBase());
             }
 
             // 17/20 times reconnect previous or add a regular tx
             else {
                 COutPoint prevout;
                 // 1/20 times reconnect a previously disconnected tx
                 if (randiter % 20 == 2 && disconnected_coins.size()) {
                     auto utxod = FindRandomFrom(disconnected_coins);
                     tx = CMutableTransaction{std::get<0>(utxod->second)};
                     prevout = tx.vin[0].prevout;
                     if (!CTransaction(tx).IsCoinBase() &&
                         !utxoset.count(prevout)) {
                         disconnected_coins.erase(utxod->first);
                         continue;
                     }
 
                     // If this tx is already IN the UTXO, then it must be a
                     // coinbase, and it must be a duplicate
                     if (utxoset.count(utxod->first)) {
                         assert(CTransaction(tx).IsCoinBase());
                         assert(duplicate_coins.count(utxod->first));
                     }
                     disconnected_coins.erase(utxod->first);
                 }
 
                 // 16/20 times create a regular tx
                 else {
                     auto utxod = FindRandomFrom(utxoset);
                     prevout = utxod->first;
 
                     // Construct the tx to spend the coins of prevouthash
                     tx.vin[0].prevout = COutPoint(prevout.GetTxId(), 0);
                     assert(!CTransaction(tx).IsCoinBase());
                 }
 
                 // In this simple test coins only have two states, spent or
                 // unspent, save the unspent state to restore
                 old_coin = result[prevout];
                 // Update the expected result of prevouthash to know these coins
                 // are spent
                 result[prevout].Clear();
 
                 utxoset.erase(prevout);
 
                 // The test is designed to ensure spending a duplicate coinbase
                 // will work properly if that ever happens and not resurrect the
                 // previously overwritten coinbase
                 if (duplicate_coins.count(prevout)) {
                     spent_a_duplicate_coinbase = true;
                 }
             }
             // Update the expected result to know about the new output coins
             assert(tx.vout.size() == 1);
             const COutPoint outpoint(tx.GetId(), 0);
             result[outpoint] =
                 Coin(tx.vout[0], height, CTransaction(tx).IsCoinBase());
 
             // Call UpdateCoins on the top cache
             CTxUndo undo;
             UpdateCoins(*(stack.back()), CTransaction(tx), undo, height);
 
             // Update the utxo set for future spends
             utxoset.insert(outpoint);
 
             // Track this tx and undo info to use later
             utxoData.emplace(outpoint,
                              std::make_tuple(CTransaction(tx), undo, old_coin));
         }
 
         // 1/20 times undo a previous transaction
         else if (utxoset.size()) {
             auto utxod = FindRandomFrom(utxoset);
 
             CTransaction &tx = std::get<0>(utxod->second);
             CTxUndo &undo = std::get<1>(utxod->second);
             Coin &orig_coin = std::get<2>(utxod->second);
 
             // Update the expected result
             // Remove new outputs
             result[utxod->first].Clear();
             // If not coinbase restore prevout
             if (!tx.IsCoinBase()) {
                 result[tx.vin[0].prevout] = orig_coin;
             }
 
             // Disconnect the tx from the current UTXO
             // See code in DisconnectBlock
             // remove outputs
             BOOST_CHECK(stack.back()->SpendCoin(utxod->first));
 
             // restore inputs
             if (!tx.IsCoinBase()) {
                 const COutPoint &out = tx.vin[0].prevout;
                 UndoCoinSpend(undo.vprevout[0], *(stack.back()), out);
             }
 
             // Store as a candidate for reconnection
             disconnected_coins.insert(utxod->first);
 
             // Update the utxoset
             utxoset.erase(utxod->first);
             if (!tx.IsCoinBase()) {
                 utxoset.insert(tx.vin[0].prevout);
             }
         }
 
         // Once every 1000 iterations and at the end, verify the full cache.
         if (InsecureRandRange(1000) == 1 ||
             i == NUM_SIMULATION_ITERATIONS - 1) {
             for (const auto &entry : result) {
                 bool have = stack.back()->HaveCoin(entry.first);
                 const Coin &coin = stack.back()->AccessCoin(entry.first);
                 BOOST_CHECK(have == !coin.IsSpent());
                 BOOST_CHECK(coin == entry.second);
             }
         }
 
         // One every 10 iterations, remove a random entry from the cache
         if (utxoset.size() > 1 && InsecureRandRange(30) == 0) {
             stack[InsecureRand32() % stack.size()]->Uncache(
                 FindRandomFrom(utxoset)->first);
         }
         if (disconnected_coins.size() > 1 && InsecureRandRange(30) == 0) {
             stack[InsecureRand32() % stack.size()]->Uncache(
                 FindRandomFrom(disconnected_coins)->first);
         }
         if (duplicate_coins.size() > 1 && InsecureRandRange(30) == 0) {
             stack[InsecureRand32() % stack.size()]->Uncache(
                 FindRandomFrom(duplicate_coins)->first);
         }
 
         if (InsecureRandRange(100) == 0) {
             // Every 100 iterations, flush an intermediate cache
             if (stack.size() > 1 && InsecureRandBool() == 0) {
                 unsigned int flushIndex = InsecureRandRange(stack.size() - 1);
                 BOOST_CHECK(stack[flushIndex]->Flush());
             }
         }
         if (InsecureRandRange(100) == 0) {
             // Every 100 iterations, change the cache stack.
             if (stack.size() > 0 && InsecureRandBool() == 0) {
                 BOOST_CHECK(stack.back()->Flush());
                 delete stack.back();
                 stack.pop_back();
             }
             if (stack.size() == 0 || (stack.size() < 4 && InsecureRandBool())) {
                 CCoinsView *tip = &base;
                 if (stack.size() > 0) {
                     tip = stack.back();
                 }
                 stack.push_back(new CCoinsViewCacheTest(tip));
             }
         }
     }
 
     // Clean up the stack.
     while (stack.size() > 0) {
         delete stack.back();
         stack.pop_back();
     }
 
     // Verify coverage.
     BOOST_CHECK(spent_a_duplicate_coinbase);
 
     g_mock_deterministic_tests = false;
 }
 
 BOOST_AUTO_TEST_CASE(coin_serialization) {
     // Good example
     CDataStream ss1(
         ParseHex("97f23c835800816115944e077fe7c803cfa57f29b36bf87c1d35"),
         SER_DISK, CLIENT_VERSION);
     Coin c1;
     ss1 >> c1;
     BOOST_CHECK_EQUAL(c1.IsCoinBase(), false);
     BOOST_CHECK_EQUAL(c1.GetHeight(), 203998U);
     BOOST_CHECK_EQUAL(c1.GetTxOut().nValue, int64_t(60000000000) * SATOSHI);
     BOOST_CHECK_EQUAL(HexStr(c1.GetTxOut().scriptPubKey),
                       HexStr(GetScriptForDestination(PKHash(uint160(ParseHex(
                           "816115944e077fe7c803cfa57f29b36bf87c1d35"))))));
 
     // Good example
     CDataStream ss2(
         ParseHex("8ddf77bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4"),
         SER_DISK, CLIENT_VERSION);
     Coin c2;
     ss2 >> c2;
     BOOST_CHECK_EQUAL(c2.IsCoinBase(), true);
     BOOST_CHECK_EQUAL(c2.GetHeight(), 120891U);
     BOOST_CHECK_EQUAL(c2.GetTxOut().nValue, 110397 * SATOSHI);
     BOOST_CHECK_EQUAL(HexStr(c2.GetTxOut().scriptPubKey),
                       HexStr(GetScriptForDestination(PKHash(uint160(ParseHex(
                           "8c988f1a4a4de2161e0f50aac7f17e7f9555caa4"))))));
 
     // Smallest possible example
     CDataStream ss3(ParseHex("000006"), SER_DISK, CLIENT_VERSION);
     Coin c3;
     ss3 >> c3;
     BOOST_CHECK_EQUAL(c3.IsCoinBase(), false);
     BOOST_CHECK_EQUAL(c3.GetHeight(), 0U);
     BOOST_CHECK_EQUAL(c3.GetTxOut().nValue, Amount::zero());
     BOOST_CHECK_EQUAL(c3.GetTxOut().scriptPubKey.size(), 0U);
 
     // scriptPubKey that ends beyond the end of the stream
     CDataStream ss4(ParseHex("000007"), SER_DISK, CLIENT_VERSION);
     try {
         Coin c4;
         ss4 >> c4;
         BOOST_CHECK_MESSAGE(false, "We should have thrown");
     } catch (const std::ios_base::failure &) {
     }
 
     // Very large scriptPubKey (3*10^9 bytes) past the end of the stream
     CDataStream tmp(SER_DISK, CLIENT_VERSION);
     uint64_t x = 3000000000ULL;
     tmp << VARINT(x);
     BOOST_CHECK_EQUAL(HexStr(tmp), "8a95c0bb00");
     CDataStream ss5(ParseHex("00008a95c0bb00"), SER_DISK, CLIENT_VERSION);
     try {
         Coin c5;
         ss5 >> c5;
         BOOST_CHECK_MESSAGE(false, "We should have thrown");
     } catch (const std::ios_base::failure &) {
     }
 }
 
 static const COutPoint OUTPOINT;
 static const Amount SPENT(-1 * SATOSHI);
 static const Amount ABSENT(-2 * SATOSHI);
 static const Amount FAIL(-3 * SATOSHI);
 static const Amount VALUE1(100 * SATOSHI);
 static const Amount VALUE2(200 * SATOSHI);
 static const Amount VALUE3(300 * SATOSHI);
 static const char DIRTY = CCoinsCacheEntry::DIRTY;
 static const char FRESH = CCoinsCacheEntry::FRESH;
 static const char NO_ENTRY = -1;
 
 static const auto FLAGS = {char(0), FRESH, DIRTY, char(DIRTY | FRESH)};
 static const auto CLEAN_FLAGS = {char(0), FRESH};
 static const auto ABSENT_FLAGS = {NO_ENTRY};
 
 static void SetCoinValue(const Amount value, Coin &coin) {
     assert(value != ABSENT);
     coin.Clear();
     assert(coin.IsSpent());
     if (value != SPENT) {
         CTxOut out;
         out.nValue = value;
         coin = Coin(std::move(out), 1, false);
         assert(!coin.IsSpent());
     }
 }
 
 static size_t InsertCoinMapEntry(CCoinsMap &map, const Amount value,
                                  char flags) {
     if (value == ABSENT) {
         assert(flags == NO_ENTRY);
         return 0;
     }
     assert(flags != NO_ENTRY);
     CCoinsCacheEntry entry;
     entry.flags = flags;
     SetCoinValue(value, entry.coin);
     auto inserted = map.emplace(OUTPOINT, std::move(entry));
     assert(inserted.second);
     return inserted.first->second.coin.DynamicMemoryUsage();
 }
 
 void GetCoinMapEntry(const CCoinsMap &map, Amount &value, char &flags) {
     auto it = map.find(OUTPOINT);
     if (it == map.end()) {
         value = ABSENT;
         flags = NO_ENTRY;
     } else {
         if (it->second.coin.IsSpent()) {
             value = SPENT;
         } else {
             value = it->second.coin.GetTxOut().nValue;
         }
         flags = it->second.flags;
         assert(flags != NO_ENTRY);
     }
 }
 
 void WriteCoinViewEntry(CCoinsView &view, const Amount value, char flags) {
     CCoinsMap map;
     InsertCoinMapEntry(map, value, flags);
     BOOST_CHECK(view.BatchWrite(map, BlockHash()));
 }
 
 class SingleEntryCacheTest {
 public:
     SingleEntryCacheTest(const Amount base_value, const Amount cache_value,
                          char cache_flags) {
         WriteCoinViewEntry(base, base_value,
                            base_value == ABSENT ? NO_ENTRY : DIRTY);
         cache.usage() +=
             InsertCoinMapEntry(cache.map(), cache_value, cache_flags);
     }
 
     CCoinsView root;
     CCoinsViewCacheTest base{&root};
     CCoinsViewCacheTest cache{&base};
 };
 
 static void CheckAccessCoin(const Amount base_value, const Amount cache_value,
                             const Amount expected_value, char cache_flags,
                             char expected_flags) {
     SingleEntryCacheTest test(base_value, cache_value, cache_flags);
     test.cache.AccessCoin(OUTPOINT);
     test.cache.SelfTest();
 
     Amount result_value;
     char result_flags;
     GetCoinMapEntry(test.cache.map(), result_value, result_flags);
     BOOST_CHECK_EQUAL(result_value, expected_value);
     BOOST_CHECK_EQUAL(result_flags, expected_flags);
 }
 
 BOOST_AUTO_TEST_CASE(coin_access) {
     /* Check AccessCoin behavior, requesting a coin from a cache view layered on
      * top of a base view, and checking the resulting entry in the cache after
      * the access.
      *
      *               Base    Cache   Result  Cache        Result
      *               Value   Value   Value   Flags        Flags
      */
     CheckAccessCoin(ABSENT, ABSENT, ABSENT, NO_ENTRY, NO_ENTRY);
     CheckAccessCoin(ABSENT, SPENT, SPENT, 0, 0);
     CheckAccessCoin(ABSENT, SPENT, SPENT, FRESH, FRESH);
     CheckAccessCoin(ABSENT, SPENT, SPENT, DIRTY, DIRTY);
     CheckAccessCoin(ABSENT, SPENT, SPENT, DIRTY | FRESH, DIRTY | FRESH);
     CheckAccessCoin(ABSENT, VALUE2, VALUE2, 0, 0);
     CheckAccessCoin(ABSENT, VALUE2, VALUE2, FRESH, FRESH);
     CheckAccessCoin(ABSENT, VALUE2, VALUE2, DIRTY, DIRTY);
     CheckAccessCoin(ABSENT, VALUE2, VALUE2, DIRTY | FRESH, DIRTY | FRESH);
     CheckAccessCoin(SPENT, ABSENT, ABSENT, NO_ENTRY, NO_ENTRY);
     CheckAccessCoin(SPENT, SPENT, SPENT, 0, 0);
     CheckAccessCoin(SPENT, SPENT, SPENT, FRESH, FRESH);
     CheckAccessCoin(SPENT, SPENT, SPENT, DIRTY, DIRTY);
     CheckAccessCoin(SPENT, SPENT, SPENT, DIRTY | FRESH, DIRTY | FRESH);
     CheckAccessCoin(SPENT, VALUE2, VALUE2, 0, 0);
     CheckAccessCoin(SPENT, VALUE2, VALUE2, FRESH, FRESH);
     CheckAccessCoin(SPENT, VALUE2, VALUE2, DIRTY, DIRTY);
     CheckAccessCoin(SPENT, VALUE2, VALUE2, DIRTY | FRESH, DIRTY | FRESH);
     CheckAccessCoin(VALUE1, ABSENT, VALUE1, NO_ENTRY, 0);
     CheckAccessCoin(VALUE1, SPENT, SPENT, 0, 0);
     CheckAccessCoin(VALUE1, SPENT, SPENT, FRESH, FRESH);
     CheckAccessCoin(VALUE1, SPENT, SPENT, DIRTY, DIRTY);
     CheckAccessCoin(VALUE1, SPENT, SPENT, DIRTY | FRESH, DIRTY | FRESH);
     CheckAccessCoin(VALUE1, VALUE2, VALUE2, 0, 0);
     CheckAccessCoin(VALUE1, VALUE2, VALUE2, FRESH, FRESH);
     CheckAccessCoin(VALUE1, VALUE2, VALUE2, DIRTY, DIRTY);
     CheckAccessCoin(VALUE1, VALUE2, VALUE2, DIRTY | FRESH, DIRTY | FRESH);
 }
 
 static void CheckSpendCoin(Amount base_value, Amount cache_value,
                            Amount expected_value, char cache_flags,
                            char expected_flags) {
     SingleEntryCacheTest test(base_value, cache_value, cache_flags);
     test.cache.SpendCoin(OUTPOINT);
     test.cache.SelfTest();
 
     Amount result_value;
     char result_flags;
     GetCoinMapEntry(test.cache.map(), result_value, result_flags);
     BOOST_CHECK_EQUAL(result_value, expected_value);
     BOOST_CHECK_EQUAL(result_flags, expected_flags);
 };
 
 BOOST_AUTO_TEST_CASE(coin_spend) {
     /**
      * Check SpendCoin behavior, requesting a coin from a cache view layered on
      * top of a base view, spending, and then checking the resulting entry in
      * the cache after the modification.
      *
      *              Base    Cache   Result  Cache        Result
      *              Value   Value   Value   Flags        Flags
      */
     CheckSpendCoin(ABSENT, ABSENT, ABSENT, NO_ENTRY, NO_ENTRY);
     CheckSpendCoin(ABSENT, SPENT, SPENT, 0, DIRTY);
     CheckSpendCoin(ABSENT, SPENT, ABSENT, FRESH, NO_ENTRY);
     CheckSpendCoin(ABSENT, SPENT, SPENT, DIRTY, DIRTY);
     CheckSpendCoin(ABSENT, SPENT, ABSENT, DIRTY | FRESH, NO_ENTRY);
     CheckSpendCoin(ABSENT, VALUE2, SPENT, 0, DIRTY);
     CheckSpendCoin(ABSENT, VALUE2, ABSENT, FRESH, NO_ENTRY);
     CheckSpendCoin(ABSENT, VALUE2, SPENT, DIRTY, DIRTY);
     CheckSpendCoin(ABSENT, VALUE2, ABSENT, DIRTY | FRESH, NO_ENTRY);
     CheckSpendCoin(SPENT, ABSENT, ABSENT, NO_ENTRY, NO_ENTRY);
     CheckSpendCoin(SPENT, SPENT, SPENT, 0, DIRTY);
     CheckSpendCoin(SPENT, SPENT, ABSENT, FRESH, NO_ENTRY);
     CheckSpendCoin(SPENT, SPENT, SPENT, DIRTY, DIRTY);
     CheckSpendCoin(SPENT, SPENT, ABSENT, DIRTY | FRESH, NO_ENTRY);
     CheckSpendCoin(SPENT, VALUE2, SPENT, 0, DIRTY);
     CheckSpendCoin(SPENT, VALUE2, ABSENT, FRESH, NO_ENTRY);
     CheckSpendCoin(SPENT, VALUE2, SPENT, DIRTY, DIRTY);
     CheckSpendCoin(SPENT, VALUE2, ABSENT, DIRTY | FRESH, NO_ENTRY);
     CheckSpendCoin(VALUE1, ABSENT, SPENT, NO_ENTRY, DIRTY);
     CheckSpendCoin(VALUE1, SPENT, SPENT, 0, DIRTY);
     CheckSpendCoin(VALUE1, SPENT, ABSENT, FRESH, NO_ENTRY);
     CheckSpendCoin(VALUE1, SPENT, SPENT, DIRTY, DIRTY);
     CheckSpendCoin(VALUE1, SPENT, ABSENT, DIRTY | FRESH, NO_ENTRY);
     CheckSpendCoin(VALUE1, VALUE2, SPENT, 0, DIRTY);
     CheckSpendCoin(VALUE1, VALUE2, ABSENT, FRESH, NO_ENTRY);
     CheckSpendCoin(VALUE1, VALUE2, SPENT, DIRTY, DIRTY);
     CheckSpendCoin(VALUE1, VALUE2, ABSENT, DIRTY | FRESH, NO_ENTRY);
 }
 
 static void CheckAddCoinBase(Amount base_value, Amount cache_value,
                              Amount modify_value, Amount expected_value,
                              char cache_flags, char expected_flags,
                              bool coinbase) {
     SingleEntryCacheTest test(base_value, cache_value, cache_flags);
 
     Amount result_value;
     char result_flags;
     try {
         CTxOut output;
         output.nValue = modify_value;
         test.cache.AddCoin(OUTPOINT, Coin(std::move(output), 1, coinbase),
                            coinbase);
         test.cache.SelfTest();
         GetCoinMapEntry(test.cache.map(), result_value, result_flags);
     } catch (std::logic_error &) {
         result_value = FAIL;
         result_flags = NO_ENTRY;
     }
 
     BOOST_CHECK_EQUAL(result_value, expected_value);
     BOOST_CHECK_EQUAL(result_flags, expected_flags);
 }
 
 // Simple wrapper for CheckAddCoinBase function above that loops through
 // different possible base_values, making sure each one gives the same results.
 // This wrapper lets the coin_add test below be shorter and less repetitive,
 // while still verifying that the CoinsViewCache::AddCoin implementation ignores
 // base values.
-template <typename... Args> static void CheckAddCoin(Args &&... args) {
+template <typename... Args> static void CheckAddCoin(Args &&...args) {
     for (const Amount &base_value : {ABSENT, SPENT, VALUE1}) {
         CheckAddCoinBase(base_value, std::forward<Args>(args)...);
     }
 }
 
 BOOST_AUTO_TEST_CASE(coin_add) {
     /**
      * Check AddCoin behavior, requesting a new coin from a cache view, writing
      * a modification to the coin, and then checking the resulting entry in the
      * cache after the modification. Verify behavior with the AddCoin
      * possible_overwrite argument set to false, and to true.
      *
      * Cache   Write   Result  Cache        Result       possible_overwrite
      * Value   Value   Value   Flags        Flags
      */
     CheckAddCoin(ABSENT, VALUE3, VALUE3, NO_ENTRY, DIRTY | FRESH, false);
     CheckAddCoin(ABSENT, VALUE3, VALUE3, NO_ENTRY, DIRTY, true);
     CheckAddCoin(SPENT, VALUE3, VALUE3, 0, DIRTY | FRESH, false);
     CheckAddCoin(SPENT, VALUE3, VALUE3, 0, DIRTY, true);
     CheckAddCoin(SPENT, VALUE3, VALUE3, FRESH, DIRTY | FRESH, false);
     CheckAddCoin(SPENT, VALUE3, VALUE3, FRESH, DIRTY | FRESH, true);
     CheckAddCoin(SPENT, VALUE3, VALUE3, DIRTY, DIRTY, false);
     CheckAddCoin(SPENT, VALUE3, VALUE3, DIRTY, DIRTY, true);
     CheckAddCoin(SPENT, VALUE3, VALUE3, DIRTY | FRESH, DIRTY | FRESH, false);
     CheckAddCoin(SPENT, VALUE3, VALUE3, DIRTY | FRESH, DIRTY | FRESH, true);
     CheckAddCoin(VALUE2, VALUE3, FAIL, 0, NO_ENTRY, false);
     CheckAddCoin(VALUE2, VALUE3, VALUE3, 0, DIRTY, true);
     CheckAddCoin(VALUE2, VALUE3, FAIL, FRESH, NO_ENTRY, false);
     CheckAddCoin(VALUE2, VALUE3, VALUE3, FRESH, DIRTY | FRESH, true);
     CheckAddCoin(VALUE2, VALUE3, FAIL, DIRTY, NO_ENTRY, false);
     CheckAddCoin(VALUE2, VALUE3, VALUE3, DIRTY, DIRTY, true);
     CheckAddCoin(VALUE2, VALUE3, FAIL, DIRTY | FRESH, NO_ENTRY, false);
     CheckAddCoin(VALUE2, VALUE3, VALUE3, DIRTY | FRESH, DIRTY | FRESH, true);
 }
 
 void CheckWriteCoin(Amount parent_value, Amount child_value,
                     Amount expected_value, char parent_flags, char child_flags,
                     char expected_flags) {
     SingleEntryCacheTest test(ABSENT, parent_value, parent_flags);
 
     Amount result_value;
     char result_flags;
     try {
         WriteCoinViewEntry(test.cache, child_value, child_flags);
         test.cache.SelfTest();
         GetCoinMapEntry(test.cache.map(), result_value, result_flags);
     } catch (std::logic_error &) {
         result_value = FAIL;
         result_flags = NO_ENTRY;
     }
 
     BOOST_CHECK_EQUAL(result_value, expected_value);
     BOOST_CHECK_EQUAL(result_flags, expected_flags);
 }
 
 BOOST_AUTO_TEST_CASE(coin_write) {
     /* Check BatchWrite behavior, flushing one entry from a child cache to a
      * parent cache, and checking the resulting entry in the parent cache
      * after the write.
      *
      *              Parent  Child   Result  Parent       Child        Result
      *              Value   Value   Value   Flags        Flags        Flags
      */
     CheckWriteCoin(ABSENT, ABSENT, ABSENT, NO_ENTRY, NO_ENTRY, NO_ENTRY);
     CheckWriteCoin(ABSENT, SPENT, SPENT, NO_ENTRY, DIRTY, DIRTY);
     CheckWriteCoin(ABSENT, SPENT, ABSENT, NO_ENTRY, DIRTY | FRESH, NO_ENTRY);
     CheckWriteCoin(ABSENT, VALUE2, VALUE2, NO_ENTRY, DIRTY, DIRTY);
     CheckWriteCoin(ABSENT, VALUE2, VALUE2, NO_ENTRY, DIRTY | FRESH,
                    DIRTY | FRESH);
     CheckWriteCoin(SPENT, ABSENT, SPENT, 0, NO_ENTRY, 0);
     CheckWriteCoin(SPENT, ABSENT, SPENT, FRESH, NO_ENTRY, FRESH);
     CheckWriteCoin(SPENT, ABSENT, SPENT, DIRTY, NO_ENTRY, DIRTY);
     CheckWriteCoin(SPENT, ABSENT, SPENT, DIRTY | FRESH, NO_ENTRY,
                    DIRTY | FRESH);
     CheckWriteCoin(SPENT, SPENT, SPENT, 0, DIRTY, DIRTY);
     CheckWriteCoin(SPENT, SPENT, SPENT, 0, DIRTY | FRESH, DIRTY);
     CheckWriteCoin(SPENT, SPENT, ABSENT, FRESH, DIRTY, NO_ENTRY);
     CheckWriteCoin(SPENT, SPENT, ABSENT, FRESH, DIRTY | FRESH, NO_ENTRY);
     CheckWriteCoin(SPENT, SPENT, SPENT, DIRTY, DIRTY, DIRTY);
     CheckWriteCoin(SPENT, SPENT, SPENT, DIRTY, DIRTY | FRESH, DIRTY);
     CheckWriteCoin(SPENT, SPENT, ABSENT, DIRTY | FRESH, DIRTY, NO_ENTRY);
     CheckWriteCoin(SPENT, SPENT, ABSENT, DIRTY | FRESH, DIRTY | FRESH,
                    NO_ENTRY);
     CheckWriteCoin(SPENT, VALUE2, VALUE2, 0, DIRTY, DIRTY);
     CheckWriteCoin(SPENT, VALUE2, VALUE2, 0, DIRTY | FRESH, DIRTY);
     CheckWriteCoin(SPENT, VALUE2, VALUE2, FRESH, DIRTY, DIRTY | FRESH);
     CheckWriteCoin(SPENT, VALUE2, VALUE2, FRESH, DIRTY | FRESH, DIRTY | FRESH);
     CheckWriteCoin(SPENT, VALUE2, VALUE2, DIRTY, DIRTY, DIRTY);
     CheckWriteCoin(SPENT, VALUE2, VALUE2, DIRTY, DIRTY | FRESH, DIRTY);
     CheckWriteCoin(SPENT, VALUE2, VALUE2, DIRTY | FRESH, DIRTY, DIRTY | FRESH);
     CheckWriteCoin(SPENT, VALUE2, VALUE2, DIRTY | FRESH, DIRTY | FRESH,
                    DIRTY | FRESH);
     CheckWriteCoin(VALUE1, ABSENT, VALUE1, 0, NO_ENTRY, 0);
     CheckWriteCoin(VALUE1, ABSENT, VALUE1, FRESH, NO_ENTRY, FRESH);
     CheckWriteCoin(VALUE1, ABSENT, VALUE1, DIRTY, NO_ENTRY, DIRTY);
     CheckWriteCoin(VALUE1, ABSENT, VALUE1, DIRTY | FRESH, NO_ENTRY,
                    DIRTY | FRESH);
     CheckWriteCoin(VALUE1, SPENT, SPENT, 0, DIRTY, DIRTY);
     CheckWriteCoin(VALUE1, SPENT, FAIL, 0, DIRTY | FRESH, NO_ENTRY);
     CheckWriteCoin(VALUE1, SPENT, ABSENT, FRESH, DIRTY, NO_ENTRY);
     CheckWriteCoin(VALUE1, SPENT, FAIL, FRESH, DIRTY | FRESH, NO_ENTRY);
     CheckWriteCoin(VALUE1, SPENT, SPENT, DIRTY, DIRTY, DIRTY);
     CheckWriteCoin(VALUE1, SPENT, FAIL, DIRTY, DIRTY | FRESH, NO_ENTRY);
     CheckWriteCoin(VALUE1, SPENT, ABSENT, DIRTY | FRESH, DIRTY, NO_ENTRY);
     CheckWriteCoin(VALUE1, SPENT, FAIL, DIRTY | FRESH, DIRTY | FRESH, NO_ENTRY);
     CheckWriteCoin(VALUE1, VALUE2, VALUE2, 0, DIRTY, DIRTY);
     CheckWriteCoin(VALUE1, VALUE2, FAIL, 0, DIRTY | FRESH, NO_ENTRY);
     CheckWriteCoin(VALUE1, VALUE2, VALUE2, FRESH, DIRTY, DIRTY | FRESH);
     CheckWriteCoin(VALUE1, VALUE2, FAIL, FRESH, DIRTY | FRESH, NO_ENTRY);
     CheckWriteCoin(VALUE1, VALUE2, VALUE2, DIRTY, DIRTY, DIRTY);
     CheckWriteCoin(VALUE1, VALUE2, FAIL, DIRTY, DIRTY | FRESH, NO_ENTRY);
     CheckWriteCoin(VALUE1, VALUE2, VALUE2, DIRTY | FRESH, DIRTY, DIRTY | FRESH);
     CheckWriteCoin(VALUE1, VALUE2, FAIL, DIRTY | FRESH, DIRTY | FRESH,
                    NO_ENTRY);
 
     // The checks above omit cases where the child flags are not DIRTY, since
     // they would be too repetitive (the parent cache is never updated in these
     // cases). The loop below covers these cases and makes sure the parent cache
     // is always left unchanged.
     for (const Amount &parent_value : {ABSENT, SPENT, VALUE1}) {
         for (const Amount &child_value : {ABSENT, SPENT, VALUE2}) {
             for (const char parent_flags :
                  parent_value == ABSENT ? ABSENT_FLAGS : FLAGS) {
                 for (const char child_flags :
                      child_value == ABSENT ? ABSENT_FLAGS : CLEAN_FLAGS) {
                     CheckWriteCoin(parent_value, child_value, parent_value,
                                    parent_flags, child_flags, parent_flags);
                 }
             }
         }
     }
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/sigencoding_tests.cpp b/src/test/sigencoding_tests.cpp
index b2839d334..ebec9b513 100644
--- a/src/test/sigencoding_tests.cpp
+++ b/src/test/sigencoding_tests.cpp
@@ -1,439 +1,437 @@
 // Copyright (c) 2018-2019 The Bitcoin developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <script/sigencoding.h>
 
 #include <script/script_flags.h>
 
 #include <test/lcg.h>
 #include <test/util/setup_common.h>
 
 #include <boost/test/unit_test.hpp>
 
 BOOST_FIXTURE_TEST_SUITE(sigencoding_tests, BasicTestingSetup)
 
 static valtype SignatureWithHashType(valtype vchSig, SigHashType sigHash) {
     vchSig.push_back(static_cast<uint8_t>(sigHash.getRawSigHashType()));
     return vchSig;
 }
 
 static void CheckSignatureEncodingWithSigHashType(const valtype &vchSig,
                                                   uint32_t flags) {
     ScriptError err = ScriptError::OK;
     BOOST_CHECK(CheckDataSignatureEncoding(vchSig, flags, &err));
 
     const bool hasForkId = (flags & SCRIPT_ENABLE_SIGHASH_FORKID) != 0;
     const bool hasStrictEnc = (flags & SCRIPT_VERIFY_STRICTENC) != 0;
     const bool is64 = (vchSig.size() == 64);
 
     std::vector<BaseSigHashType> allBaseTypes{
         BaseSigHashType::ALL, BaseSigHashType::NONE, BaseSigHashType::SINGLE};
 
     std::vector<SigHashType> baseSigHashes;
     for (const BaseSigHashType &baseType : allBaseTypes) {
         const SigHashType baseSigHash = SigHashType().withBaseType(baseType);
         baseSigHashes.push_back(baseSigHash);
         baseSigHashes.push_back(baseSigHash.withAnyoneCanPay(true));
     }
 
     for (const SigHashType &baseSigHash : baseSigHashes) {
         // Check the signature with the proper forkid flag.
         SigHashType sigHash = baseSigHash.withForkId(hasForkId);
         valtype validSig = SignatureWithHashType(vchSig, sigHash);
         BOOST_CHECK(CheckTransactionSignatureEncoding(validSig, flags, &err));
         BOOST_CHECK_EQUAL(!is64, CheckTransactionECDSASignatureEncoding(
                                      validSig, flags, &err));
         BOOST_CHECK_EQUAL(is64, CheckTransactionSchnorrSignatureEncoding(
                                     validSig, flags, &err));
 
         // If we have strict encoding, we prevent the use of undefined flags.
         std::array<SigHashType, 2> undefSigHashes{
             {SigHashType(sigHash.getRawSigHashType() | 0x20),
              sigHash.withBaseType(BaseSigHashType::UNSUPPORTED)}};
 
         for (SigHashType undefSigHash : undefSigHashes) {
             valtype undefSighash = SignatureWithHashType(vchSig, undefSigHash);
             BOOST_CHECK_EQUAL(
                 CheckTransactionSignatureEncoding(undefSighash, flags, &err),
                 !hasStrictEnc);
             if (hasStrictEnc) {
                 BOOST_CHECK(err == ScriptError::SIG_HASHTYPE);
             }
             BOOST_CHECK_EQUAL(CheckTransactionECDSASignatureEncoding(
                                   undefSighash, flags, &err),
                               !(hasStrictEnc || is64));
             if (is64 || hasStrictEnc) {
                 BOOST_CHECK(err == (is64 ? ScriptError::SIG_BADLENGTH
                                          : ScriptError::SIG_HASHTYPE));
             }
             BOOST_CHECK_EQUAL(CheckTransactionSchnorrSignatureEncoding(
                                   undefSighash, flags, &err),
                               !(hasStrictEnc || !is64));
             if (!is64 || hasStrictEnc) {
                 BOOST_CHECK(err == (!is64 ? ScriptError::SIG_NONSCHNORR
                                           : ScriptError::SIG_HASHTYPE));
             }
         }
 
         // If we check strict encoding, then invalid forkid is an error.
         SigHashType invalidSigHash = baseSigHash.withForkId(!hasForkId);
         valtype invalidSig = SignatureWithHashType(vchSig, invalidSigHash);
 
         BOOST_CHECK_EQUAL(
             CheckTransactionSignatureEncoding(invalidSig, flags, &err),
             !hasStrictEnc);
         if (hasStrictEnc) {
             BOOST_CHECK(err == (hasForkId ? ScriptError::MUST_USE_FORKID
                                           : ScriptError::ILLEGAL_FORKID));
         }
         BOOST_CHECK_EQUAL(
             CheckTransactionECDSASignatureEncoding(invalidSig, flags, &err),
             !(hasStrictEnc || is64));
         if (is64 || hasStrictEnc) {
-            BOOST_CHECK(err == (is64
-                                    ? ScriptError::SIG_BADLENGTH
-                                    : hasForkId ? ScriptError::MUST_USE_FORKID
-                                                : ScriptError::ILLEGAL_FORKID));
+            BOOST_CHECK(err == (is64        ? ScriptError::SIG_BADLENGTH
+                                : hasForkId ? ScriptError::MUST_USE_FORKID
+                                            : ScriptError::ILLEGAL_FORKID));
         }
         BOOST_CHECK_EQUAL(
             CheckTransactionSchnorrSignatureEncoding(invalidSig, flags, &err),
             !(hasStrictEnc || !is64));
         if (!is64 || hasStrictEnc) {
-            BOOST_CHECK(err == (!is64
-                                    ? ScriptError::SIG_NONSCHNORR
-                                    : hasForkId ? ScriptError::MUST_USE_FORKID
-                                                : ScriptError::ILLEGAL_FORKID));
+            BOOST_CHECK(err == (!is64       ? ScriptError::SIG_NONSCHNORR
+                                : hasForkId ? ScriptError::MUST_USE_FORKID
+                                            : ScriptError::ILLEGAL_FORKID));
         }
     }
 }
 
 BOOST_AUTO_TEST_CASE(checksignatureencoding_test) {
     valtype minimalSig{0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01};
     valtype highSSig{
         0x30, 0x45, 0x02, 0x20, 0x3e, 0x45, 0x16, 0xda, 0x72, 0x53, 0xcf, 0x06,
         0x8e, 0xff, 0xec, 0x6b, 0x95, 0xc4, 0x12, 0x21, 0xc0, 0xcf, 0x3a, 0x8e,
         0x6c, 0xcb, 0x8c, 0xbf, 0x17, 0x25, 0xb5, 0x62, 0xe9, 0xaf, 0xde, 0x2c,
         0x02, 0x21, 0x00, 0xab, 0x1e, 0x3d, 0xa7, 0x3d, 0x67, 0xe3, 0x20, 0x45,
         0xa2, 0x0e, 0x0b, 0x99, 0x9e, 0x04, 0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5,
         0x48, 0x0d, 0x48, 0x5f, 0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0};
     std::vector<valtype> nonDERSigs{
         // Non canonical total length.
         {0x30, 0x80, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01},
         // Zero length R.
         {0x30, 0x2f, 0x02, 0x00, 0x02, 0x21, 0x00, 0xab, 0x1e, 0x3d,
          0xa7, 0x3d, 0x67, 0xe3, 0x20, 0x45, 0xa2, 0x0e, 0x0b, 0x99,
          0x9e, 0x04, 0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5, 0x48, 0x0d,
          0x48, 0x5f, 0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0},
         // Non canonical length for R.
         {0x30, 0x31, 0x02, 0x80, 0x01, 0x6c, 0x02, 0x21, 0x00, 0xab, 0x1e,
          0x3d, 0xa7, 0x3d, 0x67, 0xe3, 0x20, 0x45, 0xa2, 0x0e, 0x0b, 0x99,
          0x9e, 0x04, 0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5, 0x48, 0x0d, 0x48,
          0x5f, 0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0},
         // Negative R.
         {0x30, 0x30, 0x02, 0x01, 0x80, 0x02, 0x21, 0x00, 0xab, 0x1e,
          0x3d, 0xa7, 0x3d, 0x67, 0xe3, 0x20, 0x45, 0xa2, 0x0e, 0x0b,
          0x99, 0x9e, 0x04, 0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5, 0x48,
          0x0d, 0x48, 0x5f, 0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0},
         // Null prefixed R.
         {0x30, 0x31, 0x02, 0x02, 0x00, 0x01, 0x02, 0x21, 0x00, 0xab, 0x1e,
          0x3d, 0xa7, 0x3d, 0x67, 0xe3, 0x20, 0x45, 0xa2, 0x0e, 0x0b, 0x99,
          0x9e, 0x04, 0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5, 0x48, 0x0d, 0x48,
          0x5f, 0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0},
         // Zero length S.
         {0x30, 0x2f, 0x02, 0x21, 0x00, 0xab, 0x1e, 0x3d, 0xa7, 0x3d,
          0x67, 0xe3, 0x20, 0x45, 0xa2, 0x0e, 0x0b, 0x99, 0x9e, 0x04,
          0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5, 0x48, 0x0d, 0x48, 0x5f,
          0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0, 0x02, 0x00},
         // Non canonical length for S.
         {0x30, 0x31, 0x02, 0x21, 0x00, 0xab, 0x1e, 0x3d, 0xa7, 0x3d, 0x67,
          0xe3, 0x20, 0x45, 0xa2, 0x0e, 0x0b, 0x99, 0x9e, 0x04, 0x99, 0x78,
          0xea, 0x8d, 0x6e, 0xe5, 0x48, 0x0d, 0x48, 0x5f, 0xcf, 0x2c, 0xe0,
          0xd0, 0x3b, 0x2e, 0xf0, 0x02, 0x80, 0x01, 0x6c},
         // Negative S.
         {0x30, 0x30, 0x02, 0x21, 0x00, 0xab, 0x1e, 0x3d, 0xa7, 0x3d,
          0x67, 0xe3, 0x20, 0x45, 0xa2, 0x0e, 0x0b, 0x99, 0x9e, 0x04,
          0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5, 0x48, 0x0d, 0x48, 0x5f,
          0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0, 0x02, 0x01, 0x80},
         // Null prefixed S.
         {0x30, 0x31, 0x02, 0x21, 0x00, 0xab, 0x1e, 0x3d, 0xa7, 0x3d, 0x67,
          0xe3, 0x20, 0x45, 0xa2, 0x0e, 0x0b, 0x99, 0x9e, 0x04, 0x99, 0x78,
          0xea, 0x8d, 0x6e, 0xe5, 0x48, 0x0d, 0x48, 0x5f, 0xcf, 0x2c, 0xe0,
          0xd0, 0x3b, 0x2e, 0xf0, 0x02, 0x02, 0x00, 0x01},
     };
     std::vector<valtype> nonParsableSigs{
         // Too short.
         {0x30},
         {0x30, 0x06},
         {0x30, 0x06, 0x02},
         {0x30, 0x06, 0x02, 0x01},
         {0x30, 0x06, 0x02, 0x01, 0x01},
         {0x30, 0x06, 0x02, 0x01, 0x01, 0x02},
         {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01},
         // Invalid type (must be 0x30, coumpound).
         {0x42, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01},
         // Invalid sizes.
         {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01},
         {0x30, 0x07, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01},
         // Invalid R and S sizes.
         {0x30, 0x06, 0x02, 0x00, 0x01, 0x02, 0x01, 0x01},
         {0x30, 0x06, 0x02, 0x02, 0x01, 0x02, 0x01, 0x01},
         {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x00, 0x01},
         {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x02, 0x01},
         // Invalid R and S types.
         {0x30, 0x06, 0x42, 0x01, 0x01, 0x02, 0x01, 0x01},
         {0x30, 0x06, 0x02, 0x01, 0x01, 0x42, 0x01, 0x01},
         // S out of bounds.
         {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x02, 0x00},
         // Too long.
         {0x30, 0x47, 0x02, 0x21, 0x00, 0x8e, 0x45, 0x16, 0xda, 0x72, 0x53,
          0xcf, 0x06, 0x8e, 0xff, 0xec, 0x6b, 0x95, 0xc4, 0x12, 0x21, 0xc0,
          0xcf, 0x3a, 0x8e, 0x6c, 0xcb, 0x8c, 0xbf, 0x17, 0x25, 0xb5, 0x62,
          0xe9, 0xaf, 0xde, 0x2c, 0x02, 0x22, 0x00, 0xab, 0x1e, 0x3d, 0x00,
          0xa7, 0x3d, 0x67, 0xe3, 0x20, 0x45, 0xa2, 0x0e, 0x0b, 0x99, 0x9e,
          0x04, 0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5, 0x48, 0x0d, 0x48, 0x5f,
          0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0},
     };
     valtype Zero64(64, 0);
 
     MMIXLinearCongruentialGenerator lcg;
     for (int i = 0; i < 4096; i++) {
         uint32_t flags = lcg.next();
 
         ScriptError err = ScriptError::OK;
 
         // Empty sig is always validly encoded.
         BOOST_CHECK(CheckDataSignatureEncoding({}, flags, &err));
         BOOST_CHECK(CheckTransactionSignatureEncoding({}, flags, &err));
         BOOST_CHECK(CheckTransactionECDSASignatureEncoding({}, flags, &err));
         BOOST_CHECK(CheckTransactionSchnorrSignatureEncoding({}, flags, &err));
 
         // 64-byte signatures are valid as long as the hashtype is correct.
         CheckSignatureEncodingWithSigHashType(Zero64, flags);
 
         // Signatures are valid as long as the hashtype is correct.
         CheckSignatureEncodingWithSigHashType(minimalSig, flags);
 
         if (flags & SCRIPT_VERIFY_LOW_S) {
             // If we do enforce low S, then high S sigs are rejected.
             BOOST_CHECK(!CheckDataSignatureEncoding(highSSig, flags, &err));
             BOOST_CHECK(err == ScriptError::SIG_HIGH_S);
         } else {
             // If we do not enforce low S, then high S sigs are accepted.
             CheckSignatureEncodingWithSigHashType(highSSig, flags);
         }
 
         for (const valtype &nonDERSig : nonDERSigs) {
             if (flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S |
                          SCRIPT_VERIFY_STRICTENC)) {
                 // If we get any of the dersig flags, the non canonical dersig
                 // signature fails.
                 BOOST_CHECK(
                     !CheckDataSignatureEncoding(nonDERSig, flags, &err));
                 BOOST_CHECK(err == ScriptError::SIG_DER);
             } else {
                 // If we do not check, then it is accepted.
                 BOOST_CHECK(CheckDataSignatureEncoding(nonDERSig, flags, &err));
             }
         }
 
         for (const valtype &nonDERSig : nonParsableSigs) {
             if (flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S |
                          SCRIPT_VERIFY_STRICTENC)) {
                 // If we get any of the dersig flags, the high S but non dersig
                 // signature fails.
                 BOOST_CHECK(
                     !CheckDataSignatureEncoding(nonDERSig, flags, &err));
                 BOOST_CHECK(err == ScriptError::SIG_DER);
             } else {
                 // If we do not check, then it is accepted.
                 BOOST_CHECK(CheckDataSignatureEncoding(nonDERSig, flags, &err));
             }
         }
     }
 }
 
 BOOST_AUTO_TEST_CASE(checkpubkeyencoding_test) {
     valtype compressedKey0{0x02, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
                            0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12,
                            0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34,
                            0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0};
     valtype compressedKey1{0x03, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34,
                            0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56,
                            0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78,
                            0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff};
     valtype fullKey{0x04, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12,
                     0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56,
                     0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a,
                     0xbc, 0xde, 0xf0, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12,
                     0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56,
                     0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a,
                     0xbc, 0xde, 0xf0, 0x0f, 0xff};
 
     std::vector<valtype> invalidKeys{
         // Degenerate keys.
         {},
         {0x00},
         {0x01},
         {0x02},
         {0x03},
         {0x04},
         {0x05},
         {0x42},
         {0xff},
         // Invalid first byte 0x00.
         {0x00, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34,
          0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a,
          0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0},
         {0x00, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34,
          0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a,
          0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
          0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a,
          0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
          0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff},
         // Invalid first byte 0x01.
         {0x01, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34,
          0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a,
          0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0},
         {0x00, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34,
          0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a,
          0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
          0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a,
          0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
          0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff},
         // Invalid first byte 0x05.
         {0x05, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34,
          0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a,
          0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0},
         {0x05, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34,
          0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a,
          0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
          0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a,
          0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
          0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff},
         // Invalid first byte 0xff.
         {0xff, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34,
          0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a,
          0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0},
         {0xff, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34,
          0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a,
          0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
          0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a,
          0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
          0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff},
         // Compressed key too short.
         {0x02, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34,
          0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a,
          0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0},
         {0x03, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78,
          0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde,
          0xf0, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff},
         // Compressed key too long.
         {0x02, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56,
          0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0xab, 0xba, 0x9a,
          0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0},
         {0x03, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a,
          0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0xab,
          0xba, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff},
         // Compressed key, full key size.
         {0x02, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34,
          0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a,
          0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
          0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a,
          0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
          0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff},
         {0x03, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34,
          0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a,
          0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
          0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a,
          0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
          0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff},
         // Full key, too short.
         {0x04, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34,
          0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a,
          0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
          0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a,
          0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12,
          0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff},
         // Full key, too long.
         {0x04, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34,
          0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a,
          0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
          0x56, 0x78, 0xab, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78,
          0x9a, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xde,
          0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff},
         // Full key, compressed key size.
         {0x04, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56,
          0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0xab, 0xba, 0x9a,
          0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0},
     };
 
     MMIXLinearCongruentialGenerator lcg;
     for (int i = 0; i < 4096; i++) {
         uint32_t flags = lcg.next();
 
         ScriptError err = ScriptError::OK;
 
         // Compressed and uncompressed pubkeys are always valid.
         BOOST_CHECK(CheckPubKeyEncoding(compressedKey0, flags, &err));
         BOOST_CHECK(CheckPubKeyEncoding(compressedKey1, flags, &err));
         BOOST_CHECK(CheckPubKeyEncoding(fullKey, flags, &err));
 
         // If SCRIPT_VERIFY_STRICTENC is specified, we rule out invalid keys.
         const bool hasStrictEnc = (flags & SCRIPT_VERIFY_STRICTENC) != 0;
         const bool allowInvalidKeys = !hasStrictEnc;
         for (const valtype &key : invalidKeys) {
             BOOST_CHECK_EQUAL(CheckPubKeyEncoding(key, flags, &err),
                               allowInvalidKeys);
             if (!allowInvalidKeys) {
                 BOOST_CHECK(err == ScriptError::PUBKEYTYPE);
             }
         }
     }
 }
 
 BOOST_AUTO_TEST_CASE(checkschnorr_test) {
     // tests using 64 byte sigs (+hashtype byte where relevant)
     valtype Zero64(64, 0);
     valtype DER64{0x30, 0x3e, 0x02, 0x1d, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
                   0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
                   0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
                   0x44, 0x44, 0x44, 0x02, 0x1d, 0x44, 0x44, 0x44, 0x44, 0x44,
                   0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
                   0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
                   0x44, 0x44, 0x44, 0x44};
 
     BOOST_REQUIRE_EQUAL(Zero64.size(), 64);
     BOOST_REQUIRE_EQUAL(DER64.size(), 64);
 
     MMIXLinearCongruentialGenerator lcg;
     for (int i = 0; i < 4096; i++) {
         uint32_t flags = lcg.next();
 
         const bool hasForkId = (flags & SCRIPT_ENABLE_SIGHASH_FORKID) != 0;
 
         ScriptError err = ScriptError::OK;
         valtype DER65_hb =
             SignatureWithHashType(DER64, SigHashType().withForkId(hasForkId));
         valtype Zero65_hb =
             SignatureWithHashType(Zero64, SigHashType().withForkId(hasForkId));
 
         BOOST_CHECK(CheckDataSignatureEncoding(DER64, flags, &err));
         BOOST_CHECK(CheckTransactionSignatureEncoding(DER65_hb, flags, &err));
         BOOST_CHECK(
             !CheckTransactionECDSASignatureEncoding(DER65_hb, flags, &err));
         BOOST_CHECK(err == ScriptError::SIG_BADLENGTH);
         BOOST_CHECK(
             CheckTransactionSchnorrSignatureEncoding(DER65_hb, flags, &err));
 
         BOOST_CHECK(CheckDataSignatureEncoding(Zero64, flags, &err));
         BOOST_CHECK(CheckTransactionSignatureEncoding(Zero65_hb, flags, &err));
         BOOST_CHECK(
             !CheckTransactionECDSASignatureEncoding(Zero65_hb, flags, &err));
         BOOST_CHECK(err == ScriptError::SIG_BADLENGTH);
         BOOST_CHECK(
             CheckTransactionSchnorrSignatureEncoding(Zero65_hb, flags, &err));
     }
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/tinyformat.h b/src/tinyformat.h
index 4d5fd0d7b..1891eccf6 100644
--- a/src/tinyformat.h
+++ b/src/tinyformat.h
@@ -1,1203 +1,1203 @@
 // tinyformat.h
 // Copyright (C) 2011, Chris Foster [chris42f (at) gmail (d0t) com]
 //
 // Boost Software License - Version 1.0
 //
 // Permission is hereby granted, free of charge, to any person or organization
 // obtaining a copy of the software and accompanying documentation covered by
 // this license (the "Software") to use, reproduce, display, distribute,
 // execute, and transmit the Software, and to prepare derivative works of the
 // Software, and to permit third-parties to whom the Software is furnished to
 // do so, all subject to the following:
 //
 // The copyright notices in the Software and this entire statement, including
 // the above license grant, this restriction and the following disclaimer,
 // must be included in all copies of the Software, in whole or in part, and
 // all derivative works of the Software, unless such copies or derivative
 // works are solely in the form of machine-executable object code generated by
 // a source language processor.
 //
 // 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
 // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
 // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
 //------------------------------------------------------------------------------
 // Tinyformat: A minimal type safe printf replacement
 //
 // tinyformat.h is a type safe printf replacement library in a single C++
 // header file.  Design goals include:
 //
 // * Type safety and extensibility for user defined types.
 // * C99 printf() compatibility, to the extent possible using std::ostream
 // * POSIX extension for positional arguments
 // * Simplicity and minimalism.  A single header file to include and distribute
 //   with your projects.
 // * Augment rather than replace the standard stream formatting mechanism
 // * C++98 support, with optional C++11 niceties
 //
 //
 // Main interface example usage
 // ----------------------------
 //
 // To print a date to std::cout for American usage:
 //
 //   std::string weekday = "Wednesday";
 //   const char* month = "July";
 //   size_t day = 27;
 //   long hour = 14;
 //   int min = 44;
 //
 //   tfm::printf("%s, %s %d, %.2d:%.2d\n", weekday, month, day, hour, min);
 //
 // POSIX extension for positional arguments is available.
 // The ability to rearrange formatting arguments is an important feature
 // for localization because the word order may vary in different languages.
 //
 // Previous example for German usage. Arguments are reordered:
 //
 //   tfm::printf("%1$s, %3$d. %2$s, %4$d:%5$.2d\n", weekday, month, day, hour,
 //   min);
 //
 // The strange types here emphasize the type safety of the interface; it is
 // possible to print a std::string using the "%s" conversion, and a
 // size_t using the "%d" conversion.  A similar result could be achieved
 // using either of the tfm::format() functions.  One prints on a user provided
 // stream:
 //
 //   tfm::format(std::cerr, "%s, %s %d, %.2d:%.2d\n",
 //               weekday, month, day, hour, min);
 //
 // The other returns a std::string:
 //
 //   std::string date = tfm::format("%s, %s %d, %.2d:%.2d\n",
 //                                  weekday, month, day, hour, min);
 //   std::cout << date;
 //
 // These are the three primary interface functions.  There is also a
 // convenience function printfln() which appends a newline to the usual result
 // of printf() for super simple logging.
 //
 //
 // User defined format functions
 // -----------------------------
 //
 // Simulating variadic templates in C++98 is pretty painful since it requires
 // writing out the same function for each desired number of arguments.  To make
 // this bearable tinyformat comes with a set of macros which are used
 // internally to generate the API, but which may also be used in user code.
 //
 // The three macros TINYFORMAT_ARGTYPES(n), TINYFORMAT_VARARGS(n) and
 // TINYFORMAT_PASSARGS(n) will generate a list of n argument types,
 // type/name pairs and argument names respectively when called with an integer
 // n between 1 and 16.  We can use these to define a macro which generates the
 // desired user defined function with n arguments.  To generate all 16 user
 // defined function bodies, use the macro TINYFORMAT_FOREACH_ARGNUM.  For an
 // example, see the implementation of printf() at the end of the source file.
 //
 // Sometimes it's useful to be able to pass a list of format arguments through
 // to a non-template function.  The FormatList class is provided as a way to do
 // this by storing the argument list in a type-opaque way.  Continuing the
 // example from above, we construct a FormatList using makeFormatList():
 //
 //   FormatListRef formatList = tfm::makeFormatList(weekday, month, day, hour,
 //   min);
 //
 // The format list can now be passed into any non-template function and used
 // via a call to the vformat() function:
 //
 //   tfm::vformat(std::cout, "%s, %s %d, %.2d:%.2d\n", formatList);
 //
 //
 // Additional API information
 // --------------------------
 //
 // Error handling: Define TINYFORMAT_ERROR to customize the error handling for
 // format strings which are unsupported or have the wrong number of format
 // specifiers (calls assert() by default).
 //
 // User defined types: Uses operator<< for user defined types by default.
 // Overload formatValue() for more control.
 
 #ifndef TINYFORMAT_H_INCLUDED
 #define TINYFORMAT_H_INCLUDED
 
 namespace tinyformat {}
 //------------------------------------------------------------------------------
 // Config section.  Customize to your liking!
 
 // Namespace alias to encourage brevity
 namespace tfm = tinyformat;
 
 // Error handling; calls assert() by default.
 #define TINYFORMAT_ERROR(reasonString)                                         \
     throw tinyformat::format_error(reasonString)
 
 // Define for C++11 variadic templates which make the code shorter & more
 // general.  If you don't define this, C++11 support is autodetected below.
 #define TINYFORMAT_USE_VARIADIC_TEMPLATES
 
 //------------------------------------------------------------------------------
 // Implementation details.
 #include <algorithm>
 #include <iostream>
 #include <sstream>
 #include <stdexcept> // Added for Bitcoin
 
 #ifndef TINYFORMAT_ASSERT
 #include <cassert>
 #define TINYFORMAT_ASSERT(cond) assert(cond)
 #endif
 
 #ifndef TINYFORMAT_ERROR
 #include <cassert>
 #define TINYFORMAT_ERROR(reason) assert(0 && reason)
 #endif
 
 #if !defined(TINYFORMAT_USE_VARIADIC_TEMPLATES) &&                             \
     !defined(TINYFORMAT_NO_VARIADIC_TEMPLATES)
 #ifdef __GXX_EXPERIMENTAL_CXX0X__
 #define TINYFORMAT_USE_VARIADIC_TEMPLATES
 #endif
 #endif
 
 #if defined(__GLIBCXX__) && __GLIBCXX__ < 20080201
 //  std::showpos is broken on old libstdc++ as provided with macOS.  See
 //  http://gcc.gnu.org/ml/libstdc++/2007-11/msg00075.html
 #define TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
 #endif
 
 #ifdef __APPLE__
 // Workaround macOS linker warning: Xcode uses different default symbol
 // visibilities for static libs vs executables (see issue #25)
 #define TINYFORMAT_HIDDEN __attribute__((visibility("hidden")))
 #else
 #define TINYFORMAT_HIDDEN
 #endif
 
 namespace tinyformat {
 
 // Added for Bitcoin
 class format_error : public std::runtime_error {
 public:
     explicit format_error(const std::string &what) : std::runtime_error(what) {}
 };
 
 //------------------------------------------------------------------------------
 namespace detail {
 
     // Test whether type T1 is convertible to type T2
     template <typename T1, typename T2> struct is_convertible {
     private:
         // two types of different size
         struct fail {
             char dummy[2];
         };
         struct succeed {
             char dummy;
         };
         // Try to convert a T1 to a T2 by plugging into tryConvert
         static fail tryConvert(...);
         static succeed tryConvert(const T2 &);
         static const T1 &makeT1();
 
     public:
 #ifdef _MSC_VER
 // Disable spurious loss of precision warnings in tryConvert(makeT1())
 #pragma warning(push)
 #pragma warning(disable : 4244)
 #pragma warning(disable : 4267)
 #endif
         // Standard trick: the (...) version of tryConvert will be chosen from
         // the overload set only if the version taking a T2 doesn't match. Then
         // we compare the sizes of the return types to check which function
         // matched.  Very neat, in a disgusting kind of way :)
         static const bool value =
             sizeof(tryConvert(makeT1())) == sizeof(succeed);
 #ifdef _MSC_VER
 #pragma warning(pop)
 #endif
     };
 
     // Detect when a type is not a wchar_t string
     template <typename T> struct is_wchar {
         typedef int tinyformat_wchar_is_not_supported;
     };
     template <> struct is_wchar<wchar_t *> {};
     template <> struct is_wchar<const wchar_t *> {};
     template <int n> struct is_wchar<const wchar_t[n]> {};
     template <int n> struct is_wchar<wchar_t[n]> {};
 
     // Format the value by casting to type fmtT. This default implementation
     // should never be called.
     template <typename T, typename fmtT,
               bool convertible = is_convertible<T, fmtT>::value>
     struct formatValueAsType {
         static void invoke(std::ostream & /*out*/, const T & /*value*/) {
             TINYFORMAT_ASSERT(0);
         }
     };
     // Specialized version for types that can actually be converted to fmtT, as
     // indicated by the "convertible" template parameter.
     template <typename T, typename fmtT>
     struct formatValueAsType<T, fmtT, true> {
         static void invoke(std::ostream &out, const T &value) {
             out << static_cast<fmtT>(value);
         }
     };
 
 #ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
     template <typename T, bool convertible = is_convertible<T, int>::value>
     struct formatZeroIntegerWorkaround {
         static bool invoke(std::ostream & /**/, const T & /**/) {
             return false;
         }
     };
     template <typename T> struct formatZeroIntegerWorkaround<T, true> {
         static bool invoke(std::ostream &out, const T &value) {
             if (static_cast<int>(value) == 0 &&
                 out.flags() & std::ios::showpos) {
                 out << "+0";
                 return true;
             }
             return false;
         }
     };
 #endif // TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
 
     // Convert an arbitrary type to integer.  The version with convertible=false
     // throws an error.
     template <typename T, bool convertible = is_convertible<T, int>::value>
     struct convertToInt {
         static int invoke(const T & /*value*/) {
             TINYFORMAT_ERROR("tinyformat: Cannot convert from argument type to "
                              "integer for use as variable width or precision");
             return 0;
         }
     };
     // Specialization for convertToInt when conversion is possible
     template <typename T> struct convertToInt<T, true> {
         static int invoke(const T &value) { return static_cast<int>(value); }
     };
 
     // Format at most ntrunc characters to the given stream.
     template <typename T>
     inline void formatTruncated(std::ostream &out, const T &value, int ntrunc) {
         std::ostringstream tmp;
         tmp << value;
         std::string result = tmp.str();
         out.write(result.c_str(),
                   (std::min)(ntrunc, static_cast<int>(result.size())));
     }
 #define TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(type)                          \
     inline void formatTruncated(std::ostream &out, type *value, int ntrunc) {  \
         std::streamsize len = 0;                                               \
         while (len < ntrunc && value[len] != 0)                                \
             ++len;                                                             \
         out.write(value, len);                                                 \
     }
     // Overload for const char* and char*. Could overload for signed & unsigned
     // char too, but these are technically unneeded for printf compatibility.
     TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(const char)
     TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR(char)
 #undef TINYFORMAT_DEFINE_FORMAT_TRUNCATED_CSTR
 
 } // namespace detail
 
 //------------------------------------------------------------------------------
 // Variable formatting functions.  May be overridden for user-defined types if
 // desired.
 
 /// Format a value into a stream, delegating to operator<< by default.
 ///
 /// Users may override this for their own types.  When this function is called,
 /// the stream flags will have been modified according to the format string.
 /// The format specification is provided in the range [fmtBegin, fmtEnd).  For
 /// truncating conversions, ntrunc is set to the desired maximum number of
 /// characters, for example "%.7s" calls formatValue with ntrunc = 7.
 ///
 /// By default, formatValue() uses the usual stream insertion operator
 /// operator<< to format the type T, with special cases for the %c and %p
 /// conversions.
 template <typename T>
 inline void formatValue(std::ostream &out, const char * /*fmtBegin*/,
                         const char *fmtEnd, int ntrunc, const T &value) {
 #ifndef TINYFORMAT_ALLOW_WCHAR_STRINGS
     // Since we don't support printing of wchar_t using "%ls", make it fail at
     // compile time in preference to printing as a void* at runtime.
     typedef typename detail::is_wchar<T>::tinyformat_wchar_is_not_supported
         DummyType;
     (void)DummyType(); // avoid unused type warning with gcc-4.8
 #endif
     // The mess here is to support the %c and %p conversions: if these
     // conversions are active we try to convert the type to a char or const
     // void* respectively and format that instead of the value itself. For the
     // %p conversion it's important to avoid dereferencing the pointer, which
     // could otherwise lead to a crash when printing a dangling (const char*).
     const bool canConvertToChar = detail::is_convertible<T, char>::value;
     const bool canConvertToVoidPtr =
         detail::is_convertible<T, const void *>::value;
     if (canConvertToChar && *(fmtEnd - 1) == 'c')
         detail::formatValueAsType<T, char>::invoke(out, value);
     else if (canConvertToVoidPtr && *(fmtEnd - 1) == 'p')
         detail::formatValueAsType<T, const void *>::invoke(out, value);
 #ifdef TINYFORMAT_OLD_LIBSTDCPLUSPLUS_WORKAROUND
     else if (detail::formatZeroIntegerWorkaround<T>::invoke(out, value)) /**/
         ;
 #endif
     else if (ntrunc >= 0) {
         // Take care not to overread C strings in truncating conversions like
         // "%.4s" where at most 4 characters may be read.
         detail::formatTruncated(out, value, ntrunc);
     } else
         out << value;
 }
 
 // Overloaded version for char types to support printing as an integer
 #define TINYFORMAT_DEFINE_FORMATVALUE_CHAR(charType)                           \
     inline void formatValue(std::ostream &out, const char * /*fmtBegin*/,      \
                             const char *fmtEnd, int /**/, charType value) {    \
         switch (*(fmtEnd - 1)) {                                               \
             case 'u':                                                          \
             case 'd':                                                          \
             case 'i':                                                          \
             case 'o':                                                          \
             case 'X':                                                          \
             case 'x':                                                          \
                 out << static_cast<int>(value);                                \
                 break;                                                         \
             default:                                                           \
                 out << value;                                                  \
                 break;                                                         \
         }                                                                      \
     }
 // per 3.9.1: char, signed char and uint8_t are all distinct types
 TINYFORMAT_DEFINE_FORMATVALUE_CHAR(char)
 TINYFORMAT_DEFINE_FORMATVALUE_CHAR(signed char)
 TINYFORMAT_DEFINE_FORMATVALUE_CHAR(uint8_t)
 #undef TINYFORMAT_DEFINE_FORMATVALUE_CHAR
 
 //------------------------------------------------------------------------------
 // Tools for emulating variadic templates in C++98.  The basic idea here is
 // stolen from the boost preprocessor metaprogramming library and cut down to
 // be just general enough for what we need.
 
 #define TINYFORMAT_ARGTYPES(n) TINYFORMAT_ARGTYPES_##n
 #define TINYFORMAT_VARARGS(n) TINYFORMAT_VARARGS_##n
 #define TINYFORMAT_PASSARGS(n) TINYFORMAT_PASSARGS_##n
 #define TINYFORMAT_PASSARGS_TAIL(n) TINYFORMAT_PASSARGS_TAIL_##n
 
 // To keep it as transparent as possible, the macros below have been generated
 // using python via the excellent cog.py code generation script.  This avoids
 // the need for a bunch of complex (but more general) preprocessor tricks as
 // used in boost.preprocessor.
 //
 // To rerun the code generation in place, use `cog.py -r tinyformat.h`
 // (see http://nedbatchelder.com/code/cog).  Alternatively you can just create
 // extra versions by hand.
 
 /*[[[cog
 maxParams = 16
 
 def makeCommaSepLists(lineTemplate, elemTemplate, startInd=1):
     for j in range(startInd,maxParams+1):
         list = ', '.join([elemTemplate % {'i':i} for i in range(startInd,j+1)])
         cog.outl(lineTemplate % {'j':j, 'list':list})
 
 makeCommaSepLists('#define TINYFORMAT_ARGTYPES_%(j)d %(list)s',
                   'class T%(i)d')
 
 cog.outl()
 makeCommaSepLists('#define TINYFORMAT_VARARGS_%(j)d %(list)s',
                   'const T%(i)d& v%(i)d')
 
 cog.outl()
 makeCommaSepLists('#define TINYFORMAT_PASSARGS_%(j)d %(list)s', 'v%(i)d')
 
 cog.outl()
 cog.outl('#define TINYFORMAT_PASSARGS_TAIL_1')
 makeCommaSepLists('#define TINYFORMAT_PASSARGS_TAIL_%(j)d , %(list)s',
                   'v%(i)d', startInd = 2)
 
 cog.outl()
 cog.outl('#define TINYFORMAT_FOREACH_ARGNUM(m) \\\n    ' +
          ' '.join(['m(%d)' % (j,) for j in range(1,maxParams+1)]))
 ]]]*/
 #define TINYFORMAT_ARGTYPES_1 class T1
 #define TINYFORMAT_ARGTYPES_2 class T1, class T2
 #define TINYFORMAT_ARGTYPES_3 class T1, class T2, class T3
 #define TINYFORMAT_ARGTYPES_4 class T1, class T2, class T3, class T4
 #define TINYFORMAT_ARGTYPES_5 class T1, class T2, class T3, class T4, class T5
 #define TINYFORMAT_ARGTYPES_6                                                  \
     class T1, class T2, class T3, class T4, class T5, class T6
 #define TINYFORMAT_ARGTYPES_7                                                  \
     class T1, class T2, class T3, class T4, class T5, class T6, class T7
 #define TINYFORMAT_ARGTYPES_8                                                  \
     class T1, class T2, class T3, class T4, class T5, class T6, class T7,      \
         class T8
 #define TINYFORMAT_ARGTYPES_9                                                  \
     class T1, class T2, class T3, class T4, class T5, class T6, class T7,      \
         class T8, class T9
 #define TINYFORMAT_ARGTYPES_10                                                 \
     class T1, class T2, class T3, class T4, class T5, class T6, class T7,      \
         class T8, class T9, class T10
 #define TINYFORMAT_ARGTYPES_11                                                 \
     class T1, class T2, class T3, class T4, class T5, class T6, class T7,      \
         class T8, class T9, class T10, class T11
 #define TINYFORMAT_ARGTYPES_12                                                 \
     class T1, class T2, class T3, class T4, class T5, class T6, class T7,      \
         class T8, class T9, class T10, class T11, class T12
 #define TINYFORMAT_ARGTYPES_13                                                 \
     class T1, class T2, class T3, class T4, class T5, class T6, class T7,      \
         class T8, class T9, class T10, class T11, class T12, class T13
 #define TINYFORMAT_ARGTYPES_14                                                 \
     class T1, class T2, class T3, class T4, class T5, class T6, class T7,      \
         class T8, class T9, class T10, class T11, class T12, class T13,        \
         class T14
 #define TINYFORMAT_ARGTYPES_15                                                 \
     class T1, class T2, class T3, class T4, class T5, class T6, class T7,      \
         class T8, class T9, class T10, class T11, class T12, class T13,        \
         class T14, class T15
 #define TINYFORMAT_ARGTYPES_16                                                 \
     class T1, class T2, class T3, class T4, class T5, class T6, class T7,      \
         class T8, class T9, class T10, class T11, class T12, class T13,        \
         class T14, class T15, class T16
 
 #define TINYFORMAT_VARARGS_1 const T1 &v1
 #define TINYFORMAT_VARARGS_2 const T1 &v1, const T2 &v2
 #define TINYFORMAT_VARARGS_3 const T1 &v1, const T2 &v2, const T3 &v3
 #define TINYFORMAT_VARARGS_4                                                   \
     const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4
 #define TINYFORMAT_VARARGS_5                                                   \
     const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5
 #define TINYFORMAT_VARARGS_6                                                   \
     const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5,      \
         const T6 &v6
 #define TINYFORMAT_VARARGS_7                                                   \
     const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5,      \
         const T6 &v6, const T7 &v7
 #define TINYFORMAT_VARARGS_8                                                   \
     const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5,      \
         const T6 &v6, const T7 &v7, const T8 &v8
 #define TINYFORMAT_VARARGS_9                                                   \
     const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5,      \
         const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9
 #define TINYFORMAT_VARARGS_10                                                  \
     const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5,      \
         const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9, const T10 &v10
 #define TINYFORMAT_VARARGS_11                                                  \
     const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5,      \
         const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9,                \
         const T10 &v10, const T11 &v11
 #define TINYFORMAT_VARARGS_12                                                  \
     const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5,      \
         const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9,                \
         const T10 &v10, const T11 &v11, const T12 &v12
 #define TINYFORMAT_VARARGS_13                                                  \
     const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5,      \
         const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9,                \
         const T10 &v10, const T11 &v11, const T12 &v12, const T13 &v13
 #define TINYFORMAT_VARARGS_14                                                  \
     const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5,      \
         const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9,                \
         const T10 &v10, const T11 &v11, const T12 &v12, const T13 &v13,        \
         const T14 &v14
 #define TINYFORMAT_VARARGS_15                                                  \
     const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5,      \
         const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9,                \
         const T10 &v10, const T11 &v11, const T12 &v12, const T13 &v13,        \
         const T14 &v14, const T15 &v15
 #define TINYFORMAT_VARARGS_16                                                  \
     const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5,      \
         const T6 &v6, const T7 &v7, const T8 &v8, const T9 &v9,                \
         const T10 &v10, const T11 &v11, const T12 &v12, const T13 &v13,        \
         const T14 &v14, const T15 &v15, const T16 &v16
 
 #define TINYFORMAT_PASSARGS_1 v1
 #define TINYFORMAT_PASSARGS_2 v1, v2
 #define TINYFORMAT_PASSARGS_3 v1, v2, v3
 #define TINYFORMAT_PASSARGS_4 v1, v2, v3, v4
 #define TINYFORMAT_PASSARGS_5 v1, v2, v3, v4, v5
 #define TINYFORMAT_PASSARGS_6 v1, v2, v3, v4, v5, v6
 #define TINYFORMAT_PASSARGS_7 v1, v2, v3, v4, v5, v6, v7
 #define TINYFORMAT_PASSARGS_8 v1, v2, v3, v4, v5, v6, v7, v8
 #define TINYFORMAT_PASSARGS_9 v1, v2, v3, v4, v5, v6, v7, v8, v9
 #define TINYFORMAT_PASSARGS_10 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10
 #define TINYFORMAT_PASSARGS_11 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11
 #define TINYFORMAT_PASSARGS_12 v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12
 #define TINYFORMAT_PASSARGS_13                                                 \
     v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13
 #define TINYFORMAT_PASSARGS_14                                                 \
     v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14
 #define TINYFORMAT_PASSARGS_15                                                 \
     v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15
 #define TINYFORMAT_PASSARGS_16                                                 \
     v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16
 
 #define TINYFORMAT_PASSARGS_TAIL_1
 #define TINYFORMAT_PASSARGS_TAIL_2 , v2
 #define TINYFORMAT_PASSARGS_TAIL_3 , v2, v3
 #define TINYFORMAT_PASSARGS_TAIL_4 , v2, v3, v4
 #define TINYFORMAT_PASSARGS_TAIL_5 , v2, v3, v4, v5
 #define TINYFORMAT_PASSARGS_TAIL_6 , v2, v3, v4, v5, v6
 #define TINYFORMAT_PASSARGS_TAIL_7 , v2, v3, v4, v5, v6, v7
 #define TINYFORMAT_PASSARGS_TAIL_8 , v2, v3, v4, v5, v6, v7, v8
 #define TINYFORMAT_PASSARGS_TAIL_9 , v2, v3, v4, v5, v6, v7, v8, v9
 #define TINYFORMAT_PASSARGS_TAIL_10 , v2, v3, v4, v5, v6, v7, v8, v9, v10
 #define TINYFORMAT_PASSARGS_TAIL_11 , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11
 #define TINYFORMAT_PASSARGS_TAIL_12                                            \
     , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12
 #define TINYFORMAT_PASSARGS_TAIL_13                                            \
     , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13
 #define TINYFORMAT_PASSARGS_TAIL_14                                            \
     , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14
 #define TINYFORMAT_PASSARGS_TAIL_15                                            \
     , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15
 #define TINYFORMAT_PASSARGS_TAIL_16                                            \
     , v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16
 
 #define TINYFORMAT_FOREACH_ARGNUM(m)                                           \
     m(1) m(2) m(3) m(4) m(5) m(6) m(7) m(8) m(9) m(10) m(11) m(12) m(13) m(14) \
         m(15) m(16)
 //[[[end]]]
 
 namespace detail {
 
     // Type-opaque holder for an argument to format(), with associated actions
     // on the type held as explicit function pointers. This allows FormatArg's
     // for each argument to be allocated as a homogeneous array inside
     // FormatList whereas a naive implementation based on inheritance does not.
     class FormatArg {
     public:
         FormatArg() : m_value(NULL), m_formatImpl(NULL), m_toIntImpl(NULL) {}
 
         template <typename T>
         FormatArg(const T &value)
             : m_value(static_cast<const void *>(&value)),
               m_formatImpl(&formatImpl<T>), m_toIntImpl(&toIntImpl<T>) {}
 
         void format(std::ostream &out, const char *fmtBegin, const char *fmtEnd,
                     int ntrunc) const {
             TINYFORMAT_ASSERT(m_value);
             TINYFORMAT_ASSERT(m_formatImpl);
             m_formatImpl(out, fmtBegin, fmtEnd, ntrunc, m_value);
         }
 
         int toInt() const {
             TINYFORMAT_ASSERT(m_value);
             TINYFORMAT_ASSERT(m_toIntImpl);
             return m_toIntImpl(m_value);
         }
 
     private:
         template <typename T>
         TINYFORMAT_HIDDEN static void
         formatImpl(std::ostream &out, const char *fmtBegin, const char *fmtEnd,
                    int ntrunc, const void *value) {
             formatValue(out, fmtBegin, fmtEnd, ntrunc,
                         *static_cast<const T *>(value));
         }
 
         template <typename T>
         TINYFORMAT_HIDDEN static int toIntImpl(const void *value) {
             return convertToInt<T>::invoke(*static_cast<const T *>(value));
         }
 
         const void *m_value;
         void (*m_formatImpl)(std::ostream &out, const char *fmtBegin,
                              const char *fmtEnd, int ntrunc, const void *value);
         int (*m_toIntImpl)(const void *value);
     };
 
     // Parse and return an integer from the string c, as atoi()
     // On return, c is set to one past the end of the integer.
     inline int parseIntAndAdvance(const char *&c) {
         int i = 0;
         for (; *c >= '0' && *c <= '9'; ++c)
             i = 10 * i + (*c - '0');
         return i;
     }
 
     // Parse width or precision `n` from format string pointer `c`, and advance
     // it to the next character. If an indirection is requested with `*`, the
     // argument is read from `args[argIndex]` and `argIndex` is incremented (or
     // read from `args[n]` in positional mode). Returns true if one or more
     // characters were read.
     inline bool parseWidthOrPrecision(int &n, const char *&c,
                                       bool positionalMode,
                                       const detail::FormatArg *args,
                                       int &argIndex, int numArgs) {
         if (*c >= '0' && *c <= '9') {
             n = parseIntAndAdvance(c);
         } else if (*c == '*') {
             ++c;
             n = 0;
             if (positionalMode) {
                 int pos = parseIntAndAdvance(c) - 1;
                 if (*c != '$')
                     TINYFORMAT_ERROR("tinyformat: Non-positional argument used "
                                      "after a positional one");
                 if (pos >= 0 && pos < numArgs)
                     n = args[pos].toInt();
                 else
                     TINYFORMAT_ERROR(
                         "tinyformat: Positional argument out of range");
                 ++c;
             } else {
                 if (argIndex < numArgs)
                     n = args[argIndex++].toInt();
                 else
                     TINYFORMAT_ERROR("tinyformat: Not enough arguments to read "
                                      "variable width or precision");
             }
         } else {
             return false;
         }
         return true;
     }
 
     // Print literal part of format string and return next format spec position.
     //
     // Skips over any occurrences of '%%', printing a literal '%' to the output.
     // The position of the first % character of the next nontrivial format spec
     // is returned, or the end of string.
     inline const char *printFormatStringLiteral(std::ostream &out,
                                                 const char *fmt) {
         const char *c = fmt;
         for (;; ++c) {
             if (*c == '\0') {
                 out.write(fmt, c - fmt);
                 return c;
             } else if (*c == '%') {
                 out.write(fmt, c - fmt);
                 if (*(c + 1) != '%') return c;
                 // for "%%", tack trailing % onto next literal section.
                 fmt = ++c;
             }
         }
     }
 
     // Parse a format string and set the stream state accordingly.
     //
     // The format mini-language recognized here is meant to be the one from C99,
     // with the form "%[flags][width][.precision][length]type" with POSIX
     // positional arguments extension.
     //
     // POSIX positional arguments extension:
     // Conversions can be applied to the nth argument after the format in
     // the argument list, rather than to the next unused argument. In this case,
     // the conversion specifier character % (see below) is replaced by the
     // sequence
     // "%n$", where n is a decimal integer in the range [1,{NL_ARGMAX}],
     // giving the position of the argument in the argument list. This feature
     // provides for the definition of format strings that select arguments
     // in an order appropriate to specific languages.
     //
     // The format can contain either numbered argument conversion specifications
     // (that is, "%n$" and "*m$"), or unnumbered argument conversion
     // specifications (that is, % and * ), but not both. The only exception to
     // this is that %% can be mixed with the "%n$" form. The results of mixing
     // numbered and unnumbered argument specifications in a format string are
     // undefined. When numbered argument specifications are used, specifying the
     // Nth argument requires that all the leading arguments, from the first to
     // the (N-1)th, are specified in the format string.
     //
     // In format strings containing the "%n$" form of conversion specification,
     // numbered arguments in the argument list can be referenced from the format
     // string as many times as required.
     //
     // Formatting options which can't be natively represented using the ostream
     // state are returned in spacePadPositive (for space padded positive
     // numbers) and ntrunc (for truncating conversions). argIndex is incremented
     // if necessary to pull out variable width and precision. The function
     // returns a pointer to the character after the end of the current format
     // spec.
     inline const char *streamStateFromFormat(std::ostream &out,
                                              bool &positionalMode,
                                              bool &spacePadPositive,
                                              int &ntrunc, const char *fmtStart,
                                              const detail::FormatArg *args,
                                              int &argIndex, int numArgs) {
         TINYFORMAT_ASSERT(*fmtStart == '%');
         // Reset stream state to defaults.
         out.width(0);
         out.precision(6);
         out.fill(' ');
         // Reset most flags; ignore irrelevant unitbuf & skipws.
         out.unsetf(std::ios::adjustfield | std::ios::basefield |
                    std::ios::floatfield | std::ios::showbase |
                    std::ios::boolalpha | std::ios::showpoint |
                    std::ios::showpos | std::ios::uppercase);
         bool precisionSet = false;
         bool widthSet = false;
         int widthExtra = 0;
         const char *c = fmtStart + 1;
 
         // 1) Parse an argument index (if followed by '$') or a width possibly
         // preceded with '0' flag.
         if (*c >= '0' && *c <= '9') {
             const char tmpc = *c;
             int value = parseIntAndAdvance(c);
             if (*c == '$') {
                 // value is an argument index
                 if (value > 0 && value <= numArgs)
                     argIndex = value - 1;
                 else
                     TINYFORMAT_ERROR(
                         "tinyformat: Positional argument out of range");
                 ++c;
                 positionalMode = true;
             } else if (positionalMode) {
                 TINYFORMAT_ERROR("tinyformat: Non-positional argument used "
                                  "after a positional one");
             } else {
                 if (tmpc == '0') {
                     // Use internal padding so that numeric values are
                     // formatted correctly, eg -00010 rather than 000-10
                     out.fill('0');
                     out.setf(std::ios::internal, std::ios::adjustfield);
                 }
                 if (value != 0) {
                     // Nonzero value means that we parsed width.
                     widthSet = true;
                     out.width(value);
                 }
             }
         } else if (positionalMode) {
             TINYFORMAT_ERROR("tinyformat: Non-positional argument used after a "
                              "positional one");
         }
         // 2) Parse flags and width if we did not do it in previous step.
         if (!widthSet) {
             // Parse flags
             for (;; ++c) {
                 switch (*c) {
                     case '#':
                         out.setf(std::ios::showpoint | std::ios::showbase);
                         continue;
                     case '0':
                         // overridden by left alignment ('-' flag)
                         if (!(out.flags() & std::ios::left)) {
                             // Use internal padding so that numeric values are
                             // formatted correctly, eg -00010 rather than 000-10
                             out.fill('0');
                             out.setf(std::ios::internal, std::ios::adjustfield);
                         }
                         continue;
                     case '-':
                         out.fill(' ');
                         out.setf(std::ios::left, std::ios::adjustfield);
                         continue;
                     case ' ':
                         // overridden by show positive sign, '+' flag.
                         if (!(out.flags() & std::ios::showpos))
                             spacePadPositive = true;
                         continue;
                     case '+':
                         out.setf(std::ios::showpos);
                         spacePadPositive = false;
                         widthExtra = 1;
                         continue;
                     default:
                         break;
                 }
                 break;
             }
             // Parse width
             int width = 0;
             widthSet = parseWidthOrPrecision(width, c, positionalMode, args,
                                              argIndex, numArgs);
             if (widthSet) {
                 if (width < 0) {
                     // negative widths correspond to '-' flag set
                     out.fill(' ');
                     out.setf(std::ios::left, std::ios::adjustfield);
                     width = -width;
                 }
                 out.width(width);
             }
         }
         // 3) Parse precision
         if (*c == '.') {
             ++c;
             int precision = 0;
             parseWidthOrPrecision(precision, c, positionalMode, args, argIndex,
                                   numArgs);
             // Presence of `.` indicates precision set, unless the inferred
             // value was negative in which case the default is used.
             precisionSet = precision >= 0;
             if (precisionSet) out.precision(precision);
         }
         // 4) Ignore any C99 length modifier
         while (*c == 'l' || *c == 'h' || *c == 'L' || *c == 'j' || *c == 'z' ||
                *c == 't') {
             ++c;
         }
         // 5) We're up to the conversion specifier character.
         // Set stream flags based on conversion specifier (thanks to the
         // boost::format class for forging the way here).
         bool intConversion = false;
         switch (*c) {
             case 'u':
             case 'd':
             case 'i':
                 out.setf(std::ios::dec, std::ios::basefield);
                 intConversion = true;
                 break;
             case 'o':
                 out.setf(std::ios::oct, std::ios::basefield);
                 intConversion = true;
                 break;
             case 'X':
                 out.setf(std::ios::uppercase);
                 // Falls through
             case 'x':
             case 'p':
                 out.setf(std::ios::hex, std::ios::basefield);
                 intConversion = true;
                 break;
             case 'E':
                 out.setf(std::ios::uppercase);
                 // Falls through
             case 'e':
                 out.setf(std::ios::scientific, std::ios::floatfield);
                 out.setf(std::ios::dec, std::ios::basefield);
                 break;
             case 'F':
                 out.setf(std::ios::uppercase);
                 // Falls through
             case 'f':
                 out.setf(std::ios::fixed, std::ios::floatfield);
                 break;
             case 'A':
                 out.setf(std::ios::uppercase);
                 // Falls through
             case 'a':
 #ifdef _MSC_VER
                 // Workaround
                 // https://developercommunity.visualstudio.com/content/problem/520472/hexfloat-stream-output-does-not-ignore-precision-a.html
                 // by always setting maximum precision on MSVC to avoid
                 // precision loss for doubles.
                 out.precision(13);
 #endif
                 out.setf(std::ios::fixed | std::ios::scientific,
                          std::ios::floatfield);
                 break;
             case 'G':
                 out.setf(std::ios::uppercase);
                 // Falls through
             case 'g':
                 out.setf(std::ios::dec, std::ios::basefield);
                 // As in boost::format, let stream decide float format.
                 out.flags(out.flags() & ~std::ios::floatfield);
                 break;
             case 'c':
                 // Handled as special case inside formatValue()
                 break;
             case 's':
                 if (precisionSet) ntrunc = static_cast<int>(out.precision());
                 // Make %s print Booleans as "true" and "false"
                 out.setf(std::ios::boolalpha);
                 break;
             case 'n':
                 // Not supported - will cause problems!
                 TINYFORMAT_ERROR(
                     "tinyformat: %n conversion spec not supported");
                 break;
             case '\0':
                 TINYFORMAT_ERROR("tinyformat: Conversion spec incorrectly "
                                  "terminated by end of string");
                 return c;
             default:
                 break;
         }
         if (intConversion && precisionSet && !widthSet) {
             // "precision" for integers gives the minimum number of digits (to
             // be padded with zeros on the left). This isn't really supported by
             // the iostreams, but we can approximately simulate it with the
             // width if the width isn't otherwise used.
             out.width(out.precision() + widthExtra);
             out.setf(std::ios::internal, std::ios::adjustfield);
             out.fill('0');
         }
         return c + 1;
     }
 
     //------------------------------------------------------------------------------
     inline void formatImpl(std::ostream &out, const char *fmt,
                            const detail::FormatArg *args, int numArgs) {
         // Saved stream state
         std::streamsize origWidth = out.width();
         std::streamsize origPrecision = out.precision();
         std::ios::fmtflags origFlags = out.flags();
         char origFill = out.fill();
 
         // "Positional mode" means all format specs should be of the form
         // "%n$..." with `n` an integer. We detect this in
         // `streamStateFromFormat`.
         bool positionalMode = false;
         int argIndex = 0;
         while (true) {
             fmt = printFormatStringLiteral(out, fmt);
             if (*fmt == '\0') {
                 if (!positionalMode && argIndex < numArgs) {
                     TINYFORMAT_ERROR("tinyformat: Not enough conversion "
                                      "specifiers in format string");
                 }
                 break;
             }
             bool spacePadPositive = false;
             int ntrunc = -1;
             const char *fmtEnd =
                 streamStateFromFormat(out, positionalMode, spacePadPositive,
                                       ntrunc, fmt, args, argIndex, numArgs);
             // NB: argIndex may be incremented by reading variable
             // width/precision in `streamStateFromFormat`, so do the bounds
             // check here.
             if (argIndex >= numArgs) {
                 TINYFORMAT_ERROR("tinyformat: Too many conversion specifiers "
                                  "in format string");
                 return;
             }
             const FormatArg &arg = args[argIndex];
             // Format the arg into the stream.
             if (!spacePadPositive) {
                 arg.format(out, fmt, fmtEnd, ntrunc);
             } else {
                 // The following is a special case with no direct correspondence
                 // between stream formatting and the printf() behaviour.
                 // Simulate it crudely by formatting into a temporary string
                 // stream and munging the resulting string.
                 std::ostringstream tmpStream;
                 tmpStream.copyfmt(out);
                 tmpStream.setf(std::ios::showpos);
                 arg.format(tmpStream, fmt, fmtEnd, ntrunc);
                 std::string result = tmpStream.str(); // allocates... yuck.
                 for (size_t i = 0, iend = result.size(); i < iend; ++i) {
                     if (result[i] == '+') result[i] = ' ';
                 }
                 out << result;
             }
             if (!positionalMode) ++argIndex;
             fmt = fmtEnd;
         }
 
         // Restore stream state
         out.width(origWidth);
         out.precision(origPrecision);
         out.flags(origFlags);
         out.fill(origFill);
     }
 
 } // namespace detail
 
 /// List of template arguments format(), held in a type-opaque way.
 ///
 /// A const reference to FormatList (typedef'd as FormatListRef) may be
 /// conveniently used to pass arguments to non-template functions: All type
 /// information has been stripped from the arguments, leaving just enough of a
 /// common interface to perform formatting as required.
 class FormatList {
 public:
     FormatList(detail::FormatArg *args, int N) : m_args(args), m_N(N) {}
 
     friend void vformat(std::ostream &out, const char *fmt,
                         const FormatList &list);
 
 private:
     const detail::FormatArg *m_args;
     int m_N;
 };
 
 /// Reference to type-opaque format list for passing to vformat()
 typedef const FormatList &FormatListRef;
 
 namespace detail {
 
     // Format list subclass with fixed storage to avoid dynamic allocation
     template <int N> class FormatListN : public FormatList {
     public:
 #ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
         template <typename... Args>
-        FormatListN(const Args &... args)
+        FormatListN(const Args &...args)
             : FormatList(&m_formatterStore[0], N), m_formatterStore{
                                                        FormatArg(args)...} {
             static_assert(sizeof...(args) == N, "Number of args must be N");
         }
 #else // C++98 version
         void init(int) {}
 #define TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR(n)                              \
                                                                                \
     template <TINYFORMAT_ARGTYPES(n)>                                          \
     FormatListN(TINYFORMAT_VARARGS(n)) : FormatList(&m_formatterStore[0], n) { \
         TINYFORMAT_ASSERT(n == N);                                             \
         init(0, TINYFORMAT_PASSARGS(n));                                       \
     }                                                                          \
                                                                                \
     template <TINYFORMAT_ARGTYPES(n)>                                          \
     void init(int i, TINYFORMAT_VARARGS(n)) {                                  \
         m_formatterStore[i] = FormatArg(v1);                                   \
         init(i + 1 TINYFORMAT_PASSARGS_TAIL(n));                               \
     }
 
         TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR)
 #undef TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR
 #endif
         FormatListN(const FormatListN &other)
             : FormatList(&m_formatterStore[0], N) {
             std::copy(&other.m_formatterStore[0], &other.m_formatterStore[N],
                       &m_formatterStore[0]);
         }
 
     private:
         FormatArg m_formatterStore[N];
     };
 
     // Special 0-arg version - MSVC says zero-sized C array in struct is
     // nonstandard.
     template <> class FormatListN<0> : public FormatList {
     public:
         FormatListN() : FormatList(0, 0) {}
     };
 
 } // namespace detail
 
 //------------------------------------------------------------------------------
 // Primary API functions
 
 #ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
 
 /// Make type-agnostic format list from list of template arguments.
 ///
 /// The exact return type of this function is an implementation detail and
 /// shouldn't be relied upon.  Instead it should be stored as a FormatListRef:
 ///
 ///   FormatListRef formatList = makeFormatList( /*...*/ );
 template <typename... Args>
-detail::FormatListN<sizeof...(Args)> makeFormatList(const Args &... args) {
+detail::FormatListN<sizeof...(Args)> makeFormatList(const Args &...args) {
     return detail::FormatListN<sizeof...(args)>(args...);
 }
 
 #else // C++98 version
 
 inline detail::FormatListN<0> makeFormatList() {
     return detail::FormatListN<0>();
 }
 #define TINYFORMAT_MAKE_MAKEFORMATLIST(n)                                      \
     template <TINYFORMAT_ARGTYPES(n)>                                          \
     detail::FormatListN<n> makeFormatList(TINYFORMAT_VARARGS(n)) {             \
         return detail::FormatListN<n>(TINYFORMAT_PASSARGS(n));                 \
     }
 TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_MAKEFORMATLIST)
 #undef TINYFORMAT_MAKE_MAKEFORMATLIST
 
 #endif
 
 /// Format list of arguments to the stream according to the given format string.
 ///
 /// The name vformat() is chosen for the semantic similarity to vprintf(): the
 /// list of format arguments is held in a single function argument.
 inline void vformat(std::ostream &out, const char *fmt, FormatListRef list) {
     detail::formatImpl(out, fmt, list.m_args, list.m_N);
 }
 
 #ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
 
 /// Format list of arguments to the stream according to given format string.
 template <typename... Args>
-void format(std::ostream &out, const char *fmt, const Args &... args) {
+void format(std::ostream &out, const char *fmt, const Args &...args) {
     vformat(out, fmt, makeFormatList(args...));
 }
 
 /// Format list of arguments according to the given format string and return the
 /// result as a string.
 template <typename... Args>
-std::string format(const char *fmt, const Args &... args) {
+std::string format(const char *fmt, const Args &...args) {
     std::ostringstream oss;
     format(oss, fmt, args...);
     return oss.str();
 }
 
 /// Format list of arguments to std::cout, according to the given format string
-template <typename... Args> void printf(const char *fmt, const Args &... args) {
+template <typename... Args> void printf(const char *fmt, const Args &...args) {
     format(std::cout, fmt, args...);
 }
 
 template <typename... Args>
-void printfln(const char *fmt, const Args &... args) {
+void printfln(const char *fmt, const Args &...args) {
     format(std::cout, fmt, args...);
     std::cout << '\n';
 }
 
 #else // C++98 version
 
 inline void format(std::ostream &out, const char *fmt) {
     vformat(out, fmt, makeFormatList());
 }
 
 inline std::string format(const char *fmt) {
     std::ostringstream oss;
     format(oss, fmt);
     return oss.str();
 }
 
 inline void printf(const char *fmt) {
     format(std::cout, fmt);
 }
 
 inline void printfln(const char *fmt) {
     format(std::cout, fmt);
     std::cout << '\n';
 }
 
 #define TINYFORMAT_MAKE_FORMAT_FUNCS(n)                                        \
                                                                                \
     template <TINYFORMAT_ARGTYPES(n)>                                          \
     void format(std::ostream &out, const char *fmt, TINYFORMAT_VARARGS(n)) {   \
         vformat(out, fmt, makeFormatList(TINYFORMAT_PASSARGS(n)));             \
     }                                                                          \
                                                                                \
     template <TINYFORMAT_ARGTYPES(n)>                                          \
     std::string format(const char *fmt, TINYFORMAT_VARARGS(n)) {               \
         std::ostringstream oss;                                                \
         format(oss, fmt, TINYFORMAT_PASSARGS(n));                              \
         return oss.str();                                                      \
     }                                                                          \
                                                                                \
     template <TINYFORMAT_ARGTYPES(n)>                                          \
     void printf(const char *fmt, TINYFORMAT_VARARGS(n)) {                      \
         format(std::cout, fmt, TINYFORMAT_PASSARGS(n));                        \
     }                                                                          \
                                                                                \
     template <TINYFORMAT_ARGTYPES(n)>                                          \
     void printfln(const char *fmt, TINYFORMAT_VARARGS(n)) {                    \
         format(std::cout, fmt, TINYFORMAT_PASSARGS(n));                        \
         std::cout << '\n';                                                     \
     }
 
 TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMAT_FUNCS)
 #undef TINYFORMAT_MAKE_FORMAT_FUNCS
 
 #endif
 
 // Added for Bitcoin
 template <typename... Args>
-std::string format(const std::string &fmt, const Args &... args) {
+std::string format(const std::string &fmt, const Args &...args) {
     std::ostringstream oss;
     format(oss, fmt.c_str(), args...);
     return oss.str();
 }
 
 } // namespace tinyformat
 
 // Added for Bitcoin:
 /**
  * Format arguments and return the string or write to given std::ostream (see
  * tinyformat::format doc for details)
  */
 #define strprintf tfm::format
 
 #endif // TINYFORMAT_H_INCLUDED
diff --git a/src/util/system.cpp b/src/util/system.cpp
index df23a77f0..45a7a6d8a 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -1,1420 +1,1420 @@
 // Copyright (c) 2009-2010 Satoshi Nakamoto
 // Copyright (c) 2009-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.
 
 #include <util/system.h>
 
 #include <chainparamsbase.h>
 #include <sync.h>
 #include <util/strencodings.h>
 #include <util/string.h>
 #include <util/translation.h>
 
 #include <univalue.h>
 
 #include <memory>
 #include <thread>
 #include <typeinfo>
 
 #if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
 #include <pthread.h>
 #include <pthread_np.h>
 #endif
 
 #ifndef WIN32
 // for posix_fallocate, in config/CMakeLists.txt we check if it is present after
 // this
 #ifdef __linux__
 
 #ifdef _POSIX_C_SOURCE
 #undef _POSIX_C_SOURCE
 #endif
 
 #define _POSIX_C_SOURCE 200112L
 
 #endif // __linux__
 
 #include <algorithm>
 #include <cassert>
 #include <fcntl.h>
 #include <sched.h>
 #include <sys/resource.h>
 #include <sys/stat.h>
 
 #else
 
 #ifdef _MSC_VER
 #pragma warning(disable : 4786)
 #pragma warning(disable : 4804)
 #pragma warning(disable : 4805)
 #pragma warning(disable : 4717)
 #endif
 
 #ifndef NOMINMAX
 #define NOMINMAX
 #endif
 #include <codecvt>
 
 #include <io.h> /* for _commit */
 #include <shellapi.h>
 #include <shlobj.h>
 #endif
 
 #ifdef HAVE_MALLOPT_ARENA_MAX
 #include <malloc.h>
 #endif
 
 #include <boost/algorithm/string/replace.hpp>
 
 // Application startup time (used for uptime calculation)
 const int64_t nStartupTime = GetTime();
 
 const char *const BITCOIN_CONF_FILENAME = "bitcoin.conf";
 const char *const BITCOIN_SETTINGS_FILENAME = "settings.json";
 
 ArgsManager gArgs;
 
 /** Mutex to protect dir_locks. */
 static Mutex cs_dir_locks;
 /**
  * A map that contains all the currently held directory locks. After successful
  * locking, these will be held here until the global destructor cleans them up
  * and thus automatically unlocks them, or ReleaseDirectoryLocks is called.
  */
 static std::map<std::string, std::unique_ptr<fsbridge::FileLock>>
     dir_locks GUARDED_BY(cs_dir_locks);
 
 bool LockDirectory(const fs::path &directory, const std::string lockfile_name,
                    bool probe_only) {
     LOCK(cs_dir_locks);
     fs::path pathLockFile = directory / lockfile_name;
 
     // If a lock for this directory already exists in the map, don't try to
     // re-lock it
     if (dir_locks.count(fs::PathToString(pathLockFile))) {
         return true;
     }
 
     // Create empty lock file if it doesn't exist.
     FILE *file = fsbridge::fopen(pathLockFile, "a");
     if (file) {
         fclose(file);
     }
     auto lock = std::make_unique<fsbridge::FileLock>(pathLockFile);
     if (!lock->TryLock()) {
         return error("Error while attempting to lock directory %s: %s",
                      fs::PathToString(directory), lock->GetReason());
     }
     if (!probe_only) {
         // Lock successful and we're not just probing, put it into the map
         dir_locks.emplace(fs::PathToString(pathLockFile), std::move(lock));
     }
     return true;
 }
 
 void UnlockDirectory(const fs::path &directory,
                      const std::string &lockfile_name) {
     LOCK(cs_dir_locks);
     dir_locks.erase(fs::PathToString(directory / lockfile_name));
 }
 
 void ReleaseDirectoryLocks() {
     LOCK(cs_dir_locks);
     dir_locks.clear();
 }
 
 bool DirIsWritable(const fs::path &directory) {
     fs::path tmpFile = directory / fs::unique_path();
 
     FILE *file = fsbridge::fopen(tmpFile, "a");
     if (!file) {
         return false;
     }
 
     fclose(file);
     remove(tmpFile);
 
     return true;
 }
 
 bool CheckDiskSpace(const fs::path &dir, uint64_t additional_bytes) {
     // 50 MiB
     constexpr uint64_t min_disk_space = 52428800;
 
     uint64_t free_bytes_available = fs::space(dir).available;
     return free_bytes_available >= min_disk_space + additional_bytes;
 }
 
 std::streampos GetFileSize(const char *path, std::streamsize max) {
     std::ifstream file(path, std::ios::binary);
     file.ignore(max);
     return file.gcount();
 }
 
 /**
  * Interpret a string argument as a boolean.
  *
  * The definition of atoi() requires that non-numeric string values like "foo",
  * return 0. This means that if a user unintentionally supplies a non-integer
  * argument here, the return value is always false. This means that -foo=false
  * does what the user probably expects, but -foo=true is well defined but does
  * not do what they probably expected.
  *
  * The return value of atoi() is undefined when given input not representable as
  * an int. On most systems this means string value between "-2147483648" and
  * "2147483647" are well defined (this method will return true). Setting
  * -txindex=2147483648 on most systems, however, is probably undefined.
  *
  * For a more extensive discussion of this topic (and a wide range of opinions
  * on the Right Way to change this code), see PR12713.
  */
 static bool InterpretBool(const std::string &strValue) {
     if (strValue.empty()) {
         return true;
     }
     return (atoi(strValue) != 0);
 }
 
 static std::string SettingName(const std::string &arg) {
     return arg.size() > 0 && arg[0] == '-' ? arg.substr(1) : arg;
 }
 
 /**
  * Interpret -nofoo as if the user supplied -foo=0.
  *
  * This method also tracks when the -no form was supplied, and if so, checks
  * whether there was a double-negative (-nofoo=0 -> -foo=1).
  *
  * If there was not a double negative, it removes the "no" from the key
  * and returns false.
  *
  * If there was a double negative, it removes "no" from the key, and
  * returns true.
  *
  * If there was no "no", it returns the string value untouched.
  *
  * Where an option was negated can be later checked using the IsArgNegated()
  * method. One use case for this is to have a way to disable options that are
  * not normally boolean (e.g. using -nodebuglogfile to request that debug log
  * output is not sent to any file at all).
  */
 
 static util::SettingsValue InterpretOption(std::string &section,
                                            std::string &key,
                                            const std::string &value) {
     // Split section name from key name for keys like "testnet.foo" or
     // "regtest.bar"
     size_t option_index = key.find('.');
     if (option_index != std::string::npos) {
         section = key.substr(0, option_index);
         key.erase(0, option_index + 1);
     }
     if (key.substr(0, 2) == "no") {
         key.erase(0, 2);
         // Double negatives like -nofoo=0 are supported (but discouraged)
         if (!InterpretBool(value)) {
             LogPrintf("Warning: parsed potentially confusing double-negative "
                       "-%s=%s\n",
                       key, value);
             return true;
         }
         return false;
     }
     return value;
 }
 
 /**
  * Check settings value validity according to flags.
  *
  * TODO: Add more meaningful error checks here in the future
  * See "here's how the flags are meant to behave" in
  * https://github.com/bitcoin/bitcoin/pull/16097#issuecomment-514627823
  */
 static bool CheckValid(const std::string &key, const util::SettingsValue &val,
                        unsigned int flags, std::string &error) {
     if (val.isBool() && !(flags & ArgsManager::ALLOW_BOOL)) {
         error = strprintf(
             "Negating of -%s is meaningless and therefore forbidden", key);
         return false;
     }
     return true;
 }
 
 namespace {
 fs::path StripRedundantLastElementsOfPath(const fs::path &path) {
     auto result = path;
     while (fs::PathToString(result.filename()) == ".") {
         result = result.parent_path();
     }
 
     assert(fs::equivalent(result, path));
     return result;
 }
 } // namespace
 
 // Define default constructor and destructor that are not inline, so code
 // instantiating this class doesn't need to #include class definitions for all
 // members. For example, m_settings has an internal dependency on univalue.
 ArgsManager::ArgsManager() {}
 ArgsManager::~ArgsManager() {}
 
 const std::set<std::string> ArgsManager::GetUnsuitableSectionOnlyArgs() const {
     std::set<std::string> unsuitables;
 
     LOCK(cs_args);
 
     // if there's no section selected, don't worry
     if (m_network.empty()) {
         return std::set<std::string>{};
     }
 
     // if it's okay to use the default section for this network, don't worry
     if (m_network == CBaseChainParams::MAIN) {
         return std::set<std::string>{};
     }
 
     for (const auto &arg : m_network_only_args) {
         if (OnlyHasDefaultSectionSetting(m_settings, m_network,
                                          SettingName(arg))) {
             unsuitables.insert(arg);
         }
     }
     return unsuitables;
 }
 
 const std::list<SectionInfo> ArgsManager::GetUnrecognizedSections() const {
     // Section names to be recognized in the config file.
     static const std::set<std::string> available_sections{
         CBaseChainParams::REGTEST, CBaseChainParams::TESTNET,
         CBaseChainParams::MAIN};
 
     LOCK(cs_args);
     std::list<SectionInfo> unrecognized = m_config_sections;
     unrecognized.remove_if([](const SectionInfo &appeared) {
         return available_sections.find(appeared.m_name) !=
                available_sections.end();
     });
     return unrecognized;
 }
 
 void ArgsManager::SelectConfigNetwork(const std::string &network) {
     LOCK(cs_args);
     m_network = network;
 }
 
 bool ParseKeyValue(std::string &key, std::string &val) {
     size_t is_index = key.find('=');
     if (is_index != std::string::npos) {
         val = key.substr(is_index + 1);
         key.erase(is_index);
     }
 #ifdef WIN32
     key = ToLower(key);
     if (key[0] == '/') {
         key[0] = '-';
     }
 #endif
 
     if (key[0] != '-') {
         return false;
     }
 
     // Transform --foo to -foo
     if (key.length() > 1 && key[1] == '-') {
         key.erase(0, 1);
     }
     return true;
 }
 
 bool ArgsManager::ParseParameters(int argc, const char *const argv[],
                                   std::string &error) {
     LOCK(cs_args);
     m_settings.command_line_options.clear();
 
     for (int i = 1; i < argc; i++) {
         std::string key(argv[i]);
 
 #ifdef MAC_OSX
         // At the first time when a user gets the "App downloaded from the
         // internet" warning, and clicks the Open button, macOS passes
         // a unique process serial number (PSN) as -psn_... command-line
         // argument, which we filter out.
         if (key.substr(0, 5) == "-psn_") {
             continue;
         }
 #endif
 
         if (key == "-") {
             // bitcoin-tx using stdin
             break;
         }
         std::string val;
         if (!ParseKeyValue(key, val)) {
             break;
         }
 
         // Transform -foo to foo
         key.erase(0, 1);
         std::string section;
         util::SettingsValue value = InterpretOption(section, key, val);
         std::optional<unsigned int> flags = GetArgFlags('-' + key);
 
         // Unknown command line options and command line options with dot
         // characters (which are returned from InterpretOption with nonempty
         // section strings) are not valid.
         if (!flags || !section.empty()) {
             error = strprintf("Invalid parameter %s", argv[i]);
             return false;
         }
 
         if (!CheckValid(key, value, *flags, error)) {
             return false;
         }
 
         m_settings.command_line_options[key].push_back(value);
     }
 
     // we do not allow -includeconf from command line
     bool success = true;
     if (auto *includes =
             util::FindKey(m_settings.command_line_options, "includeconf")) {
         for (const auto &include : util::SettingsSpan(*includes)) {
             error +=
                 "-includeconf cannot be used from commandline; -includeconf=" +
                 include.get_str() + "\n";
             success = false;
         }
     }
     return success;
 }
 
 std::optional<unsigned int>
 ArgsManager::GetArgFlags(const std::string &name) const {
     LOCK(cs_args);
     for (const auto &arg_map : m_available_args) {
         const auto search = arg_map.second.find(name);
         if (search != arg_map.second.end()) {
             return search->second.m_flags;
         }
     }
     return std::nullopt;
 }
 
 const fs::path &ArgsManager::GetBlocksDirPath() {
     LOCK(cs_args);
     fs::path &path = m_cached_blocks_path;
 
     // Cache the path to avoid calling fs::create_directories on every call of
     // this function
     if (!path.empty()) {
         return path;
     }
 
     if (IsArgSet("-blocksdir")) {
         path =
             fs::system_complete(fs::PathFromString(GetArg("-blocksdir", "")));
         if (!fs::is_directory(path)) {
             path = "";
             return path;
         }
     } else {
         path = GetDataDirPath(false);
     }
 
     path /= fs::PathFromString(BaseParams().DataDir());
     path /= "blocks";
     fs::create_directories(path);
     path = StripRedundantLastElementsOfPath(path);
     return path;
 }
 
 const fs::path &ArgsManager::GetDataDirPath(bool net_specific) const {
     LOCK(cs_args);
     fs::path &path =
         net_specific ? m_cached_network_datadir_path : m_cached_datadir_path;
 
     // Cache the path to avoid calling fs::create_directories on every call of
     // this function
     if (!path.empty()) {
         return path;
     }
     std::string datadir = GetArg("-datadir", "");
     if (!datadir.empty()) {
         path = fs::system_complete(fs::PathFromString(datadir));
         if (!fs::is_directory(path)) {
             path = "";
             return path;
         }
     } else {
         path = GetDefaultDataDir();
     }
     if (net_specific) {
         path /= fs::PathFromString(BaseParams().DataDir());
     }
 
     if (fs::create_directories(path)) {
         // This is the first run, create wallets subdirectory too
         fs::create_directories(path / "wallets");
     }
 
     path = StripRedundantLastElementsOfPath(path);
     return path;
 }
 
 void ArgsManager::ClearPathCache() {
     LOCK(cs_args);
 
     m_cached_datadir_path = fs::path();
     m_cached_network_datadir_path = fs::path();
     m_cached_blocks_path = fs::path();
 }
 
 std::vector<std::string> ArgsManager::GetArgs(const std::string &strArg) const {
     std::vector<std::string> result;
     for (const util::SettingsValue &value : GetSettingsList(strArg)) {
-        result.push_back(
-            value.isFalse() ? "0" : value.isTrue() ? "1" : value.get_str());
+        result.push_back(value.isFalse()  ? "0"
+                         : value.isTrue() ? "1"
+                                          : value.get_str());
     }
     return result;
 }
 
 bool ArgsManager::IsArgSet(const std::string &strArg) const {
     return !GetSetting(strArg).isNull();
 }
 
 bool ArgsManager::InitSettings(std::string &error) {
     if (!GetSettingsPath()) {
         return true; // Do nothing if settings file disabled.
     }
 
     std::vector<std::string> errors;
     if (!ReadSettingsFile(&errors)) {
         error = strprintf("Failed loading settings file:\n- %s\n",
                           Join(errors, "\n- "));
         return false;
     }
     if (!WriteSettingsFile(&errors)) {
         error = strprintf("Failed saving settings file:\n- %s\n",
                           Join(errors, "\n- "));
         return false;
     }
     return true;
 }
 
 bool ArgsManager::GetSettingsPath(fs::path *filepath, bool temp) const {
     if (IsArgNegated("-settings")) {
         return false;
     }
     if (filepath) {
         std::string settings = GetArg("-settings", BITCOIN_SETTINGS_FILENAME);
         *filepath = fs::absolute(
             fs::PathFromString(temp ? settings + ".tmp" : settings),
             GetDataDirPath(/* net_specific= */ true));
     }
     return true;
 }
 
 static void SaveErrors(const std::vector<std::string> errors,
                        std::vector<std::string> *error_out) {
     for (const auto &error : errors) {
         if (error_out) {
             error_out->emplace_back(error);
         } else {
             LogPrintf("%s\n", error);
         }
     }
 }
 
 bool ArgsManager::ReadSettingsFile(std::vector<std::string> *errors) {
     fs::path path;
     if (!GetSettingsPath(&path, /* temp= */ false)) {
         return true; // Do nothing if settings file disabled.
     }
 
     LOCK(cs_args);
     m_settings.rw_settings.clear();
     std::vector<std::string> read_errors;
     if (!util::ReadSettings(path, m_settings.rw_settings, read_errors)) {
         SaveErrors(read_errors, errors);
         return false;
     }
     for (const auto &setting : m_settings.rw_settings) {
         std::string section;
         std::string key = setting.first;
         // Split setting key into section and argname
         (void)InterpretOption(section, key, /* value */ {});
         if (!GetArgFlags('-' + key)) {
             LogPrintf("Ignoring unknown rw_settings value %s\n", setting.first);
         }
     }
     return true;
 }
 
 bool ArgsManager::WriteSettingsFile(std::vector<std::string> *errors) const {
     fs::path path, path_tmp;
     if (!GetSettingsPath(&path, /* temp= */ false) ||
         !GetSettingsPath(&path_tmp, /* temp= */ true)) {
         throw std::logic_error("Attempt to write settings file when dynamic "
                                "settings are disabled.");
     }
 
     LOCK(cs_args);
     std::vector<std::string> write_errors;
     if (!util::WriteSettings(path_tmp, m_settings.rw_settings, write_errors)) {
         SaveErrors(write_errors, errors);
         return false;
     }
     if (!RenameOver(path_tmp, path)) {
         SaveErrors(
             {strprintf("Failed renaming settings file %s to %s\n",
                        fs::PathToString(path_tmp), fs::PathToString(path))},
             errors);
         return false;
     }
     return true;
 }
 
 bool ArgsManager::IsArgNegated(const std::string &strArg) const {
     return GetSetting(strArg).isFalse();
 }
 
 std::string ArgsManager::GetArg(const std::string &strArg,
                                 const std::string &strDefault) const {
     const util::SettingsValue value = GetSetting(strArg);
-    return value.isNull()
-               ? strDefault
-               : value.isFalse() ? "0" : value.isTrue() ? "1" : value.get_str();
+    return value.isNull()    ? strDefault
+           : value.isFalse() ? "0"
+           : value.isTrue()  ? "1"
+                             : value.get_str();
 }
 
 int64_t ArgsManager::GetArg(const std::string &strArg, int64_t nDefault) const {
     const util::SettingsValue value = GetSetting(strArg);
-    return value.isNull()
-               ? nDefault
-               : value.isFalse()
-                     ? 0
-                     : value.isTrue() ? 1
-                                      : value.isNum() ? value.get_int64()
-                                                      : atoi64(value.get_str());
+    return value.isNull()    ? nDefault
+           : value.isFalse() ? 0
+           : value.isTrue()  ? 1
+           : value.isNum()   ? value.get_int64()
+                             : atoi64(value.get_str());
 }
 
 bool ArgsManager::GetBoolArg(const std::string &strArg, bool fDefault) const {
     const util::SettingsValue value = GetSetting(strArg);
-    return value.isNull() ? fDefault
-                          : value.isBool() ? value.get_bool()
-                                           : InterpretBool(value.get_str());
+    return value.isNull()   ? fDefault
+           : value.isBool() ? value.get_bool()
+                            : InterpretBool(value.get_str());
 }
 
 bool ArgsManager::SoftSetArg(const std::string &strArg,
                              const std::string &strValue) {
     LOCK(cs_args);
     if (IsArgSet(strArg)) {
         return false;
     }
     ForceSetArg(strArg, strValue);
     return true;
 }
 
 bool ArgsManager::SoftSetBoolArg(const std::string &strArg, bool fValue) {
     if (fValue) {
         return SoftSetArg(strArg, std::string("1"));
     } else {
         return SoftSetArg(strArg, std::string("0"));
     }
 }
 
 void ArgsManager::ForceSetArg(const std::string &strArg,
                               const std::string &strValue) {
     LOCK(cs_args);
     m_settings.forced_settings[SettingName(strArg)] = strValue;
 }
 
 /**
  * This function is only used for testing purpose so
  * so we should not worry about element uniqueness and
  * integrity of mapMultiArgs data structure
  */
 void ArgsManager::ForceSetMultiArg(const std::string &strArg,
                                    const std::vector<std::string> &values) {
     LOCK(cs_args);
     util::SettingsValue value;
     value.setArray();
     for (const std::string &s : values) {
         value.push_back(s);
     }
 
     m_settings.forced_settings[SettingName(strArg)] = value;
 }
 
 void ArgsManager::AddArg(const std::string &name, const std::string &help,
                          unsigned int flags, const OptionsCategory &cat) {
     // Split arg name from its help param
     size_t eq_index = name.find('=');
     if (eq_index == std::string::npos) {
         eq_index = name.size();
     }
     std::string arg_name = name.substr(0, eq_index);
 
     LOCK(cs_args);
     std::map<std::string, Arg> &arg_map = m_available_args[cat];
     auto ret = arg_map.emplace(
         arg_name,
         Arg{name.substr(eq_index, name.size() - eq_index), help, flags});
     // Make sure an insertion actually happened.
     assert(ret.second);
 
     if (flags & ArgsManager::NETWORK_ONLY) {
         m_network_only_args.emplace(arg_name);
     }
 }
 
 void ArgsManager::AddHiddenArgs(const std::vector<std::string> &names) {
     for (const std::string &name : names) {
         AddArg(name, "", ArgsManager::ALLOW_ANY, OptionsCategory::HIDDEN);
     }
 }
 
 void ArgsManager::ClearForcedArg(const std::string &strArg) {
     LOCK(cs_args);
     m_settings.forced_settings.erase(SettingName(strArg));
 }
 
 std::string ArgsManager::GetHelpMessage() const {
     const bool show_debug = GetBoolArg("-help-debug", false);
 
     std::string usage = "";
     LOCK(cs_args);
     for (const auto &arg_map : m_available_args) {
         switch (arg_map.first) {
             case OptionsCategory::OPTIONS:
                 usage += HelpMessageGroup("Options:");
                 break;
             case OptionsCategory::CONNECTION:
                 usage += HelpMessageGroup("Connection options:");
                 break;
             case OptionsCategory::ZMQ:
                 usage += HelpMessageGroup("ZeroMQ notification options:");
                 break;
             case OptionsCategory::DEBUG_TEST:
                 usage += HelpMessageGroup("Debugging/Testing options:");
                 break;
             case OptionsCategory::NODE_RELAY:
                 usage += HelpMessageGroup("Node relay options:");
                 break;
             case OptionsCategory::BLOCK_CREATION:
                 usage += HelpMessageGroup("Block creation options:");
                 break;
             case OptionsCategory::RPC:
                 usage += HelpMessageGroup("RPC server options:");
                 break;
             case OptionsCategory::WALLET:
                 usage += HelpMessageGroup("Wallet options:");
                 break;
             case OptionsCategory::WALLET_DEBUG_TEST:
                 if (show_debug) {
                     usage +=
                         HelpMessageGroup("Wallet debugging/testing options:");
                 }
                 break;
             case OptionsCategory::CHAINPARAMS:
                 usage += HelpMessageGroup("Chain selection options:");
                 break;
             case OptionsCategory::GUI:
                 usage += HelpMessageGroup("UI Options:");
                 break;
             case OptionsCategory::COMMANDS:
                 usage += HelpMessageGroup("Commands:");
                 break;
             case OptionsCategory::REGISTER_COMMANDS:
                 usage += HelpMessageGroup("Register Commands:");
                 break;
             default:
                 break;
         }
 
         // When we get to the hidden options, stop
         if (arg_map.first == OptionsCategory::HIDDEN) {
             break;
         }
 
         for (const auto &arg : arg_map.second) {
             if (show_debug || !(arg.second.m_flags & ArgsManager::DEBUG_ONLY)) {
                 std::string name;
                 if (arg.second.m_help_param.empty()) {
                     name = arg.first;
                 } else {
                     name = arg.first + arg.second.m_help_param;
                 }
                 usage += HelpMessageOpt(name, arg.second.m_help_text);
             }
         }
     }
     return usage;
 }
 
 bool HelpRequested(const ArgsManager &args) {
     return args.IsArgSet("-?") || args.IsArgSet("-h") ||
            args.IsArgSet("-help") || args.IsArgSet("-help-debug");
 }
 
 void SetupHelpOptions(ArgsManager &args) {
     args.AddArg("-?", "Print this help message and exit", false,
                 OptionsCategory::OPTIONS);
     args.AddHiddenArgs({"-h", "-help"});
 }
 
 static const int screenWidth = 79;
 static const int optIndent = 2;
 static const int msgIndent = 7;
 
 std::string HelpMessageGroup(const std::string &message) {
     return std::string(message) + std::string("\n\n");
 }
 
 std::string HelpMessageOpt(const std::string &option,
                            const std::string &message) {
     return std::string(optIndent, ' ') + std::string(option) +
            std::string("\n") + std::string(msgIndent, ' ') +
            FormatParagraph(message, screenWidth - msgIndent, msgIndent) +
            std::string("\n\n");
 }
 
 static std::string FormatException(const std::exception *pex,
                                    const char *pszThread) {
 #ifdef WIN32
     char pszModule[MAX_PATH] = "";
     GetModuleFileNameA(nullptr, pszModule, sizeof(pszModule));
 #else
     const char *pszModule = "bitcoin";
 #endif
     if (pex) {
         return strprintf("EXCEPTION: %s       \n%s       \n%s in %s       \n",
                          typeid(*pex).name(), pex->what(), pszModule,
                          pszThread);
     } else {
         return strprintf("UNKNOWN EXCEPTION       \n%s in %s       \n",
                          pszModule, pszThread);
     }
 }
 
 void PrintExceptionContinue(const std::exception *pex, const char *pszThread) {
     std::string message = FormatException(pex, pszThread);
     LogPrintf("\n\n************************\n%s\n", message);
     tfm::format(std::cerr, "\n\n************************\n%s\n", message);
 }
 
 fs::path GetDefaultDataDir() {
     // Windows: C:\Users\Username\AppData\Roaming\Bitcoin
     // macOS: ~/Library/Application Support/Bitcoin
     // Unix-like: ~/.bitcoin
 #ifdef WIN32
     // Windows
     return GetSpecialFolderPath(CSIDL_APPDATA) / "Bitcoin";
 #else
     fs::path pathRet;
     char *pszHome = getenv("HOME");
     if (pszHome == nullptr || strlen(pszHome) == 0) {
         pathRet = fs::path("/");
     } else {
         pathRet = fs::path(pszHome);
     }
 #ifdef MAC_OSX
     // macOS
     return pathRet / "Library/Application Support/Bitcoin";
 #else
     // Unix-like
     return pathRet / ".bitcoin";
 #endif
 #endif
 }
 
 const fs::path &GetDataDir(bool fNetSpecific) {
     return gArgs.GetDataDirPath(fNetSpecific);
 }
 
 bool CheckDataDirOption() {
     std::string datadir = gArgs.GetArg("-datadir", "");
     return datadir.empty() ||
            fs::is_directory(fs::system_complete(fs::PathFromString(datadir)));
 }
 
 fs::path GetConfigFile(const std::string &confPath) {
     return AbsPathForConfigVal(fs::PathFromString(confPath), false);
 }
 
 static bool
 GetConfigOptions(std::istream &stream, const std::string &filepath,
                  std::string &error,
                  std::vector<std::pair<std::string, std::string>> &options,
                  std::list<SectionInfo> &sections) {
     std::string str, prefix;
     std::string::size_type pos;
     int linenr = 1;
     while (std::getline(stream, str)) {
         bool used_hash = false;
         if ((pos = str.find('#')) != std::string::npos) {
             str = str.substr(0, pos);
             used_hash = true;
         }
         const static std::string pattern = " \t\r\n";
         str = TrimString(str, pattern);
         if (!str.empty()) {
             if (*str.begin() == '[' && *str.rbegin() == ']') {
                 const std::string section = str.substr(1, str.size() - 2);
                 sections.emplace_back(SectionInfo{section, filepath, linenr});
                 prefix = section + '.';
             } else if (*str.begin() == '-') {
                 error = strprintf(
                     "parse error on line %i: %s, options in configuration file "
                     "must be specified without leading -",
                     linenr, str);
                 return false;
             } else if ((pos = str.find('=')) != std::string::npos) {
                 std::string name =
                     prefix + TrimString(str.substr(0, pos), pattern);
                 std::string value = TrimString(str.substr(pos + 1), pattern);
                 if (used_hash &&
                     name.find("rpcpassword") != std::string::npos) {
                     error = strprintf(
                         "parse error on line %i, using # in rpcpassword can be "
                         "ambiguous and should be avoided",
                         linenr);
                     return false;
                 }
                 options.emplace_back(name, value);
                 if ((pos = name.rfind('.')) != std::string::npos &&
                     prefix.length() <= pos) {
                     sections.emplace_back(
                         SectionInfo{name.substr(0, pos), filepath, linenr});
                 }
             } else {
                 error = strprintf("parse error on line %i: %s", linenr, str);
                 if (str.size() >= 2 && str.substr(0, 2) == "no") {
                     error += strprintf(", if you intended to specify a negated "
                                        "option, use %s=1 instead",
                                        str);
                 }
                 return false;
             }
         }
         ++linenr;
     }
     return true;
 }
 
 bool ArgsManager::ReadConfigStream(std::istream &stream,
                                    const std::string &filepath,
                                    std::string &error,
                                    bool ignore_invalid_keys) {
     LOCK(cs_args);
     std::vector<std::pair<std::string, std::string>> options;
     if (!GetConfigOptions(stream, filepath, error, options,
                           m_config_sections)) {
         return false;
     }
     for (const std::pair<std::string, std::string> &option : options) {
         std::string section;
         std::string key = option.first;
         util::SettingsValue value =
             InterpretOption(section, key, option.second);
         std::optional<unsigned int> flags = GetArgFlags('-' + key);
         if (flags) {
             if (!CheckValid(key, value, *flags, error)) {
                 return false;
             }
             m_settings.ro_config[section][key].push_back(value);
         } else {
             if (ignore_invalid_keys) {
                 LogPrintf("Ignoring unknown configuration value %s\n",
                           option.first);
             } else {
                 error = strprintf("Invalid configuration value %s",
                                   option.first.c_str());
                 return false;
             }
         }
     }
     return true;
 }
 
 bool ArgsManager::ReadConfigFiles(std::string &error,
                                   bool ignore_invalid_keys) {
     {
         LOCK(cs_args);
         m_settings.ro_config.clear();
         m_config_sections.clear();
     }
 
     const std::string confPath = GetArg("-conf", BITCOIN_CONF_FILENAME);
     fsbridge::ifstream stream(GetConfigFile(confPath));
 
     // ok to not have a config file
     if (stream.good()) {
         if (!ReadConfigStream(stream, confPath, error, ignore_invalid_keys)) {
             return false;
         }
         // `-includeconf` cannot be included in the command line arguments
         // except as `-noincludeconf` (which indicates that no included conf
         // file should be used).
         bool use_conf_file{true};
         {
             LOCK(cs_args);
             if (auto *includes = util::FindKey(m_settings.command_line_options,
                                                "includeconf")) {
                 // ParseParameters() fails if a non-negated -includeconf is
                 // passed on the command-line
                 assert(util::SettingsSpan(*includes).last_negated());
                 use_conf_file = false;
             }
         }
         if (use_conf_file) {
             std::string chain_id = GetChainName();
             std::vector<std::string> conf_file_names;
 
             auto add_includes = [&](const std::string &network,
                                     size_t skip = 0) {
                 size_t num_values = 0;
                 LOCK(cs_args);
                 if (auto *section =
                         util::FindKey(m_settings.ro_config, network)) {
                     if (auto *values = util::FindKey(*section, "includeconf")) {
                         for (size_t i = std::max(
                                  skip, util::SettingsSpan(*values).negated());
                              i < values->size(); ++i) {
                             conf_file_names.push_back((*values)[i].get_str());
                         }
                         num_values = values->size();
                     }
                 }
                 return num_values;
             };
 
             // We haven't set m_network yet (that happens in SelectParams()), so
             // manually check for network.includeconf args.
             const size_t chain_includes = add_includes(chain_id);
             const size_t default_includes = add_includes({});
 
             for (const std::string &conf_file_name : conf_file_names) {
                 fsbridge::ifstream conf_file_stream(
                     GetConfigFile(conf_file_name));
                 if (conf_file_stream.good()) {
                     if (!ReadConfigStream(conf_file_stream, conf_file_name,
                                           error, ignore_invalid_keys)) {
                         return false;
                     }
                     LogPrintf("Included configuration file %s\n",
                               conf_file_name);
                 } else {
                     error = "Failed to include configuration file " +
                             conf_file_name;
                     return false;
                 }
             }
 
             // Warn about recursive -includeconf
             conf_file_names.clear();
             add_includes(chain_id, /* skip= */ chain_includes);
             add_includes({}, /* skip= */ default_includes);
             std::string chain_id_final = GetChainName();
             if (chain_id_final != chain_id) {
                 // Also warn about recursive includeconf for the chain that was
                 // specified in one of the includeconfs
                 add_includes(chain_id_final);
             }
             for (const std::string &conf_file_name : conf_file_names) {
                 tfm::format(std::cerr,
                             "warning: -includeconf cannot be used from "
                             "included files; ignoring -includeconf=%s\n",
                             conf_file_name);
             }
         }
     }
 
     // If datadir is changed in .conf file:
     gArgs.ClearPathCache();
     if (!CheckDataDirOption()) {
         error = strprintf("specified data directory \"%s\" does not exist.",
                           GetArg("-datadir", "").c_str());
         return false;
     }
     return true;
 }
 
 std::string ArgsManager::GetChainName() const {
     auto get_net = [&](const std::string &arg) {
         LOCK(cs_args);
         util::SettingsValue value =
             util::GetSetting(m_settings, /* section= */ "", SettingName(arg),
                              /* ignore_default_section_config= */ false,
                              /* get_chain_name= */ true);
-        return value.isNull() ? false
-                              : value.isBool() ? value.get_bool()
-                                               : InterpretBool(value.get_str());
+        return value.isNull()   ? false
+               : value.isBool() ? value.get_bool()
+                                : InterpretBool(value.get_str());
     };
 
     const bool fRegTest = get_net("-regtest");
     const bool fTestNet = get_net("-testnet");
     const bool is_chain_arg_set = IsArgSet("-chain");
 
     if (int(is_chain_arg_set) + int(fRegTest) + int(fTestNet) > 1) {
         throw std::runtime_error("Invalid combination of -regtest, -testnet "
                                  "and -chain. Can use at most one.");
     }
     if (fRegTest) {
         return CBaseChainParams::REGTEST;
     }
     if (fTestNet) {
         return CBaseChainParams::TESTNET;
     }
     return GetArg("-chain", CBaseChainParams::MAIN);
 }
 
 bool ArgsManager::UseDefaultSection(const std::string &arg) const {
     return m_network == CBaseChainParams::MAIN ||
            m_network_only_args.count(arg) == 0;
 }
 
 util::SettingsValue ArgsManager::GetSetting(const std::string &arg) const {
     LOCK(cs_args);
     return util::GetSetting(m_settings, m_network, SettingName(arg),
                             !UseDefaultSection(arg),
                             /* get_chain_name= */ false);
 }
 
 std::vector<util::SettingsValue>
 ArgsManager::GetSettingsList(const std::string &arg) const {
     LOCK(cs_args);
     return util::GetSettingsList(m_settings, m_network, SettingName(arg),
                                  !UseDefaultSection(arg));
 }
 
 void ArgsManager::logArgsPrefix(
     const std::string &prefix, const std::string &section,
     const std::map<std::string, std::vector<util::SettingsValue>> &args) const {
     std::string section_str = section.empty() ? "" : "[" + section + "] ";
     for (const auto &arg : args) {
         for (const auto &value : arg.second) {
             std::optional<unsigned int> flags = GetArgFlags('-' + arg.first);
             if (flags) {
                 std::string value_str =
                     (*flags & SENSITIVE) ? "****" : value.write();
                 LogPrintf("%s %s%s=%s\n", prefix, section_str, arg.first,
                           value_str);
             }
         }
     }
 }
 
 void ArgsManager::LogArgs() const {
     LOCK(cs_args);
     for (const auto &section : m_settings.ro_config) {
         logArgsPrefix("Config file arg:", section.first, section.second);
     }
     for (const auto &setting : m_settings.rw_settings) {
         LogPrintf("Setting file arg: %s = %s\n", setting.first,
                   setting.second.write());
     }
     logArgsPrefix("Command-line arg:", "", m_settings.command_line_options);
 }
 
 bool RenameOver(fs::path src, fs::path dest) {
 #ifdef WIN32
     return MoveFileExW(src.wstring().c_str(), dest.wstring().c_str(),
                        MOVEFILE_REPLACE_EXISTING) != 0;
 #else
     int rc = std::rename(src.c_str(), dest.c_str());
     return (rc == 0);
 #endif /* WIN32 */
 }
 
 /**
  * Ignores exceptions thrown by Boost's create_directories if the requested
  * directory exists. Specifically handles case where path p exists, but it
  * wasn't possible for the user to write to the parent directory.
  */
 bool TryCreateDirectories(const fs::path &p) {
     try {
         return fs::create_directories(p);
     } catch (const fs::filesystem_error &) {
         if (!fs::exists(p) || !fs::is_directory(p)) {
             throw;
         }
     }
 
     // create_directory didn't create the directory, it had to have existed
     // already.
     return false;
 }
 
 bool FileCommit(FILE *file) {
     // harmless if redundantly called
     if (fflush(file) != 0) {
         LogPrintf("%s: fflush failed: %d\n", __func__, errno);
         return false;
     }
 #ifdef WIN32
     HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
     if (FlushFileBuffers(hFile) == 0) {
         LogPrintf("%s: FlushFileBuffers failed: %d\n", __func__,
                   GetLastError());
         return false;
     }
 #else
 #if defined(HAVE_FDATASYNC)
     // Ignore EINVAL for filesystems that don't support sync
     if (fdatasync(fileno(file)) != 0 && errno != EINVAL) {
         LogPrintf("%s: fdatasync failed: %d\n", __func__, errno);
         return false;
     }
 #elif defined(MAC_OSX) && defined(F_FULLFSYNC)
     // Manpage says "value other than -1" is returned on success
     if (fcntl(fileno(file), F_FULLFSYNC, 0) == -1) {
         LogPrintf("%s: fcntl F_FULLFSYNC failed: %d\n", __func__, errno);
         return false;
     }
 #else
     if (fsync(fileno(file)) != 0 && errno != EINVAL) {
         LogPrintf("%s: fsync failed: %d\n", __func__, errno);
         return false;
     }
 #endif
 #endif
     return true;
 }
 
 bool TruncateFile(FILE *file, unsigned int length) {
 #if defined(WIN32)
     return _chsize(_fileno(file), length) == 0;
 #else
     return ftruncate(fileno(file), length) == 0;
 #endif
 }
 
 /**
  * This function tries to raise the file descriptor limit to the requested
  * number. It returns the actual file descriptor limit (which may be more or
  * less than nMinFD)
  */
 int RaiseFileDescriptorLimit(int nMinFD) {
 #if defined(WIN32)
     return 8192;
 #else
     struct rlimit limitFD;
     if (getrlimit(RLIMIT_NOFILE, &limitFD) != -1) {
         if (limitFD.rlim_cur < (rlim_t)nMinFD) {
             limitFD.rlim_cur = nMinFD;
             if (limitFD.rlim_cur > limitFD.rlim_max) {
                 limitFD.rlim_cur = limitFD.rlim_max;
             }
             setrlimit(RLIMIT_NOFILE, &limitFD);
             getrlimit(RLIMIT_NOFILE, &limitFD);
         }
         return limitFD.rlim_cur;
     }
     // getrlimit failed, assume it's fine.
     return nMinFD;
 #endif
 }
 
 /**
  * This function tries to make a particular range of a file allocated
  * (corresponding to disk space) it is advisory, and the range specified in the
  * arguments will never contain live data.
  */
 void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
 #if defined(WIN32)
     // Windows-specific version.
     HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
     LARGE_INTEGER nFileSize;
     int64_t nEndPos = (int64_t)offset + length;
     nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF;
     nFileSize.u.HighPart = nEndPos >> 32;
     SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN);
     SetEndOfFile(hFile);
 #elif defined(MAC_OSX)
     // OSX specific version
     // NOTE: Contrary to other OS versions, the OSX version assumes that
     // NOTE: offset is the size of the file.
     fstore_t fst;
     fst.fst_flags = F_ALLOCATECONTIG;
     fst.fst_posmode = F_PEOFPOSMODE;
     fst.fst_offset = 0;
     // mac os fst_length takes the number of free bytes to allocate,
     // not the desired file size
     fst.fst_length = length;
     fst.fst_bytesalloc = 0;
     if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) {
         fst.fst_flags = F_ALLOCATEALL;
         fcntl(fileno(file), F_PREALLOCATE, &fst);
     }
     ftruncate(fileno(file), static_cast<off_t>(offset) + length);
 #elif defined(HAVE_POSIX_FALLOCATE)
     // Version using posix_fallocate
     off_t nEndPos = (off_t)offset + length;
     posix_fallocate(fileno(file), 0, nEndPos);
 #else
     // Fallback version
     // TODO: just write one byte per block
     static const char buf[65536] = {};
     if (fseek(file, offset, SEEK_SET)) {
         return;
     }
     while (length > 0) {
         unsigned int now = 65536;
         if (length < now) {
             now = length;
         }
         // Allowed to fail; this function is advisory anyway.
         fwrite(buf, 1, now, file);
         length -= now;
     }
 #endif
 }
 
 #ifdef WIN32
 fs::path GetSpecialFolderPath(int nFolder, bool fCreate) {
     WCHAR pszPath[MAX_PATH] = L"";
 
     if (SHGetSpecialFolderPathW(nullptr, pszPath, nFolder, fCreate)) {
         return fs::path(pszPath);
     }
 
     LogPrintf(
         "SHGetSpecialFolderPathW() failed, could not obtain requested path.\n");
     return fs::path("");
 }
 #endif
 
 #ifndef WIN32
 std::string ShellEscape(const std::string &arg) {
     std::string escaped = arg;
     boost::replace_all(escaped, "'", "'\"'\"'");
     return "'" + escaped + "'";
 }
 #endif
 
 #if defined(HAVE_SYSTEM)
 void runCommand(const std::string &strCommand) {
     if (strCommand.empty()) {
         return;
     }
 #ifndef WIN32
     int nErr = ::system(strCommand.c_str());
 #else
     int nErr = ::_wsystem(
         std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t>()
             .from_bytes(strCommand)
             .c_str());
 #endif
     if (nErr) {
         LogPrintf("runCommand error: system(%s) returned %d\n", strCommand,
                   nErr);
     }
 }
 #endif
 
 void SetupEnvironment() {
 #ifdef HAVE_MALLOPT_ARENA_MAX
     // glibc-specific: On 32-bit systems set the number of arenas to 1. By
     // default, since glibc 2.10, the C library will create up to two heap
     // arenas per core. This is known to cause excessive virtual address space
     // usage in our usage. Work around it by setting the maximum number of
     // arenas to 1.
     if (sizeof(void *) == 4) {
         mallopt(M_ARENA_MAX, 1);
     }
 #endif
 // On most POSIX systems (e.g. Linux, but not BSD) the environment's locale may
 // be invalid, in which case the "C.UTF-8" locale is used as fallback.
 #if !defined(WIN32) && !defined(MAC_OSX) && !defined(__FreeBSD__) &&           \
     !defined(__OpenBSD__)
     try {
         // Raises a runtime error if current locale is invalid.
         std::locale("");
     } catch (const std::runtime_error &) {
         setenv("LC_ALL", "C.UTF-8", 1);
     }
 #elif defined(WIN32)
     // Set the default input/output charset is utf-8
     SetConsoleCP(CP_UTF8);
     SetConsoleOutputCP(CP_UTF8);
 #endif
     // The path locale is lazy initialized and to avoid deinitialization errors
     // in multithreading environments, it is set explicitly by the main thread.
     // A dummy locale is used to extract the internal default locale, used by
     // fs::path, which is then used to explicitly imbue the path.
     std::locale loc = fs::path::imbue(std::locale::classic());
 #ifndef WIN32
     fs::path::imbue(loc);
 #else
     fs::path::imbue(std::locale(loc, new std::codecvt_utf8_utf16<wchar_t>()));
 #endif
 }
 
 bool SetupNetworking() {
 #ifdef WIN32
     // Initialize Windows Sockets.
     WSADATA wsadata;
     int ret = WSAStartup(MAKEWORD(2, 2), &wsadata);
     if (ret != NO_ERROR || LOBYTE(wsadata.wVersion) != 2 ||
         HIBYTE(wsadata.wVersion) != 2) {
         return false;
     }
 #endif
     return true;
 }
 
 int GetNumCores() {
     return std::thread::hardware_concurrency();
 }
 
 std::string CopyrightHolders(const std::string &strPrefix) {
     return strPrefix + strprintf(_(COPYRIGHT_HOLDERS).translated,
                                  COPYRIGHT_HOLDERS_SUBSTITUTION);
 }
 
 // Obtain the application startup time (used for uptime calculation)
 int64_t GetStartupTime() {
     return nStartupTime;
 }
 
 fs::path AbsPathForConfigVal(const fs::path &path, bool net_specific) {
     if (path.is_absolute()) {
         return path;
     }
     return fs::absolute(path, GetDataDir(net_specific));
 }
 
 void ScheduleBatchPriority() {
 #ifdef SCHED_BATCH
     const static sched_param param{};
     const int rc = pthread_setschedparam(pthread_self(), SCHED_BATCH, &param);
     if (rc != 0) {
         LogPrintf("Failed to pthread_setschedparam: %s\n", strerror(rc));
     }
 #endif
 }
 
 namespace util {
 #ifdef WIN32
 WinCmdLineArgs::WinCmdLineArgs() {
     wchar_t **wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
     std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> utf8_cvt;
     argv = new char *[argc];
     args.resize(argc);
     for (int i = 0; i < argc; i++) {
         args[i] = utf8_cvt.to_bytes(wargv[i]);
         argv[i] = &*args[i].begin();
     }
     LocalFree(wargv);
 }
 
 WinCmdLineArgs::~WinCmdLineArgs() {
     delete[] argv;
 }
 
 std::pair<int, char **> WinCmdLineArgs::get() {
     return std::make_pair(argc, argv);
 }
 #endif
 } // namespace util
diff --git a/src/util/system.h b/src/util/system.h
index ecfd6a401..bf6a3e814 100644
--- a/src/util/system.h
+++ b/src/util/system.h
@@ -1,517 +1,517 @@
 // Copyright (c) 2009-2010 Satoshi Nakamoto
 // Copyright (c) 2009-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.
 
 /**
  * Server/client environment: argument handling, config file parsing,
  * thread wrappers, startup time
  */
 #ifndef BITCOIN_UTIL_SYSTEM_H
 #define BITCOIN_UTIL_SYSTEM_H
 
 #if defined(HAVE_CONFIG_H)
 #include <config/bitcoin-config.h>
 #endif
 
 #include <attributes.h>
 #include <compat.h>
 #include <compat/assumptions.h>
 #include <fs.h>
 #include <logging.h>
 #include <sync.h>
 #include <tinyformat.h>
 #include <util/settings.h>
 #include <util/threadnames.h>
 #include <util/time.h>
 
 #include <cstdint>
 #include <exception>
 #include <map>
 #include <optional>
 #include <set>
 #include <string>
 #include <utility>
 #include <vector>
 
 // Application startup time (used for uptime calculation)
 int64_t GetStartupTime();
 
 extern const char *const BITCOIN_CONF_FILENAME;
 extern const char *const BITCOIN_SETTINGS_FILENAME;
 
 void SetupEnvironment();
 bool SetupNetworking();
 
-template <typename... Args> bool error(const char *fmt, const Args &... args) {
+template <typename... Args> bool error(const char *fmt, const Args &...args) {
     LogPrintf("ERROR: %s\n", tfm::format(fmt, args...));
     return false;
 }
 
 void PrintExceptionContinue(const std::exception *pex, const char *pszThread);
 bool FileCommit(FILE *file);
 bool TruncateFile(FILE *file, unsigned int length);
 int RaiseFileDescriptorLimit(int nMinFD);
 void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length);
 [[nodiscard]] bool RenameOver(fs::path src, fs::path dest);
 bool LockDirectory(const fs::path &directory, const std::string lockfile_name,
                    bool probe_only = false);
 void UnlockDirectory(const fs::path &directory,
                      const std::string &lockfile_name);
 bool DirIsWritable(const fs::path &directory);
 bool CheckDiskSpace(const fs::path &dir, uint64_t additional_bytes = 0);
 
 /**
  * Get the size of a file by scanning it.
  *
  * @param[in] path The file path
  * @param[in] max Stop seeking beyond this limit
  * @return The file size or max
  */
 std::streampos
 GetFileSize(const char *path,
             std::streamsize max = std::numeric_limits<std::streamsize>::max());
 
 /**
  * Release all directory locks. This is used for unit testing only, at runtime
  * the global destructor will take care of the locks.
  */
 void ReleaseDirectoryLocks();
 
 bool TryCreateDirectories(const fs::path &p);
 fs::path GetDefaultDataDir();
 const fs::path &GetDataDir(bool fNetSpecific = true);
 // Return true if -datadir option points to a valid directory or is not
 // specified.
 bool CheckDataDirOption();
 fs::path GetConfigFile(const std::string &confPath);
 #ifdef WIN32
 fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
 #endif
 #ifndef WIN32
 std::string ShellEscape(const std::string &arg);
 #endif
 #if defined(HAVE_SYSTEM)
 void runCommand(const std::string &strCommand);
 #endif
 
 [[nodiscard]] bool ParseKeyValue(std::string &key, std::string &val);
 
 /**
  * Most paths passed as configuration arguments are treated as relative to
  * the datadir if they are not absolute.
  *
  * @param path The path to be conditionally prefixed with datadir.
  * @param net_specific Forwarded to GetDataDir().
  * @return The normalized path.
  */
 fs::path AbsPathForConfigVal(const fs::path &path, bool net_specific = true);
 
 inline bool IsSwitchChar(char c) {
 #ifdef WIN32
     return c == '-' || c == '/';
 #else
     return c == '-';
 #endif
 }
 
 enum class OptionsCategory {
     OPTIONS,
     CONNECTION,
     WALLET,
     WALLET_DEBUG_TEST,
     ZMQ,
     DEBUG_TEST,
     CHAINPARAMS,
     NODE_RELAY,
     BLOCK_CREATION,
     RPC,
     GUI,
     COMMANDS,
     REGISTER_COMMANDS,
 
     // Always the last option to avoid printing these in the help
     HIDDEN,
 
     // Avalanche is still experimental, so we keep it hidden for now.
     AVALANCHE,
 };
 
 struct SectionInfo {
     std::string m_name;
     std::string m_file;
     int m_line;
 };
 
 class ArgsManager {
 public:
     enum Flags {
         // Boolean options can accept negation syntax -noOPTION or -noOPTION=1
         ALLOW_BOOL = 0x01,
         ALLOW_INT = 0x02,
         ALLOW_STRING = 0x04,
         ALLOW_ANY = ALLOW_BOOL | ALLOW_INT | ALLOW_STRING,
         DEBUG_ONLY = 0x100,
         /* Some options would cause cross-contamination if values for
          * mainnet were used while running on regtest/testnet (or vice-versa).
          * Setting them as NETWORK_ONLY ensures that sharing a config file
          * between mainnet and regtest/testnet won't cause problems due to these
          * parameters by accident. */
         NETWORK_ONLY = 0x200,
         // This argument's value is sensitive (such as a password).
         SENSITIVE = 0x400,
     };
 
 protected:
     struct Arg {
         std::string m_help_param;
         std::string m_help_text;
         unsigned int m_flags;
     };
 
     mutable RecursiveMutex cs_args;
     util::Settings m_settings GUARDED_BY(cs_args);
     std::string m_network GUARDED_BY(cs_args);
     std::set<std::string> m_network_only_args GUARDED_BY(cs_args);
     std::map<OptionsCategory, std::map<std::string, Arg>>
         m_available_args GUARDED_BY(cs_args);
     std::list<SectionInfo> m_config_sections GUARDED_BY(cs_args);
     fs::path m_cached_blocks_path GUARDED_BY(cs_args);
     mutable fs::path m_cached_datadir_path GUARDED_BY(cs_args);
     mutable fs::path m_cached_network_datadir_path GUARDED_BY(cs_args);
 
     [[nodiscard]] bool ReadConfigStream(std::istream &stream,
                                         const std::string &filepath,
                                         std::string &error,
                                         bool ignore_invalid_keys = false);
 
     /**
      * Returns true if settings values from the default section should be used,
      * depending on the current network and whether the setting is
      * network-specific.
      */
     bool UseDefaultSection(const std::string &arg) const
         EXCLUSIVE_LOCKS_REQUIRED(cs_args);
 
     /**
      * Get setting value.
      *
      * Result will be null if setting was unset, true if "-setting" argument was
      * passed false if "-nosetting" argument was passed, and a string if a
      * "-setting=value" argument was passed.
      */
     util::SettingsValue GetSetting(const std::string &arg) const;
 
     /**
      * Get list of setting values.
      */
     std::vector<util::SettingsValue>
     GetSettingsList(const std::string &arg) const;
 
 public:
     ArgsManager();
     ~ArgsManager();
 
     /**
      * Select the network in use
      */
     void SelectConfigNetwork(const std::string &network);
 
     [[nodiscard]] bool ParseParameters(int argc, const char *const argv[],
                                        std::string &error);
     [[nodiscard]] bool ReadConfigFiles(std::string &error,
                                        bool ignore_invalid_keys = false);
 
     /**
      * Log warnings for options in m_section_only_args when they are specified
      * in the default section but not overridden on the command line or in a
      * network-specific section in the config file.
      */
     const std::set<std::string> GetUnsuitableSectionOnlyArgs() const;
 
     /**
      * Log warnings for unrecognized section names in the config file.
      */
     const std::list<SectionInfo> GetUnrecognizedSections() const;
 
     /**
      * Get blocks directory path
      *
      * @return Blocks path which is network specific
      */
     const fs::path &GetBlocksDirPath();
 
     /**
      * Get data directory path
      *
      * @param net_specific Append network identifier to the returned path
      * @return Absolute path on success, otherwise an empty path when a
      *         non-directory path would be returned
      * @post Returned directory path is created unless it is empty
      */
     const fs::path &GetDataDirPath(bool net_specific = true) const;
 
     /**
      * Clear cached directory paths
      */
     void ClearPathCache();
 
     /**
      * Return a vector of strings of the given argument
      *
      * @param strArg Argument to get (e.g. "-foo")
      * @return command-line arguments
      */
     std::vector<std::string> GetArgs(const std::string &strArg) const;
 
     /**
      * Return true if the given argument has been manually set.
      *
      * @param strArg Argument to get (e.g. "-foo")
      * @return true if the argument has been set
      */
     bool IsArgSet(const std::string &strArg) const;
 
     /**
      * Return true if the argument was originally passed as a negated option,
      * i.e. -nofoo.
      *
      * @param strArg Argument to get (e.g. "-foo")
      * @return true if the argument was passed negated
      */
     bool IsArgNegated(const std::string &strArg) const;
 
     /**
      * Return string argument or default value.
      *
      * @param strArg Argument to get (e.g. "-foo")
      * @param strDefault (e.g. "1")
      * @return command-line argument or default value
      */
     std::string GetArg(const std::string &strArg,
                        const std::string &strDefault) const;
 
     /**
      * Return integer argument or default value.
      *
      * @param strArg Argument to get (e.g. "-foo")
      * @param nDefault (e.g. 1)
      * @return command-line argument (0 if invalid number) or default value
      */
     int64_t GetArg(const std::string &strArg, int64_t nDefault) const;
 
     /**
      * Return boolean argument or default value.
      *
      * @param strArg Argument to get (e.g. "-foo")
      * @param fDefault (true or false)
      * @return command-line argument or default value
      */
     bool GetBoolArg(const std::string &strArg, bool fDefault) const;
 
     /**
      * Set an argument if it doesn't already have a value.
      *
      * @param strArg Argument to set (e.g. "-foo")
      * @param strValue Value (e.g. "1")
      * @return true if argument gets set, false if it already had a value
      */
     bool SoftSetArg(const std::string &strArg, const std::string &strValue);
 
     /**
      * Set a boolean argument if it doesn't already have a value.
      *
      * @param strArg Argument to set (e.g. "-foo")
      * @param fValue Value (e.g. false)
      * @return true if argument gets set, false if it already had a value
      */
     bool SoftSetBoolArg(const std::string &strArg, bool fValue);
 
     // Forces an arg setting. Called by SoftSetArg() if the arg hasn't already
     // been set. Also called directly in testing.
     void ForceSetArg(const std::string &strArg, const std::string &strValue);
 
     // Forces a multi arg setting, used only in testing
     void ForceSetMultiArg(const std::string &strArg,
                           const std::vector<std::string> &values);
 
     /**
      * Looks for -regtest, -testnet and returns the appropriate BIP70 chain
      * name.
      * @return CBaseChainParams::MAIN by default; raises runtime error if an
      * invalid combination is given.
      */
     std::string GetChainName() const;
 
     /**
      * Add argument
      */
     void AddArg(const std::string &name, const std::string &help,
                 unsigned int flags, const OptionsCategory &cat);
 
     /**
      * Remove a forced arg setting, used only in testing.
      */
     void ClearForcedArg(const std::string &strArg);
 
     /**
      * Add many hidden arguments
      */
     void AddHiddenArgs(const std::vector<std::string> &args);
 
     /**
      * Clear available arguments
      */
     void ClearArgs() {
         LOCK(cs_args);
         m_available_args.clear();
         m_network_only_args.clear();
     }
 
     /**
      * Get the help string
      */
     std::string GetHelpMessage() const;
 
     /**
      * Return Flags for known arg.
      * Return std::nullopt for unknown arg.
      */
     std::optional<unsigned int> GetArgFlags(const std::string &name) const;
 
     /**
      * Read and update settings file with saved settings. This needs to be
      * called after SelectParams() because the settings file location is
      * network-specific.
      */
     bool InitSettings(std::string &error);
 
     /**
      * Get settings file path, or return false if read-write settings were
      * disabled with -nosettings.
      */
     bool GetSettingsPath(fs::path *filepath = nullptr, bool temp = false) const;
 
     /**
      * Read settings file. Push errors to vector, or log them if null.
      */
     bool ReadSettingsFile(std::vector<std::string> *errors = nullptr);
 
     /**
      * Write settings file. Push errors to vector, or log them if null.
      */
     bool WriteSettingsFile(std::vector<std::string> *errors = nullptr) const;
 
     /**
      * Access settings with lock held.
      */
     template <typename Fn> void LockSettings(Fn &&fn) {
         LOCK(cs_args);
         fn(m_settings);
     }
 
     /**
      * Log the config file options and the command line arguments,
      * useful for troubleshooting.
      */
     void LogArgs() const;
 
 private:
     // Helper function for LogArgs().
     void
     logArgsPrefix(const std::string &prefix, const std::string &section,
                   const std::map<std::string, std::vector<util::SettingsValue>>
                       &args) const;
 };
 
 extern ArgsManager gArgs;
 
 /**
  * @return true if help has been requested via a command-line arg
  */
 bool HelpRequested(const ArgsManager &args);
 
 /** Add help options to the args manager */
 void SetupHelpOptions(ArgsManager &args);
 
 /**
  * Format a string to be used as group of options in help messages.
  *
  * @param message Group name (e.g. "RPC server options:")
  * @return the formatted string
  */
 std::string HelpMessageGroup(const std::string &message);
 
 /**
  * Format a string to be used as option description in help messages.
  *
  * @param option Option message (e.g. "-rpcuser=<user>")
  * @param message Option description (e.g. "Username for JSON-RPC connections")
  * @return the formatted string
  */
 std::string HelpMessageOpt(const std::string &option,
                            const std::string &message);
 
 /**
  * Return the number of cores available on the current system.
  * @note This does count virtual cores, such as those provided by
  * HyperThreading.
  */
 int GetNumCores();
 
 /**
  * .. and a wrapper that just calls func once
  */
 template <typename Callable> void TraceThread(const char *name, Callable func) {
     util::ThreadRename(name);
     try {
         LogPrintf("%s thread start\n", name);
         func();
         LogPrintf("%s thread exit\n", name);
     } catch (const std::exception &e) {
         PrintExceptionContinue(&e, name);
         throw;
     } catch (...) {
         PrintExceptionContinue(nullptr, name);
         throw;
     }
 }
 
 std::string CopyrightHolders(const std::string &strPrefix);
 
 /**
  * On platforms that support it, tell the kernel the calling thread is
  * CPU-intensive and non-interactive. See SCHED_BATCH in sched(7) for details.
  *
  */
 void ScheduleBatchPriority();
 
 namespace util {
 
 //! Simplification of std insertion
 template <typename Tdst, typename Tsrc>
 inline void insert(Tdst &dst, const Tsrc &src) {
     dst.insert(dst.begin(), src.begin(), src.end());
 }
 template <typename TsetT, typename Tsrc>
 inline void insert(std::set<TsetT> &dst, const Tsrc &src) {
     dst.insert(src.begin(), src.end());
 }
 
 #ifdef WIN32
 class WinCmdLineArgs {
 public:
     WinCmdLineArgs();
     ~WinCmdLineArgs();
     std::pair<int, char **> get();
 
 private:
     int argc;
     char **argv;
     std::vector<std::string> args;
 };
 #endif
 
 } // namespace util
 
 #endif // BITCOIN_UTIL_SYSTEM_H
diff --git a/src/util/translation.h b/src/util/translation.h
index 14b6dd1e1..44d35e365 100644
--- a/src/util/translation.h
+++ b/src/util/translation.h
@@ -1,60 +1,60 @@
 // Copyright (c) 2019 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #ifndef BITCOIN_UTIL_TRANSLATION_H
 #define BITCOIN_UTIL_TRANSLATION_H
 
 #include <tinyformat.h>
 
 #include <functional>
 
 /**
  * Bilingual messages:
  *   - in GUI: user's native language + untranslated (i.e. English)
  *   - in log and stderr: untranslated only
  */
 struct bilingual_str {
     std::string original;
     std::string translated;
 
     bilingual_str &operator+=(const bilingual_str &rhs) {
         original += rhs.original;
         translated += rhs.translated;
         return *this;
     }
 
     bool empty() const { return original.empty(); }
 };
 
 inline bilingual_str operator+(bilingual_str lhs, const bilingual_str &rhs) {
     lhs += rhs;
     return lhs;
 }
 
 /** Mark a bilingual_str as untranslated */
 inline bilingual_str Untranslated(std::string original) {
     return {original, original};
 }
 
 namespace tinyformat {
 template <typename... Args>
-bilingual_str format(const bilingual_str &fmt, const Args &... args) {
+bilingual_str format(const bilingual_str &fmt, const Args &...args) {
     return bilingual_str{format(fmt.original, args...),
                          format(fmt.translated, args...)};
 }
 } // namespace tinyformat
 
 /** Translate a message to the native language of the user. */
 const extern std::function<std::string(const char *)> G_TRANSLATION_FUN;
 
 /**
  * Translation function.
  * If no translation function is set, simply return the input.
  */
 inline bilingual_str _(const char *psz) {
     return bilingual_str{psz,
                          G_TRANSLATION_FUN ? (G_TRANSLATION_FUN)(psz) : psz};
 }
 
 #endif // BITCOIN_UTIL_TRANSLATION_H
diff --git a/src/util/vector.h b/src/util/vector.h
index 6670d79c5..982a56f2e 100644
--- a/src/util/vector.h
+++ b/src/util/vector.h
@@ -1,49 +1,49 @@
 // Copyright (c) 2019 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #ifndef BITCOIN_UTIL_VECTOR_H
 #define BITCOIN_UTIL_VECTOR_H
 
 #include <initializer_list>
 #include <type_traits>
 #include <vector>
 
 /** Construct a vector with the specified elements.
  *
  * This is preferable over the list initializing constructor of std::vector:
  * - It automatically infers the element type from its arguments.
  * - If any arguments are rvalue references, they will be moved into the vector
  *   (list initialization always copies).
  */
 template <typename... Args>
 inline std::vector<typename std::common_type<Args...>::type>
-Vector(Args &&... args) {
+Vector(Args &&...args) {
     std::vector<typename std::common_type<Args...>::type> ret;
     ret.reserve(sizeof...(args));
     // The line below uses the trick from
     // https://www.experts-exchange.com/articles/32502/None-recursive-variadic-templates-with-std-initializer-list.html
     (void)std::initializer_list<int>{
         (ret.emplace_back(std::forward<Args>(args)), 0)...};
     return ret;
 }
 
 /** Concatenate two vectors, moving elements. */
 template <typename V> inline V Cat(V v1, V &&v2) {
     v1.reserve(v1.size() + v2.size());
     for (auto &arg : v2) {
         v1.push_back(std::move(arg));
     }
     return v1;
 }
 
 /** Concatenate two vectors. */
 template <typename V> inline V Cat(V v1, const V &v2) {
     v1.reserve(v1.size() + v2.size());
     for (const auto &arg : v2) {
         v1.push_back(arg);
     }
     return v1;
 }
 
 #endif // BITCOIN_UTIL_VECTOR_H
diff --git a/test/lint/lint-format-strings.py b/test/lint/lint-format-strings.py
index cb5d6bda9..a0919d7fd 100755
--- a/test/lint/lint-format-strings.py
+++ b/test/lint/lint-format-strings.py
@@ -1,341 +1,341 @@
 #!/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 doctest
 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/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/tinyformat.h", "printf(const char *fmt, const Args &... args)"),
+    ("src/tinyformat.h", "printf(const char *fmt, const Args &...args)"),
     ("src/tinyformat.h", "printf(const char *fmt, TINYFORMAT_VARARGS(n))"),
     ("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/wallet/scriptpubkeyman.h",
      "WalletLogPrintf(const std::string& fmt, const Params&... parameters)"),
 ]
 
 FUNCTION_NAMES_AND_NUMBER_OF_LEADING_ARGUMENTS = [
     ("FatalError", 0),
     ("fprintf", 1),
     ("LogConnectFailure", 1),
     ("LogPrint", 1),
     ("LogPrintf", 0),
     ("printf", 0),
     ("snprintf", 2),
     ("sprintf", 1),
     ("strprintf", 0),
     ("tfm::format", 1),  # Assuming tfm::::format(std::ostream&, ...
     ("vfprintf", 1),
     ("vprintf", 1),
     ("vsnprintf", 1),
     ("vsprintf", 1),
 ]
 
 
 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 isinstance(function_name, str) and isinstance(
         source_code, 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 isinstance(s, 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 isinstance(s, 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 isinstance(s, 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<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().to_bytes(buf), err);')
     ['strprintf(', '"%s (%d)",', ' std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().to_bytes(buf),', ' err', ')']
     >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo<wchar_t>().to_bytes(buf), err);')
     ['strprintf(', '"%s (%d)",', ' foo<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 << 1, err);')
     ['strprintf(', '"%s (%d)",', ' foo << 1,', ' err', ')']
     >>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo<bar>() >> 1, err);')
     ['strprintf(', '"%s (%d)",', ' foo<bar>() >> 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 isinstance(function_name, str) and isinstance(
         function_call, 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 isinstance(argument, 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 isinstance(format_string, str)
     n = 0
     in_specifier = False
     for i, char in enumerate(format_string):
         if format_string[i - 1:i +
                          1] == "%%" or format_string[i:i + 2] == "%%":
             pass
         elif char == "%":
             in_specifier = True
             n += 1
         elif char in "aAcdeEfFgGinopsuxX":
             in_specifier = False
         elif in_specifier and char == "*":
             n += 1
     return n
 
 
 def main(args_in):
     """ Return a string output with information on string format errors
 
     >>> main(["test/lint/lint-format-strings-tests.txt"])
     test/lint/lint-format-strings-tests.txt: Expected 1 argument(s) after format string but found 2 argument(s): printf("%d", 1, 2)
     test/lint/lint-format-strings-tests.txt: Expected 2 argument(s) after format string but found 3 argument(s): printf("%a %b", 1, 2, "anything")
     test/lint/lint-format-strings-tests.txt: Expected 1 argument(s) after format string but found 0 argument(s): printf("%d")
     test/lint/lint-format-strings-tests.txt: Expected 3 argument(s) after format string but found 2 argument(s): printf("%a%b%z", 1, "anything")
 
     >>> main(["test/lint/lint-format-strings-tests-skip-arguments.txt"])
     test/lint/lint-format-strings-tests-skip-arguments.txt: Expected 1 argument(s) after format string but found 2 argument(s): fprintf(skipped, "%d", 1, 2)
     test/lint/lint-format-strings-tests-skip-arguments.txt: Expected 1 argument(s) after format string but found 0 argument(s): fprintf(skipped, "%d")
     test/lint/lint-format-strings-tests-skip-arguments.txt: Expected 1 argument(s) after format string but found 2 argument(s): snprintf(skip1, skip2, "%d", 1, 2)
     test/lint/lint-format-strings-tests-skip-arguments.txt: Expected 1 argument(s) after format string but found 0 argument(s): snprintf(skip1, skip2, "%d")
     test/lint/lint-format-strings-tests-skip-arguments.txt: Could not parse function call string "snprintf(...)": snprintf(skip1, "%d")
     """
     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("file", type=argparse.FileType(
         "r", encoding="utf-8"), nargs="*", help="C++ source code file (e.g. foo.cpp)")
     args = parser.parse_args(args_in)
 
     for f in args.file:
         file_content = f.read()
         for (function_name,
              skip_arguments) in FUNCTION_NAMES_AND_NUMBER_OF_LEADING_ARGUMENTS:
             for function_call_str in parse_function_calls(
                     function_name, file_content):
                 parts = parse_function_call_and_arguments(
                     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 + skip_arguments:
                     print("{}: Could not parse function call string \"{}(...)\": {}".format(
                         f.name, function_name, relevant_function_call_str))
                     continue
                 argument_count = len(parts) - 3 - skip_arguments
                 format_str = parse_string_content(parts[1 + skip_arguments])
                 format_specifier_count = count_format_specifiers(format_str)
                 if format_specifier_count != argument_count:
                     print("{}: Expected {} argument(s) after format string but found {} argument(s): {}".format(
                         f.name, format_specifier_count, argument_count, relevant_function_call_str))
                     continue
 
 
 if __name__ == "__main__":
     doctest.testmod()
     main(sys.argv[1:])