aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac6
-rwxr-xr-xcontrib/devtools/copyright_header.py8
-rwxr-xr-xcontrib/devtools/github-merge.py3
-rwxr-xr-xcontrib/devtools/lint-python-shebang.sh11
-rwxr-xr-xcontrib/devtools/lint-python.sh12
-rwxr-xr-xcontrib/devtools/optimize-pngs.py8
-rwxr-xr-xcontrib/devtools/test-security-check.py5
-rwxr-xr-xcontrib/linearize/linearize-data.py1
-rwxr-xr-xcontrib/linearize/linearize-hashes.py1
-rwxr-xr-xcontrib/seeds/generate-seeds.py7
-rwxr-xr-xcontrib/seeds/makeseeds.py10
-rw-r--r--contrib/testgen/base58.py9
-rwxr-xr-xcontrib/testgen/gen_base58_test_vectors.py9
-rw-r--r--depends/Makefile15
-rw-r--r--doc/developer-notes.md9
-rw-r--r--doc/release-notes-pr12823.md20
-rw-r--r--doc/release-notes.md5
-rwxr-xr-xshare/rpcauth/rpcauth.py2
-rw-r--r--share/setup.nsi.in3
-rw-r--r--src/.clang-format5
-rw-r--r--src/Makefile.am2
-rw-r--r--src/Makefile.bench.include2
-rw-r--r--src/addrdb.cpp3
-rw-r--r--src/bench/bench.cpp4
-rw-r--r--src/bench/mempool_eviction.cpp2
-rw-r--r--src/bench/perf.cpp53
-rw-r--r--src/bench/perf.h37
-rw-r--r--src/bench/verify_script.cpp2
-rw-r--r--src/bitcoind.cpp5
-rw-r--r--src/chainparams.cpp6
-rw-r--r--src/chainparamsbase.cpp1
-rw-r--r--src/compat.h6
-rw-r--r--src/compat/endian.h45
-rw-r--r--src/consensus/params.h4
-rw-r--r--src/core_write.cpp1
-rw-r--r--src/init.cpp72
-rw-r--r--src/init.h2
-rw-r--r--src/interfaces/node.cpp5
-rw-r--r--src/interfaces/node.h9
-rw-r--r--src/interfaces/wallet.h2
-rw-r--r--src/logging.cpp283
-rw-r--r--src/logging.h125
-rw-r--r--src/net.cpp27
-rw-r--r--src/net_processing.cpp12
-rw-r--r--src/netaddress.cpp50
-rw-r--r--src/netaddress.h10
-rw-r--r--src/netbase.cpp6
-rw-r--r--src/qt/test/wallettests.cpp6
-rw-r--r--src/rpc/misc.cpp2
-rw-r--r--src/rpc/rawtransaction.cpp2
-rw-r--r--src/test/blockencodings_tests.cpp23
-rw-r--r--src/test/multisig_tests.cpp2
-rw-r--r--src/test/script_tests.cpp4
-rw-r--r--src/test/serialize_tests.cpp7
-rw-r--r--src/test/test_bitcoin.cpp12
-rw-r--r--src/test/test_bitcoin.h6
-rw-r--r--src/test/txvalidationcache_tests.cpp4
-rw-r--r--src/test/util_tests.cpp252
-rw-r--r--src/util.cpp572
-rw-r--r--src/util.h141
-rw-r--r--src/validation.cpp114
-rw-r--r--src/validation.h3
-rw-r--r--src/validationinterface.cpp4
-rw-r--r--src/wallet/init.cpp51
-rw-r--r--src/wallet/rpcwallet.cpp18
-rw-r--r--src/wallet/test/wallet_tests.cpp25
-rw-r--r--src/wallet/wallet.cpp40
-rw-r--r--src/wallet/wallet.h27
-rw-r--r--src/wallet/walletdb.cpp2
-rw-r--r--src/walletinitinterface.h18
-rwxr-xr-xtest/functional/feature_bip68_sequence.py4
-rwxr-xr-xtest/functional/feature_block.py8
-rwxr-xr-xtest/functional/feature_config_args.py7
-rwxr-xr-xtest/functional/feature_logging.py21
-rwxr-xr-xtest/functional/feature_maxuploadtarget.py2
-rwxr-xr-xtest/functional/feature_proxy.py2
-rwxr-xr-xtest/functional/feature_segwit.py10
-rwxr-xr-xtest/functional/interface_rest.py4
-rwxr-xr-xtest/functional/p2p_mempool.py2
-rwxr-xr-xtest/functional/p2p_segwit.py100
-rwxr-xr-xtest/functional/rpc_bind.py104
-rw-r--r--test/functional/test_framework/blocktools.py112
-rw-r--r--test/functional/test_framework/script.py6
-rw-r--r--test/functional/test_framework/socks5.py12
-rwxr-xr-xtest/functional/test_framework/test_node.py12
-rw-r--r--test/functional/test_framework/util.py1
-rwxr-xr-xtest/functional/test_runner.py4
-rwxr-xr-xtest/functional/wallet_importprunedfunds.py2
-rwxr-xr-xtest/functional/wallet_keypool.py2
-rwxr-xr-xtest/functional/wallet_txn_clone.py5
-rwxr-xr-xtest/functional/wallet_txn_doublespend.py9
-rw-r--r--test/util/data/blanktxv1.json1
-rw-r--r--test/util/data/blanktxv2.json1
-rw-r--r--test/util/data/tt-delin1-out.json1
-rw-r--r--test/util/data/tt-delout1-out.json1
-rw-r--r--test/util/data/tt-locktime317000-out.json1
-rw-r--r--test/util/data/txcreate1.json1
-rw-r--r--test/util/data/txcreate2.json1
-rw-r--r--test/util/data/txcreatedata1.json1
-rw-r--r--test/util/data/txcreatedata2.json1
-rw-r--r--test/util/data/txcreatedata_seq0.json1
-rw-r--r--test/util/data/txcreatedata_seq1.json1
-rw-r--r--test/util/data/txcreatemultisig1.json1
-rw-r--r--test/util/data/txcreatemultisig2.json1
-rw-r--r--test/util/data/txcreatemultisig3.json1
-rw-r--r--test/util/data/txcreatemultisig4.json1
-rw-r--r--test/util/data/txcreatemultisig5.json1
-rw-r--r--test/util/data/txcreateoutpubkey1.json1
-rw-r--r--test/util/data/txcreateoutpubkey2.json1
-rw-r--r--test/util/data/txcreateoutpubkey3.json1
-rw-r--r--test/util/data/txcreatescript1.json1
-rw-r--r--test/util/data/txcreatescript2.json1
-rw-r--r--test/util/data/txcreatescript3.json1
-rw-r--r--test/util/data/txcreatescript4.json1
-rw-r--r--test/util/data/txcreatesignv1.json1
115 files changed, 1680 insertions, 1033 deletions
diff --git a/configure.ac b/configure.ac
index b38e480f27..c4bc061d74 100644
--- a/configure.ac
+++ b/configure.ac
@@ -630,11 +630,7 @@ if test x$use_hardening != xno; then
AX_CHECK_LINK_FLAG([[-Wl,--high-entropy-va]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,--high-entropy-va"])
AX_CHECK_LINK_FLAG([[-Wl,-z,relro]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,relro"])
AX_CHECK_LINK_FLAG([[-Wl,-z,now]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,now"])
-
- if test x$TARGET_OS != xwindows; then
- AX_CHECK_COMPILE_FLAG([-fPIE],[PIE_FLAGS="-fPIE"])
- AX_CHECK_LINK_FLAG([[-pie]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -pie"])
- fi
+ AX_CHECK_LINK_FLAG([[-fPIE -pie]], [PIE_FLAGS="-fPIE"; HARDENED_LDFLAGS="$HARDENED_LDFLAGS -pie"],, [[$CXXFLAG_WERROR]])
case $host in
*mingw*)
diff --git a/contrib/devtools/copyright_header.py b/contrib/devtools/copyright_header.py
index c817e794b9..e7cccaab03 100755
--- a/contrib/devtools/copyright_header.py
+++ b/contrib/devtools/copyright_header.py
@@ -286,7 +286,7 @@ Arguments:
def report_cmd(argv):
if len(argv) == 2:
sys.exit(REPORT_USAGE)
-
+
base_directory = argv[2]
if not os.path.exists(base_directory):
sys.exit("*** bad <base_directory>: %s" % base_directory)
@@ -444,7 +444,7 @@ def print_file_action_message(filename, action):
def update_cmd(argv):
if len(argv) != 3:
sys.exit(UPDATE_USAGE)
-
+
base_directory = argv[2]
if not os.path.exists(base_directory):
sys.exit("*** bad base_directory: %s" % base_directory)
@@ -570,13 +570,13 @@ def insert_cmd(argv):
_, extension = os.path.splitext(filename)
if extension not in ['.h', '.cpp', '.cc', '.c', '.py']:
sys.exit("*** cannot insert for file extension %s" % extension)
-
+
if extension == '.py':
style = 'python'
else:
style = 'cpp'
exec_insert_header(filename, style)
-
+
################################################################################
# UI
################################################################################
diff --git a/contrib/devtools/github-merge.py b/contrib/devtools/github-merge.py
index 9c666673cf..187ef75fb7 100755
--- a/contrib/devtools/github-merge.py
+++ b/contrib/devtools/github-merge.py
@@ -21,7 +21,8 @@ import argparse
import hashlib
import subprocess
import sys
-import json,codecs
+import json
+import codecs
try:
from urllib.request import Request,urlopen
except:
diff --git a/contrib/devtools/lint-python-shebang.sh b/contrib/devtools/lint-python-shebang.sh
new file mode 100755
index 0000000000..f5c5971c03
--- /dev/null
+++ b/contrib/devtools/lint-python-shebang.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+# Shebang must use python3 (not python or python2)
+EXIT_CODE=0
+for PYTHON_FILE in $(git ls-files -- "*.py"); do
+ if [[ $(head -c 2 "${PYTHON_FILE}") == "#!" &&
+ $(head -n 1 "${PYTHON_FILE}") != "#!/usr/bin/env python3" ]]; then
+ echo "Missing shebang \"#!/usr/bin/env python3\" in ${PYTHON_FILE} (do not use python or python2)"
+ EXIT_CODE=1
+ fi
+done
+exit ${EXIT_CODE}
diff --git a/contrib/devtools/lint-python.sh b/contrib/devtools/lint-python.sh
index 1469ce1640..239337000d 100755
--- a/contrib/devtools/lint-python.sh
+++ b/contrib/devtools/lint-python.sh
@@ -15,6 +15,8 @@
# E133 closing bracket is missing indentation
# E223 tab before operator
# E224 tab after operator
+# E242 tab after ','
+# E266 too many leading '#' for block comment
# E271 multiple spaces after keyword
# E272 multiple spaces before keyword
# E273 tab after keyword
@@ -22,7 +24,10 @@
# E275 missing whitespace after keyword
# E304 blank lines found after function decorator
# E306 expected 1 blank line before a nested definition
+# E401 multiple imports on one line
+# E402 module level import not at top of file
# E502 the backslash is redundant between brackets
+# E701 multiple statements on one line (colon)
# E702 multiple statements on one line (semicolon)
# E703 statement ends with a semicolon
# E714 test for object identity should be "is not"
@@ -30,6 +35,8 @@
# E741 do not use variables named "l", "O", or "I"
# E742 do not define classes named "l", "O", or "I"
# E743 do not define functions named "l", "O", or "I"
+# E901 SyntaxError: invalid syntax
+# E902 TokenError: EOF in multi-line string
# F401 module imported but unused
# F402 import module from line N shadowed by loop variable
# F404 future import(s) name after other statements
@@ -49,16 +56,19 @@
# F707 an except: block as not the last exception handler
# F811 redefinition of unused name from line N
# F812 list comprehension redefines 'foo' from line N
+# F821 undefined name 'Foo'
# F822 undefined name name in __all__
# F823 local variable name … referenced before assignment
# F831 duplicate argument name in function definition
# F841 local variable 'foo' is assigned to but never used
# W292 no newline at end of file
+# W293 blank line contains whitespace
# W504 line break after binary operator
# W601 .has_key() is deprecated, use "in"
# W602 deprecated form of raising exception
# W603 "<>" is deprecated, use "!="
# W604 backticks are deprecated, use "repr()"
# W605 invalid escape sequence "x"
+# W606 'async' and 'await' are reserved keywords starting with Python 3.7
-flake8 --ignore=B,C,E,F,I,N,W --select=E112,E113,E115,E116,E125,E131,E133,E223,E224,E271,E272,E273,E274,E275,E304,E306,E502,E702,E703,E714,E721,E741,E742,E743,F401,F402,F404,F406,F407,F601,F602,F621,F622,F631,F701,F702,F703,F704,F705,F706,F707,F811,F812,F822,F823,F831,F841,W292,W504,W601,W602,W603,W604,W605 .
+flake8 --ignore=B,C,E,F,I,N,W --select=E112,E113,E115,E116,E125,E131,E133,E223,E224,E242,E266,E271,E272,E273,E274,E275,E304,E306,E401,E402,E502,E701,E702,E703,E714,E721,E741,E742,E743,F401,E901,E902,F402,F404,F406,F407,F601,F602,F621,F622,F631,F701,F702,F703,F704,F705,F706,F707,F811,F812,F821,F822,F823,F831,F841,W292,W293,W504,W601,W602,W603,W604,W605,W606 .
diff --git a/contrib/devtools/optimize-pngs.py b/contrib/devtools/optimize-pngs.py
index 565b199125..a75731ef76 100755
--- a/contrib/devtools/optimize-pngs.py
+++ b/contrib/devtools/optimize-pngs.py
@@ -41,19 +41,19 @@ for folder in folders:
file_path = os.path.join(absFolder, file)
fileMetaMap = {'file' : file, 'osize': os.path.getsize(file_path), 'sha256Old' : file_hash(file_path)}
fileMetaMap['contentHashPre'] = content_hash(file_path)
-
+
try:
subprocess.call([pngcrush, "-brute", "-ow", "-rem", "gAMA", "-rem", "cHRM", "-rem", "iCCP", "-rem", "sRGB", "-rem", "alla", "-rem", "text", file_path],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
except:
print("pngcrush is not installed, aborting...")
sys.exit(0)
-
+
#verify
if "Not a PNG file" in subprocess.check_output([pngcrush, "-n", "-v", file_path], stderr=subprocess.STDOUT, universal_newlines=True):
print("PNG file "+file+" is corrupted after crushing, check out pngcursh version")
sys.exit(1)
-
+
fileMetaMap['sha256New'] = file_hash(file_path)
fileMetaMap['contentHashPost'] = content_hash(file_path)
@@ -72,5 +72,5 @@ for fileDict in outputArray:
totalSaveBytes += fileDict['osize'] - fileDict['psize']
noHashChange = noHashChange and (oldHash == newHash)
print(fileDict['file']+"\n size diff from: "+str(fileDict['osize'])+" to: "+str(fileDict['psize'])+"\n old sha256: "+oldHash+"\n new sha256: "+newHash+"\n")
-
+
print("completed. Checksum stable: "+str(noHashChange)+". Total reduction: "+str(totalSaveBytes)+" bytes")
diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py
index 22f5ee20f7..ee87c8bab4 100755
--- a/contrib/devtools/test-security-check.py
+++ b/contrib/devtools/test-security-check.py
@@ -1,11 +1,10 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python3
# Copyright (c) 2015-2017 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
Test script for security-check.py
'''
-from __future__ import division,print_function
import subprocess
import unittest
@@ -22,7 +21,7 @@ def write_testcode(filename):
def call_security_check(cc, source, executable, options):
subprocess.check_call([cc,source,'-o',executable] + options)
- p = subprocess.Popen(['./security-check.py',executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
+ p = subprocess.Popen(['./security-check.py',executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
(stdout, stderr) = p.communicate()
return (p.returncode, stdout.rstrip())
diff --git a/contrib/linearize/linearize-data.py b/contrib/linearize/linearize-data.py
index 4969e96827..c609e9b336 100755
--- a/contrib/linearize/linearize-data.py
+++ b/contrib/linearize/linearize-data.py
@@ -21,7 +21,6 @@ from binascii import hexlify, unhexlify
settings = {}
-##### Switch endian-ness #####
def hex_switchEndian(s):
""" Switches the endianness of a hex string (in pairs of hex chars) """
pairList = [s[i:i+2].encode() for i in range(0, len(s), 2)]
diff --git a/contrib/linearize/linearize-hashes.py b/contrib/linearize/linearize-hashes.py
index 6b69c5b3a3..e1304e26d0 100755
--- a/contrib/linearize/linearize-hashes.py
+++ b/contrib/linearize/linearize-hashes.py
@@ -21,7 +21,6 @@ import os.path
settings = {}
-##### Switch endian-ness #####
def hex_switchEndian(s):
""" Switches the endianness of a hex string (in pairs of hex chars) """
pairList = [s[i:i+2].encode() for i in range(0, len(s), 2)]
diff --git a/contrib/seeds/generate-seeds.py b/contrib/seeds/generate-seeds.py
index 2790ef4acd..72eb7255f3 100755
--- a/contrib/seeds/generate-seeds.py
+++ b/contrib/seeds/generate-seeds.py
@@ -34,7 +34,8 @@ These should be pasted into `src/chainparamsseeds.h`.
from base64 import b32decode
from binascii import a2b_hex
-import sys, os
+import sys
+import os
import re
# ipv4 in ipv6 prefix
@@ -46,7 +47,7 @@ def name_to_ipv6(addr):
if len(addr)>6 and addr.endswith('.onion'):
vchAddr = b32decode(addr[0:-6], True)
if len(vchAddr) != 16-len(pchOnionCat):
- raise ValueError('Invalid onion %s' % s)
+ raise ValueError('Invalid onion %s' % vchAddr)
return pchOnionCat + vchAddr
elif '.' in addr: # IPv4
return pchIPv4 + bytearray((int(x) for x in addr.split('.')))
@@ -132,7 +133,7 @@ def main():
with open(os.path.join(indir,'nodes_test.txt'),'r') as f:
process_nodes(g, f, 'pnSeed6_test', 18333)
g.write('#endif // BITCOIN_CHAINPARAMSSEEDS_H\n')
-
+
if __name__ == '__main__':
main()
diff --git a/contrib/seeds/makeseeds.py b/contrib/seeds/makeseeds.py
index 6e253c994d..59044e701a 100755
--- a/contrib/seeds/makeseeds.py
+++ b/contrib/seeds/makeseeds.py
@@ -6,6 +6,11 @@
# Generate seeds.txt from Pieter's DNS seeder
#
+import re
+import sys
+import dns.resolver
+import collections
+
NSEEDS=512
MAX_SEEDS_PER_ASN=2
@@ -22,11 +27,6 @@ SUSPICIOUS_HOSTS = {
"54.94.195.96", "54.94.200.247"
}
-import re
-import sys
-import dns.resolver
-import collections
-
PATTERN_IPV4 = re.compile(r"^((\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})):(\d+)$")
PATTERN_IPV6 = re.compile(r"^\[([0-9a-z:]+)\]:(\d+)$")
PATTERN_ONION = re.compile(r"^([abcdefghijklmnopqrstuvwxyz234567]{16}\.onion):(\d+)$")
diff --git a/contrib/testgen/base58.py b/contrib/testgen/base58.py
index 0dbb79a707..071bc722b0 100644
--- a/contrib/testgen/base58.py
+++ b/contrib/testgen/base58.py
@@ -43,8 +43,10 @@ def b58encode(v):
# leading 0-bytes in the input become leading-1s
nPad = 0
for c in v:
- if c == 0: nPad += 1
- else: break
+ if c == 0:
+ nPad += 1
+ else:
+ break
return (__b58chars[0]*nPad) + result
@@ -98,7 +100,8 @@ def b58decode_chk(v):
def get_bcaddress_version(strAddress):
""" Returns None if strAddress is invalid. Otherwise returns integer version of address. """
addr = b58decode_chk(strAddress)
- if addr is None or len(addr)!=21: return None
+ if addr is None or len(addr)!=21:
+ return None
version = addr[0]
return ord(version)
diff --git a/contrib/testgen/gen_base58_test_vectors.py b/contrib/testgen/gen_base58_test_vectors.py
index 4351605786..de15657d27 100755
--- a/contrib/testgen/gen_base58_test_vectors.py
+++ b/contrib/testgen/gen_base58_test_vectors.py
@@ -74,12 +74,12 @@ def gen_invalid_vector(template, corrupt_prefix, randomize_payload_size, corrupt
prefix = os.urandom(1)
else:
prefix = bytearray(template[0])
-
+
if randomize_payload_size:
payload = os.urandom(max(int(random.expovariate(0.5)), 50))
else:
payload = os.urandom(template[1])
-
+
if corrupt_suffix:
suffix = os.urandom(len(template[2]))
else:
@@ -114,7 +114,8 @@ def gen_invalid_vectors():
yield val,
if __name__ == '__main__':
- import sys, json
+ import sys
+ import json
iters = {'valid':gen_valid_vectors, 'invalid':gen_invalid_vectors}
try:
uiter = iters[sys.argv[1]]
@@ -124,7 +125,7 @@ if __name__ == '__main__':
count = int(sys.argv[2])
except IndexError:
count = 0
-
+
data = list(islice(uiter(), count))
json.dump(data, sys.stdout, sort_keys=True, indent=4)
sys.stdout.write('\n')
diff --git a/depends/Makefile b/depends/Makefile
index 14e94ba453..8b67bce9d8 100644
--- a/depends/Makefile
+++ b/depends/Makefile
@@ -1,6 +1,7 @@
.NOTPARALLEL :
SOURCES_PATH ?= $(BASEDIR)/sources
+WORK_PATH = $(BASEDIR)/work
BASE_CACHE ?= $(BASEDIR)/built
SDK_PATH ?= $(BASEDIR)/SDKs
NO_QT ?=
@@ -29,9 +30,9 @@ else
release_type=release
endif
-base_build_dir=$(BASEDIR)/work/build
-base_staging_dir=$(BASEDIR)/work/staging
-base_download_dir=$(BASEDIR)/work/download
+base_build_dir=$(WORK_PATH)/build
+base_staging_dir=$(WORK_PATH)/staging
+base_download_dir=$(WORK_PATH)/download
canonical_host:=$(shell ./config.sub $(HOST))
build:=$(shell ./config.sub $(BUILD))
@@ -165,6 +166,12 @@ $(host_prefix)/share/config.site: check-packages
check-packages: check-sources
+clean-all: clean
+ @rm -rf $(SOURCES_PATH) x86_64* i686* mips* arm* aarch64*
+
+clean:
+ @rm -rf $(WORK_PATH) $(BASE_CACHE) $(BUILD)
+
install: check-packages $(host_prefix)/share/config.site
@@ -178,4 +185,4 @@ download-win:
@$(MAKE) -s HOST=x86_64-w64-mingw32 download-one
download: download-osx download-linux download-win
-.PHONY: install cached download-one download-osx download-linux download-win download check-packages check-sources
+.PHONY: install cached clean clean-all download-one download-osx download-linux download-win download check-packages check-sources
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index 6b5311d3e3..1f237b750e 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -50,7 +50,7 @@ Do not submit patches solely to modify the style of existing code.
[src/.clang-format](/src/.clang-format). You can use the provided
[clang-format-diff script](/contrib/devtools/README.md#clang-format-diffpy)
tool to clean up patches automatically before submission.
- - Braces on new lines for namespaces, classes, functions, methods.
+ - Braces on new lines for classes, functions, methods.
- Braces on the same line for everything else.
- 4 space indentation (no tabs) for every block except namespaces.
- No indentation for `public`/`protected`/`private` or for `namespace`.
@@ -85,8 +85,7 @@ Block style example:
```c++
int g_count = 0;
-namespace foo
-{
+namespace foo {
class Class
{
std::string m_name;
@@ -585,11 +584,11 @@ Source code organization
```c++
namespace mynamespace {
- ...
+...
} // namespace mynamespace
namespace {
- ...
+...
} // namespace
```
diff --git a/doc/release-notes-pr12823.md b/doc/release-notes-pr12823.md
new file mode 100644
index 0000000000..b493908716
--- /dev/null
+++ b/doc/release-notes-pr12823.md
@@ -0,0 +1,20 @@
+Configuration sections for testnet and regtest
+----------------------------------------------
+
+It is now possible for a single configuration file to set different
+options for different networks. This is done by using sections or by
+prefixing the option with the network, such as:
+
+ main.uacomment=bitcoin
+ test.uacomment=bitcoin-testnet
+ regtest.uacomment=regtest
+ [main]
+ mempoolsize=300
+ [test]
+ mempoolsize=100
+ [regtest]
+ mempoolsize=20
+
+The `addnode=`, `connect=`, `port=`, `bind=`, `rpcport=`, `rpcbind=`
+and `wallet=` options will only apply to mainnet when specified in the
+configuration file, unless a network is specified.
diff --git a/doc/release-notes.md b/doc/release-notes.md
index 9e9c891de9..d4c5b03449 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -65,6 +65,11 @@ RPC changes
- The `fundrawtransaction` RPC will reject the previously deprecated `reserveChangeKey` option.
- `sendmany` now shuffles outputs to improve privacy, so any previously expected behavior with regards to output ordering can no longer be relied upon.
- The new RPC `testmempoolaccept` can be used to test acceptance of a transaction to the mempool without adding it.
+- JSON transaction decomposition now includes a `weight` field which provides
+ the transaction's exact weight. This is included in REST /rest/tx/ and
+ /rest/block/ endpoints when in json mode. This is also included in `getblock`
+ (with verbosity=2), `listsinceblock`, `listtransactions`, and
+ `getrawtransaction` RPC commands.
External wallet files
---------------------
diff --git a/share/rpcauth/rpcauth.py b/share/rpcauth/rpcauth.py
index 10cf516732..f9b9787514 100755
--- a/share/rpcauth/rpcauth.py
+++ b/share/rpcauth/rpcauth.py
@@ -25,7 +25,7 @@ salt = "".join([x[2:] for x in hexseq])
#Create 32 byte b64 password
password = base64.urlsafe_b64encode(os.urandom(32)).decode("utf-8")
-
+
m = hmac.new(bytearray(salt, 'utf-8'), bytearray(password, 'utf-8'), "SHA256")
result = m.hexdigest()
diff --git a/share/setup.nsi.in b/share/setup.nsi.in
index dd42085a27..9fee9b42e0 100644
--- a/share/setup.nsi.in
+++ b/share/setup.nsi.in
@@ -20,7 +20,8 @@ SetCompressor /SOLID lzma
!define MUI_STARTMENUPAGE_REGISTRY_KEY ${REGKEY}
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME StartMenuGroup
!define MUI_STARTMENUPAGE_DEFAULTFOLDER "@PACKAGE_NAME@"
-!define MUI_FINISHPAGE_RUN $INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@
+!define MUI_FINISHPAGE_RUN "$WINDIR\explorer.exe"
+!define MUI_FINISHPAGE_RUN_PARAMETERS $INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@
!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
!define MUI_UNWELCOMEFINISHPAGE_BITMAP "@abs_top_srcdir@/share/pixmaps/nsis-wizard.bmp"
!define MUI_UNFINISHPAGE_NOAUTOCLOSE
diff --git a/src/.clang-format b/src/.clang-format
index 2d2ee67035..38e19edf2c 100644
--- a/src/.clang-format
+++ b/src/.clang-format
@@ -12,7 +12,10 @@ AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackParameters: false
BreakBeforeBinaryOperators: false
-BreakBeforeBraces: Linux
+BreakBeforeBraces: Custom
+BraceWrapping:
+ AfterClass: true
+ AfterFunction: true
BreakBeforeTernaryOperators: false
BreakConstructorInitializersBeforeComma: false
ColumnLimit: 0
diff --git a/src/Makefile.am b/src/Makefile.am
index 1bbb92bf42..521687eb45 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -113,6 +113,7 @@ BITCOIN_CORE_H = \
keystore.h \
dbwrapper.h \
limitedmap.h \
+ logging.h \
memusage.h \
merkleblock.h \
miner.h \
@@ -364,6 +365,7 @@ libbitcoin_util_a_SOURCES = \
fs.cpp \
interfaces/handler.cpp \
interfaces/node.cpp \
+ logging.cpp \
random.cpp \
rpc/protocol.cpp \
rpc/util.cpp \
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index 748c5b7887..3306dcf598 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -25,8 +25,6 @@ bench_bench_bitcoin_SOURCES = \
bench/verify_script.cpp \
bench/base58.cpp \
bench/lockedpool.cpp \
- bench/perf.cpp \
- bench/perf.h \
bench/prevector.cpp
nodist_bench_bench_bitcoin_SOURCES = $(GENERATED_BENCH_FILES)
diff --git a/src/addrdb.cpp b/src/addrdb.cpp
index e4620e63c6..59305ff187 100644
--- a/src/addrdb.cpp
+++ b/src/addrdb.cpp
@@ -49,7 +49,8 @@ bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data
// Serialize
if (!SerializeDB(fileout, data)) return false;
- FileCommit(fileout.Get());
+ if (!FileCommit(fileout.Get()))
+ return error("%s: Failed to flush file %s", __func__, pathTmp.string());
fileout.fclose();
// replace existing file, if any, with new file
diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp
index 21329a5151..de3e57b04f 100644
--- a/src/bench/bench.cpp
+++ b/src/bench/bench.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <bench/bench.h>
-#include <bench/perf.h>
#include <assert.h>
#include <iostream>
@@ -96,7 +95,6 @@ benchmark::BenchRunner::BenchRunner(std::string name, benchmark::BenchFunction f
void benchmark::BenchRunner::RunAll(Printer& printer, uint64_t num_evals, double scaling, const std::string& filter, bool is_list_only)
{
- perf_init();
if (!std::ratio_less_equal<benchmark::clock::period, std::micro>::value) {
std::cerr << "WARNING: Clock precision is worse than microsecond - benchmarks may be less accurate!\n";
}
@@ -126,8 +124,6 @@ void benchmark::BenchRunner::RunAll(Printer& printer, uint64_t num_evals, double
}
printer.footer();
-
- perf_fini();
}
bool benchmark::State::UpdateTimer(const benchmark::time_point current_time)
diff --git a/src/bench/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp
index cdda0bd9be..e05a5e3d1e 100644
--- a/src/bench/mempool_eviction.cpp
+++ b/src/bench/mempool_eviction.cpp
@@ -9,7 +9,7 @@
#include <list>
#include <vector>
-static void AddTx(const CTransaction& tx, const CAmount& nFee, CTxMemPool& pool)
+static void AddTx(const CMutableTransaction& tx, const CAmount& nFee, CTxMemPool& pool)
{
int64_t nTime = 0;
unsigned int nHeight = 1;
diff --git a/src/bench/perf.cpp b/src/bench/perf.cpp
deleted file mode 100644
index f92d08c56e..0000000000
--- a/src/bench/perf.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2016-2017 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 <bench/perf.h>
-
-#if defined(__i386__) || defined(__x86_64__)
-
-/* These architectures support querying the cycle counter
- * from user space, no need for any syscall overhead.
- */
-void perf_init(void) { }
-void perf_fini(void) { }
-
-#elif defined(__linux__)
-
-#include <unistd.h>
-#include <sys/syscall.h>
-#include <linux/perf_event.h>
-
-static int fd = -1;
-static struct perf_event_attr attr;
-
-void perf_init(void)
-{
- attr.type = PERF_TYPE_HARDWARE;
- attr.config = PERF_COUNT_HW_CPU_CYCLES;
- fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0);
-}
-
-void perf_fini(void)
-{
- if (fd != -1) {
- close(fd);
- }
-}
-
-uint64_t perf_cpucycles(void)
-{
- uint64_t result = 0;
- if (fd == -1 || read(fd, &result, sizeof(result)) < (ssize_t)sizeof(result)) {
- return 0;
- }
- return result;
-}
-
-#else /* Unhandled platform */
-
-void perf_init(void) { }
-void perf_fini(void) { }
-uint64_t perf_cpucycles(void) { return 0; }
-
-#endif
diff --git a/src/bench/perf.h b/src/bench/perf.h
deleted file mode 100644
index 73ea8b9647..0000000000
--- a/src/bench/perf.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 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.
-
-/** Functions for measurement of CPU cycles */
-#ifndef BITCOIN_BENCH_PERF_H
-#define BITCOIN_BENCH_PERF_H
-
-#include <stdint.h>
-
-#if defined(__i386__)
-
-static inline uint64_t perf_cpucycles(void)
-{
- uint64_t x;
- __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
- return x;
-}
-
-#elif defined(__x86_64__)
-
-static inline uint64_t perf_cpucycles(void)
-{
- uint32_t hi, lo;
- __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
- return ((uint64_t)lo)|(((uint64_t)hi)<<32);
-}
-#else
-
-uint64_t perf_cpucycles(void);
-
-#endif
-
-void perf_init(void);
-void perf_fini(void);
-
-#endif // BITCOIN_BENCH_PERF_H
diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp
index 705fa368a5..4100519d48 100644
--- a/src/bench/verify_script.cpp
+++ b/src/bench/verify_script.cpp
@@ -71,7 +71,7 @@ static void VerifyScriptBench(benchmark::State& state)
CScript scriptPubKey = CScript() << witnessversion << ToByteVector(pubkeyHash);
CScript scriptSig;
CScript witScriptPubkey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(pubkeyHash) << OP_EQUALVERIFY << OP_CHECKSIG;
- CTransaction txCredit = BuildCreditingTransaction(scriptPubKey);
+ const CMutableTransaction& txCredit = BuildCreditingTransaction(scriptPubKey);
CMutableTransaction txSpend = BuildSpendingTransaction(scriptSig, txCredit);
CScriptWitness& witness = txSpend.vin[0].scriptWitness;
witness.stack.emplace_back();
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index 83d9719df2..0dc2dfbf7d 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -42,12 +42,9 @@
void WaitForShutdown()
{
- bool fShutdown = ShutdownRequested();
- // Tell the main threads to shutdown.
- while (!fShutdown)
+ while (!ShutdownRequested())
{
MilliSleep(200);
- fShutdown = ShutdownRequested();
}
Interrupt();
}
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 6067503b0b..121d95af90 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -75,7 +75,7 @@ public:
CMainParams() {
strNetworkID = "main";
consensus.nSubsidyHalvingInterval = 210000;
- consensus.BIP16Height = 173805; // 00000000000000ce80a7e057163a4db1d5ad7b20fb6f598c9597b9665c8fb0d4 - April 1, 2012
+ consensus.BIP16Exception = uint256S("0x00000000000002dc756eebf4f49723ed8d30cc28a5f108eb94b1ba88ac4f9c22");
consensus.BIP34Height = 227931;
consensus.BIP34Hash = uint256S("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8");
consensus.BIP65Height = 388381; // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0
@@ -190,7 +190,7 @@ public:
CTestNetParams() {
strNetworkID = "test";
consensus.nSubsidyHalvingInterval = 210000;
- consensus.BIP16Height = 514; // 00000000040b4e986385315e14bee30ad876d8b47f748025b26683116d21aa65
+ consensus.BIP16Exception = uint256S("0x00000000dd30457c001f4095d208cc1296b0eed002427aa599874af7a432b105");
consensus.BIP34Height = 21111;
consensus.BIP34Hash = uint256S("0x0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8");
consensus.BIP65Height = 581885; // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6
@@ -283,7 +283,7 @@ public:
CRegTestParams() {
strNetworkID = "regtest";
consensus.nSubsidyHalvingInterval = 150;
- consensus.BIP16Height = 0; // always enforce P2SH BIP16 on regtest
+ consensus.BIP16Exception = uint256();
consensus.BIP34Height = 100000000; // BIP34 has not activated on regtest (far in the future so block v1 are not rejected in tests)
consensus.BIP34Hash = uint256();
consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in rpc activation tests)
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index e840a2ed30..3ef9c2cfe5 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -47,4 +47,5 @@ std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain
void SelectBaseParams(const std::string& chain)
{
globalChainBaseParams = CreateBaseChainParams(chain);
+ gArgs.SelectConfigNetwork(chain);
}
diff --git a/src/compat.h b/src/compat.h
index 8a0f901304..920b3f776d 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -96,6 +96,12 @@ typedef int32_t ssize_t;
size_t strnlen( const char *start, size_t max_len);
#endif // HAVE_DECL_STRNLEN
+#ifndef WIN32
+typedef void* sockopt_arg_type;
+#else
+typedef char* sockopt_arg_type;
+#endif
+
bool static inline IsSelectableSocket(const SOCKET& s) {
#ifdef WIN32
return true;
diff --git a/src/compat/endian.h b/src/compat/endian.h
index e5c7e50223..4f244c3930 100644
--- a/src/compat/endian.h
+++ b/src/compat/endian.h
@@ -19,6 +19,51 @@
#include <sys/endian.h>
#endif
+#ifndef HAVE_CONFIG_H
+// While not technically a supported configuration, defaulting to defining these
+// DECLs when we were compiled without autotools makes it easier for other build
+// systems to build things like libbitcoinconsensus for strange targets.
+#ifdef htobe16
+#define HAVE_DECL_HTOBE16 1
+#endif
+#ifdef htole16
+#define HAVE_DECL_HTOLE16 1
+#endif
+#ifdef be16toh
+#define HAVE_DECL_BE16TOH 1
+#endif
+#ifdef le16toh
+#define HAVE_DECL_LE16TOH 1
+#endif
+
+#ifdef htobe32
+#define HAVE_DECL_HTOBE32 1
+#endif
+#ifdef htole32
+#define HAVE_DECL_HTOLE32 1
+#endif
+#ifdef be32toh
+#define HAVE_DECL_BE32TOH 1
+#endif
+#ifdef le32toh
+#define HAVE_DECL_LE32TOH 1
+#endif
+
+#ifdef htobe64
+#define HAVE_DECL_HTOBE64 1
+#endif
+#ifdef htole64
+#define HAVE_DECL_HTOLE64 1
+#endif
+#ifdef be64toh
+#define HAVE_DECL_BE64TOH 1
+#endif
+#ifdef le64toh
+#define HAVE_DECL_LE64TOH 1
+#endif
+
+#endif // HAVE_CONFIG_H
+
#if defined(WORDS_BIGENDIAN)
#if HAVE_DECL_HTOBE16 == 0
diff --git a/src/consensus/params.h b/src/consensus/params.h
index 4ef808c856..0559304fc2 100644
--- a/src/consensus/params.h
+++ b/src/consensus/params.h
@@ -49,8 +49,8 @@ struct BIP9Deployment {
struct Params {
uint256 hashGenesisBlock;
int nSubsidyHalvingInterval;
- /** Block height at which BIP16 becomes active */
- int BIP16Height;
+ /* Block hash that is excepted from BIP16 enforcement */
+ uint256 BIP16Exception;
/** Block height and hash at which BIP34 becomes active */
int BIP34Height;
uint256 BIP34Hash;
diff --git a/src/core_write.cpp b/src/core_write.cpp
index 54b18a4931..929498ff28 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -161,6 +161,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
entry.pushKV("version", tx.nVersion);
entry.pushKV("size", (int)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION));
entry.pushKV("vsize", (GetTransactionWeight(tx) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR);
+ entry.pushKV("weight", GetTransactionWeight(tx));
entry.pushKV("locktime", (int64_t)tx.nLockTime);
UniValue vin(UniValue::VARR);
diff --git a/src/init.cpp b/src/init.cpp
index 486c84f5a3..f403f90b08 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -76,19 +76,18 @@ std::unique_ptr<PeerLogicValidation> peerLogic;
class DummyWalletInit : public WalletInitInterface {
public:
- std::string GetHelpString(bool showDebug) override {return std::string{};}
- bool ParameterInteraction() override {return true;}
- void RegisterRPC(CRPCTable &) override {}
- bool Verify() override {return true;}
- bool Open() override {LogPrintf("No wallet support compiled in!\n"); return true;}
- void Start(CScheduler& scheduler) override {}
- void Flush() override {}
- void Stop() override {}
- void Close() override {}
+ std::string GetHelpString(bool showDebug) const override {return std::string{};}
+ bool ParameterInteraction() const override {return true;}
+ void RegisterRPC(CRPCTable &) const override {}
+ bool Verify() const override {return true;}
+ bool Open() const override {LogPrintf("No wallet support compiled in!\n"); return true;}
+ void Start(CScheduler& scheduler) const override {}
+ void Flush() const override {}
+ void Stop() const override {}
+ void Close() const override {}
};
-static DummyWalletInit g_dummy_wallet_init;
-WalletInitInterface* const g_wallet_init_interface = &g_dummy_wallet_init;
+const WalletInitInterface& g_wallet_init_interface = DummyWalletInit();
#endif
#if ENABLE_ZMQ
@@ -204,7 +203,7 @@ void Shutdown()
StopREST();
StopRPC();
StopHTTPServer();
- g_wallet_init_interface->Flush();
+ g_wallet_init_interface.Flush();
StopMapPort();
// Because these depend on each-other, we make sure that neither can be
@@ -262,7 +261,7 @@ void Shutdown()
pcoinsdbview.reset();
pblocktree.reset();
}
- g_wallet_init_interface->Stop();
+ g_wallet_init_interface.Stop();
#if ENABLE_ZMQ
if (pzmqNotificationInterface) {
@@ -282,7 +281,7 @@ void Shutdown()
UnregisterAllValidationInterfaces();
GetMainSignals().UnregisterBackgroundSignalScheduler();
GetMainSignals().UnregisterWithMempoolSignals(mempool);
- g_wallet_init_interface->Close();
+ g_wallet_init_interface.Close();
globalVerifyHandle.reset();
ECC_Stop();
LogPrintf("%s: done\n", __func__);
@@ -425,7 +424,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-whitelist=<IP address or network>", _("Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR notated network (e.g. 1.2.3.0/24). Can be specified multiple times.") +
" " + _("Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway"));
- strUsage += g_wallet_init_interface->GetHelpString(showDebug);
+ strUsage += g_wallet_init_interface.GetHelpString(showDebug);
#if ENABLE_ZMQ
strUsage += HelpMessageGroup(_("ZeroMQ notification options:"));
@@ -685,7 +684,7 @@ void ThreadImport(std::vector<fs::path> vImportFiles)
// scan for better chains in the block chain database, that are not yet connected in the active best chain
CValidationState state;
if (!ActivateBestChain(state, chainparams)) {
- LogPrintf("Failed to connect best block\n");
+ LogPrintf("Failed to connect best block (%s)\n", FormatStateMessage(state));
StartShutdown();
return;
}
@@ -803,6 +802,11 @@ void InitParameterInteraction()
if (gArgs.SoftSetBoolArg("-whitelistrelay", true))
LogPrintf("%s: parameter interaction: -whitelistforcerelay=1 -> setting -whitelistrelay=1\n", __func__);
}
+
+ // Warn if network-specific options (-addnode, -connect, etc) are
+ // specified in default section of config file, but not overridden
+ // on the command line or in this network's section of the config file.
+ gArgs.WarnForSectionOnlyArgs();
}
static std::string ResolveErrMsg(const char * const optname, const std::string& strBind)
@@ -810,14 +814,25 @@ static std::string ResolveErrMsg(const char * const optname, const std::string&
return strprintf(_("Cannot resolve -%s address: '%s'"), optname, strBind);
}
+/**
+ * Initialize global loggers.
+ *
+ * Note that this is called very early in the process lifetime, so you should be
+ * careful about what global state you rely on here.
+ */
void InitLogging()
{
- fPrintToConsole = gArgs.GetBoolArg("-printtoconsole", false);
+ // Add newlines to the logfile to distinguish this execution from the last
+ // one; called before console logging is set up, so this is only sent to
+ // debug.log.
+ LogPrintf("\n\n\n\n\n");
+
+ fPrintToConsole = gArgs.GetBoolArg("-printtoconsole", !gArgs.GetBoolArg("-daemon", false));
+ fPrintToDebugLog = !gArgs.IsArgNegated("-debuglogfile");
fLogTimestamps = gArgs.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS);
fLogTimeMicros = gArgs.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS);
fLogIPs = gArgs.GetBoolArg("-logips", DEFAULT_LOGIPS);
- LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
std::string version_string = FormatFullVersion();
#ifdef DEBUG
version_string += " (debug build)";
@@ -1093,7 +1108,7 @@ bool AppInitParameterInteraction()
return InitError(strprintf("acceptnonstdtxn is not currently supported for %s chain", chainparams.NetworkIDString()));
nBytesPerSigOp = gArgs.GetArg("-bytespersigop", nBytesPerSigOp);
- if (!g_wallet_init_interface->ParameterInteraction()) return false;
+ if (!g_wallet_init_interface.ParameterInteraction()) return false;
fIsBareMultisigStd = gArgs.GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG);
fAcceptDatacarrier = gArgs.GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER);
@@ -1211,13 +1226,12 @@ bool AppInitMain()
#ifndef WIN32
CreatePidFile(GetPidFile(), getpid());
#endif
- if (gArgs.GetBoolArg("-shrinkdebugfile", logCategories == BCLog::NONE)) {
- // Do this first since it both loads a bunch of debug.log into memory,
- // and because this needs to happen before any other debug.log printing
- ShrinkDebugFile();
- }
-
if (fPrintToDebugLog) {
+ if (gArgs.GetBoolArg("-shrinkdebugfile", logCategories == BCLog::NONE)) {
+ // Do this first since it both loads a bunch of debug.log into memory,
+ // and because this needs to happen before any other debug.log printing
+ ShrinkDebugFile();
+ }
if (!OpenDebugLog()) {
return InitError(strprintf("Could not open debug log file %s", GetDebugLogPath().string()));
}
@@ -1259,7 +1273,7 @@ bool AppInitMain()
* available in the GUI RPC console even if external calls are disabled.
*/
RegisterAllCoreRPCCommands(tableRPC);
- g_wallet_init_interface->RegisterRPC(tableRPC);
+ g_wallet_init_interface.RegisterRPC(tableRPC);
/* Start the RPC server already. It will be started in "warmup" mode
* and not really process calls already (but it will signify connections
@@ -1276,7 +1290,7 @@ bool AppInitMain()
int64_t nStart;
// ********************************************************* Step 5: verify wallet database integrity
- if (!g_wallet_init_interface->Verify()) return false;
+ if (!g_wallet_init_interface.Verify()) return false;
// ********************************************************* Step 6: network initialization
// Note that we absolutely cannot open any actual connections
@@ -1595,7 +1609,7 @@ bool AppInitMain()
fFeeEstimatesInitialized = true;
// ********************************************************* Step 8: load wallet
- if (!g_wallet_init_interface->Open()) return false;
+ if (!g_wallet_init_interface.Open()) return false;
// ********************************************************* Step 9: data directory maintenance
@@ -1741,7 +1755,7 @@ bool AppInitMain()
SetRPCWarmupFinished();
uiInterface.InitMessage(_("Done loading"));
- g_wallet_init_interface->Start(scheduler);
+ g_wallet_init_interface.Start(scheduler);
return true;
}
diff --git a/src/init.h b/src/init.h
index 829c110112..000c8c95e4 100644
--- a/src/init.h
+++ b/src/init.h
@@ -13,7 +13,7 @@ class CScheduler;
class CWallet;
class WalletInitInterface;
-extern WalletInitInterface* const g_wallet_init_interface;
+extern const WalletInitInterface& g_wallet_init_interface;
namespace boost
{
diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp
index 919748f942..e55cba3c65 100644
--- a/src/interfaces/node.cpp
+++ b/src/interfaces/node.cpp
@@ -216,9 +216,6 @@ class NodeImpl : public Node
return result;
}
CFeeRate getDustRelayFee() override { return ::dustRelayFee; }
- CFeeRate getFallbackFee() override { CHECK_WALLET(return CWallet::fallbackFee); }
- CFeeRate getPayTxFee() override { CHECK_WALLET(return ::payTxFee); }
- void setPayTxFee(CFeeRate rate) override { CHECK_WALLET(::payTxFee = rate); }
UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) override
{
JSONRPCRequest req;
@@ -239,7 +236,7 @@ class NodeImpl : public Node
{
#ifdef ENABLE_WALLET
std::vector<std::unique_ptr<Wallet>> wallets;
- for (CWalletRef wallet : ::vpwallets) {
+ for (CWallet* wallet : GetWallets()) {
wallets.emplace_back(MakeWallet(*wallet));
}
return wallets;
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index f375af2f19..84e869100a 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -173,15 +173,6 @@ public:
//! Get dust relay fee.
virtual CFeeRate getDustRelayFee() = 0;
- //! Get fallback fee.
- virtual CFeeRate getFallbackFee() = 0;
-
- //! Get pay tx fee.
- virtual CFeeRate getPayTxFee() = 0;
-
- //! Set pay tx fee.
- virtual void setPayTxFee(CFeeRate rate) = 0;
-
//! Execute rpc command.
virtual UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) = 0;
diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h
index dfe3d5f711..9d4830d189 100644
--- a/src/interfaces/wallet.h
+++ b/src/interfaces/wallet.h
@@ -6,7 +6,7 @@
#define BITCOIN_INTERFACES_WALLET_H
#include <amount.h> // For CAmount
-#include <pubkey.h> // For CTxDestination (CKeyID and CScriptID)
+#include <pubkey.h> // For CKeyID and CScriptID (definitions needed in CTxDestination instantiation)
#include <script/ismine.h> // For isminefilter, isminetype
#include <script/standard.h> // For CTxDestination
#include <support/allocators/secure.h> // For SecureString
diff --git a/src/logging.cpp b/src/logging.cpp
new file mode 100644
index 0000000000..e481582321
--- /dev/null
+++ b/src/logging.cpp
@@ -0,0 +1,283 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-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 <logging.h>
+#include <util.h>
+#include <utilstrencodings.h>
+
+#include <list>
+#include <mutex>
+
+const char * const DEFAULT_DEBUGLOGFILE = "debug.log";
+
+bool fPrintToConsole = false;
+bool fPrintToDebugLog = true;
+
+bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS;
+bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS;
+bool fLogIPs = DEFAULT_LOGIPS;
+std::atomic<bool> fReopenDebugLog(false);
+
+/** Log categories bitfield. */
+std::atomic<uint32_t> logCategories(0);
+/**
+ * LogPrintf() has been broken a couple of times now
+ * by well-meaning people adding mutexes in the most straightforward way.
+ * It breaks because it may be called by global destructors during shutdown.
+ * Since the order of destruction of static/global objects is undefined,
+ * defining a mutex as a global object doesn't work (the mutex gets
+ * destroyed, and then some later destructor calls OutputDebugStringF,
+ * maybe indirectly, and you get a core dump at shutdown trying to lock
+ * the mutex).
+ */
+
+static std::once_flag debugPrintInitFlag;
+
+/**
+ * We use std::call_once() to make sure mutexDebugLog and
+ * vMsgsBeforeOpenLog are initialized in a thread-safe manner.
+ *
+ * NOTE: fileout, mutexDebugLog and sometimes vMsgsBeforeOpenLog
+ * are leaked on exit. This is ugly, but will be cleaned up by
+ * the OS/libc. When the shutdown sequence is fully audited and
+ * tested, explicit destruction of these objects can be implemented.
+ */
+static FILE* fileout = nullptr;
+static std::mutex* mutexDebugLog = nullptr;
+static std::list<std::string>* vMsgsBeforeOpenLog;
+
+static int FileWriteStr(const std::string &str, FILE *fp)
+{
+ return fwrite(str.data(), 1, str.size(), fp);
+}
+
+static void DebugPrintInit()
+{
+ assert(mutexDebugLog == nullptr);
+ mutexDebugLog = new std::mutex();
+ vMsgsBeforeOpenLog = new std::list<std::string>;
+}
+
+fs::path GetDebugLogPath()
+{
+ fs::path logfile(gArgs.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE));
+ return AbsPathForConfigVal(logfile);
+}
+
+bool OpenDebugLog()
+{
+ std::call_once(debugPrintInitFlag, &DebugPrintInit);
+ std::lock_guard<std::mutex> scoped_lock(*mutexDebugLog);
+
+ assert(fileout == nullptr);
+ assert(vMsgsBeforeOpenLog);
+ fs::path pathDebug = GetDebugLogPath();
+
+ fileout = fsbridge::fopen(pathDebug, "a");
+ if (!fileout) {
+ return false;
+ }
+
+ setbuf(fileout, nullptr); // unbuffered
+ // dump buffered messages from before we opened the log
+ while (!vMsgsBeforeOpenLog->empty()) {
+ FileWriteStr(vMsgsBeforeOpenLog->front(), fileout);
+ vMsgsBeforeOpenLog->pop_front();
+ }
+
+ delete vMsgsBeforeOpenLog;
+ vMsgsBeforeOpenLog = nullptr;
+ return true;
+}
+
+struct CLogCategoryDesc
+{
+ uint32_t flag;
+ std::string category;
+};
+
+const CLogCategoryDesc LogCategories[] =
+{
+ {BCLog::NONE, "0"},
+ {BCLog::NONE, "none"},
+ {BCLog::NET, "net"},
+ {BCLog::TOR, "tor"},
+ {BCLog::MEMPOOL, "mempool"},
+ {BCLog::HTTP, "http"},
+ {BCLog::BENCH, "bench"},
+ {BCLog::ZMQ, "zmq"},
+ {BCLog::DB, "db"},
+ {BCLog::RPC, "rpc"},
+ {BCLog::ESTIMATEFEE, "estimatefee"},
+ {BCLog::ADDRMAN, "addrman"},
+ {BCLog::SELECTCOINS, "selectcoins"},
+ {BCLog::REINDEX, "reindex"},
+ {BCLog::CMPCTBLOCK, "cmpctblock"},
+ {BCLog::RAND, "rand"},
+ {BCLog::PRUNE, "prune"},
+ {BCLog::PROXY, "proxy"},
+ {BCLog::MEMPOOLREJ, "mempoolrej"},
+ {BCLog::LIBEVENT, "libevent"},
+ {BCLog::COINDB, "coindb"},
+ {BCLog::QT, "qt"},
+ {BCLog::LEVELDB, "leveldb"},
+ {BCLog::ALL, "1"},
+ {BCLog::ALL, "all"},
+};
+
+bool GetLogCategory(uint32_t *f, const std::string *str)
+{
+ if (f && str) {
+ if (*str == "") {
+ *f = BCLog::ALL;
+ return true;
+ }
+ for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
+ if (LogCategories[i].category == *str) {
+ *f = LogCategories[i].flag;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+std::string ListLogCategories()
+{
+ std::string ret;
+ int outcount = 0;
+ for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
+ // Omit the special cases.
+ if (LogCategories[i].flag != BCLog::NONE && LogCategories[i].flag != BCLog::ALL) {
+ if (outcount != 0) ret += ", ";
+ ret += LogCategories[i].category;
+ outcount++;
+ }
+ }
+ return ret;
+}
+
+std::vector<CLogCategoryActive> ListActiveLogCategories()
+{
+ std::vector<CLogCategoryActive> ret;
+ for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
+ // Omit the special cases.
+ if (LogCategories[i].flag != BCLog::NONE && LogCategories[i].flag != BCLog::ALL) {
+ CLogCategoryActive catActive;
+ catActive.category = LogCategories[i].category;
+ catActive.active = LogAcceptCategory(LogCategories[i].flag);
+ ret.push_back(catActive);
+ }
+ }
+ return ret;
+}
+
+/**
+ * fStartedNewLine is a state variable held by the calling context that will
+ * suppress printing of the timestamp when multiple calls are made that don't
+ * end in a newline. Initialize it to true, and hold it, in the calling context.
+ */
+static std::string LogTimestampStr(const std::string &str, std::atomic_bool *fStartedNewLine)
+{
+ std::string strStamped;
+
+ if (!fLogTimestamps)
+ return str;
+
+ if (*fStartedNewLine) {
+ int64_t nTimeMicros = GetTimeMicros();
+ strStamped = FormatISO8601DateTime(nTimeMicros/1000000);
+ if (fLogTimeMicros) {
+ strStamped.pop_back();
+ strStamped += strprintf(".%06dZ", nTimeMicros%1000000);
+ }
+ int64_t mocktime = GetMockTime();
+ if (mocktime) {
+ strStamped += " (mocktime: " + FormatISO8601DateTime(mocktime) + ")";
+ }
+ strStamped += ' ' + str;
+ } else
+ strStamped = str;
+
+ if (!str.empty() && str[str.size()-1] == '\n')
+ *fStartedNewLine = true;
+ else
+ *fStartedNewLine = false;
+
+ return strStamped;
+}
+
+int LogPrintStr(const std::string &str)
+{
+ int ret = 0; // Returns total number of characters written
+ static std::atomic_bool fStartedNewLine(true);
+
+ std::string strTimestamped = LogTimestampStr(str, &fStartedNewLine);
+
+ if (fPrintToConsole) {
+ // print to console
+ ret = fwrite(strTimestamped.data(), 1, strTimestamped.size(), stdout);
+ fflush(stdout);
+ }
+ if (fPrintToDebugLog) {
+ std::call_once(debugPrintInitFlag, &DebugPrintInit);
+ std::lock_guard<std::mutex> scoped_lock(*mutexDebugLog);
+
+ // buffer if we haven't opened the log yet
+ if (fileout == nullptr) {
+ assert(vMsgsBeforeOpenLog);
+ ret = strTimestamped.length();
+ vMsgsBeforeOpenLog->push_back(strTimestamped);
+ }
+ else
+ {
+ // reopen the log file, if requested
+ if (fReopenDebugLog) {
+ fReopenDebugLog = false;
+ fs::path pathDebug = GetDebugLogPath();
+ if (fsbridge::freopen(pathDebug,"a",fileout) != nullptr)
+ setbuf(fileout, nullptr); // unbuffered
+ }
+
+ ret = FileWriteStr(strTimestamped, fileout);
+ }
+ }
+ return ret;
+}
+
+void ShrinkDebugFile()
+{
+ // Amount of debug.log to save at end when shrinking (must fit in memory)
+ constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000;
+ // Scroll debug.log if it's getting too big
+ fs::path pathLog = GetDebugLogPath();
+ FILE* file = fsbridge::fopen(pathLog, "r");
+
+ // Special files (e.g. device nodes) may not have a size.
+ size_t log_size = 0;
+ try {
+ log_size = fs::file_size(pathLog);
+ } catch (boost::filesystem::filesystem_error &) {}
+
+ // If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE
+ // trim it down by saving only the last RECENT_DEBUG_HISTORY_SIZE bytes
+ if (file && log_size > 11 * (RECENT_DEBUG_HISTORY_SIZE / 10))
+ {
+ // Restart the file with some of the end
+ std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0);
+ fseek(file, -((long)vch.size()), SEEK_END);
+ int nBytes = fread(vch.data(), 1, vch.size(), file);
+ fclose(file);
+
+ file = fsbridge::fopen(pathLog, "w");
+ if (file)
+ {
+ fwrite(vch.data(), 1, nBytes, file);
+ fclose(file);
+ }
+ }
+ else if (file != nullptr)
+ fclose(file);
+}
diff --git a/src/logging.h b/src/logging.h
new file mode 100644
index 0000000000..4053f75acf
--- /dev/null
+++ b/src/logging.h
@@ -0,0 +1,125 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-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.
+
+#ifndef BITCOIN_LOGGING_H
+#define BITCOIN_LOGGING_H
+
+#include <fs.h>
+#include <tinyformat.h>
+
+#include <atomic>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+static const bool DEFAULT_LOGTIMEMICROS = false;
+static const bool DEFAULT_LOGIPS = false;
+static const bool DEFAULT_LOGTIMESTAMPS = true;
+extern const char * const DEFAULT_DEBUGLOGFILE;
+
+extern bool fPrintToConsole;
+extern bool fPrintToDebugLog;
+
+extern bool fLogTimestamps;
+extern bool fLogTimeMicros;
+extern bool fLogIPs;
+extern std::atomic<bool> fReopenDebugLog;
+
+extern std::atomic<uint32_t> logCategories;
+
+struct CLogCategoryActive
+{
+ 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),
+ DB = (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),
+ ALL = ~(uint32_t)0,
+ };
+}
+/** Return true if log accepts specified category */
+static inline bool LogAcceptCategory(uint32_t category)
+{
+ return (logCategories.load(std::memory_order_relaxed) & category) != 0;
+}
+
+/** Returns a string with the log categories. */
+std::string ListLogCategories();
+
+/** Returns a vector of the active log categories. */
+std::vector<CLogCategoryActive> ListActiveLogCategories();
+
+/** Return true if str parses as a log category and set the flags in f */
+bool GetLogCategory(uint32_t *f, const std::string *str);
+
+/** Send a string to the log output */
+int LogPrintStr(const std::string &str);
+
+/** Get format string from VA_ARGS for error reporting */
+template<typename... Args> std::string FormatStringFromLogArgs(const char *fmt, const Args&... args) { return fmt; }
+
+static inline void MarkUsed() {}
+template<typename T, typename... Args> static inline void MarkUsed(const T& t, const Args&... args)
+{
+ (void)t;
+ MarkUsed(args...);
+}
+
+// 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.
+
+#ifdef USE_COVERAGE
+#define LogPrintf(...) do { MarkUsed(__VA_ARGS__); } while(0)
+#define LogPrint(category, ...) do { MarkUsed(__VA_ARGS__); } while(0)
+#else
+#define LogPrintf(...) do { \
+ if (fPrintToConsole || fPrintToDebugLog) { \
+ std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \
+ try { \
+ _log_msg_ = tfm::format(__VA_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: " + FormatStringFromLogArgs(__VA_ARGS__); \
+ } \
+ LogPrintStr(_log_msg_); \
+ } \
+} while(0)
+
+#define LogPrint(category, ...) do { \
+ if (LogAcceptCategory((category))) { \
+ LogPrintf(__VA_ARGS__); \
+ } \
+} while(0)
+#endif
+
+fs::path GetDebugLogPath();
+bool OpenDebugLog();
+void ShrinkDebugFile();
+
+#endif // BITCOIN_LOGGING_H
diff --git a/src/net.cpp b/src/net.cpp
index 356a66563f..cd076c1ce2 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -1923,23 +1923,25 @@ std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo()
for (const std::string& strAddNode : lAddresses) {
CService service(LookupNumeric(strAddNode.c_str(), Params().GetDefaultPort()));
+ AddedNodeInfo addedNode{strAddNode, CService(), false, false};
if (service.IsValid()) {
// strAddNode is an IP:port
auto it = mapConnected.find(service);
if (it != mapConnected.end()) {
- ret.push_back(AddedNodeInfo{strAddNode, service, true, it->second});
- } else {
- ret.push_back(AddedNodeInfo{strAddNode, CService(), false, false});
+ addedNode.resolvedAddress = service;
+ addedNode.fConnected = true;
+ addedNode.fInbound = it->second;
}
} else {
// strAddNode is a name
auto it = mapConnectedByName.find(strAddNode);
if (it != mapConnectedByName.end()) {
- ret.push_back(AddedNodeInfo{strAddNode, it->second.second, true, it->second.first});
- } else {
- ret.push_back(AddedNodeInfo{strAddNode, CService(), false, false});
+ addedNode.resolvedAddress = it->second.second;
+ addedNode.fConnected = true;
+ addedNode.fInbound = it->second.first;
}
}
+ ret.emplace_back(std::move(addedNode));
}
return ret;
@@ -2088,23 +2090,16 @@ bool CConnman::BindListenPort(const CService &addrBind, std::string& strError, b
LogPrintf("%s\n", strError);
return false;
}
-#ifndef WIN32
+
// Allow binding if the port is still in TIME_WAIT state after
// the program was closed and restarted.
- setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
-#else
- setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&nOne, sizeof(int));
-#endif
+ setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (sockopt_arg_type)&nOne, sizeof(int));
// some systems don't have IPV6_V6ONLY but are always v6only; others do have the option
// and enable it by default or not. Try to enable it, if possible.
if (addrBind.IsIPv6()) {
#ifdef IPV6_V6ONLY
-#ifdef WIN32
- setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&nOne, sizeof(int));
-#else
- setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&nOne, sizeof(int));
-#endif
+ setsockopt(hListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (sockopt_arg_type)&nOne, sizeof(int));
#endif
#ifdef WIN32
int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED;
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index dbdae705de..ee4e9e61bc 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -1100,8 +1100,10 @@ void static ProcessGetBlockData(CNode* pfrom, const Consensus::Params& consensus
}
} // release cs_main before calling ActivateBestChain
if (need_activate_chain) {
- CValidationState dummy;
- ActivateBestChain(dummy, Params(), a_recent_block);
+ CValidationState state;
+ if (!ActivateBestChain(state, Params(), a_recent_block)) {
+ LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state));
+ }
}
LOCK(cs_main);
@@ -1992,8 +1994,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
LOCK(cs_most_recent_block);
a_recent_block = most_recent_block;
}
- CValidationState dummy;
- ActivateBestChain(dummy, Params(), a_recent_block);
+ CValidationState state;
+ if (!ActivateBestChain(state, Params(), a_recent_block)) {
+ LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state));
+ }
}
LOCK(cs_main);
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index 4f231d73c8..18d5948f85 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -14,7 +14,7 @@ static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43};
// 0xFD + sha256("bitcoin")[0:5]
static const unsigned char g_internal_prefix[] = { 0xFD, 0x6B, 0x88, 0xC0, 0x87, 0x24 };
-void CNetAddr::Init()
+CNetAddr::CNetAddr()
{
memset(ip, 0, sizeof(ip));
scopeId = 0;
@@ -67,11 +67,6 @@ bool CNetAddr::SetSpecial(const std::string &strName)
return false;
}
-CNetAddr::CNetAddr()
-{
- Init();
-}
-
CNetAddr::CNetAddr(const struct in_addr& ipv4Addr)
{
SetRaw(NET_IPV4, (const uint8_t*)&ipv4Addr);
@@ -290,11 +285,6 @@ bool operator==(const CNetAddr& a, const CNetAddr& b)
return (memcmp(a.ip, b.ip, 16) == 0);
}
-bool operator!=(const CNetAddr& a, const CNetAddr& b)
-{
- return (memcmp(a.ip, b.ip, 16) != 0);
-}
-
bool operator<(const CNetAddr& a, const CNetAddr& b)
{
return (memcmp(a.ip, b.ip, 16) < 0);
@@ -469,14 +459,8 @@ int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const
}
}
-void CService::Init()
+CService::CService() : port(0)
{
- port = 0;
-}
-
-CService::CService()
-{
- Init();
}
CService::CService(const CNetAddr& cip, unsigned short portIn) : CNetAddr(cip), port(portIn)
@@ -525,11 +509,6 @@ bool operator==(const CService& a, const CService& b)
return static_cast<CNetAddr>(a) == static_cast<CNetAddr>(b) && a.port == b.port;
}
-bool operator!=(const CService& a, const CService& b)
-{
- return static_cast<CNetAddr>(a) != static_cast<CNetAddr>(b) || a.port != b.port;
-}
-
bool operator<(const CService& a, const CService& b)
{
return static_cast<CNetAddr>(a) < static_cast<CNetAddr>(b) || (static_cast<CNetAddr>(a) == static_cast<CNetAddr>(b) && a.port < b.port);
@@ -663,16 +642,16 @@ bool CSubNet::Match(const CNetAddr &addr) const
static inline int NetmaskBits(uint8_t x)
{
switch(x) {
- case 0x00: return 0; break;
- case 0x80: return 1; break;
- case 0xc0: return 2; break;
- case 0xe0: return 3; break;
- case 0xf0: return 4; break;
- case 0xf8: return 5; break;
- case 0xfc: return 6; break;
- case 0xfe: return 7; break;
- case 0xff: return 8; break;
- default: return -1; break;
+ case 0x00: return 0;
+ case 0x80: return 1;
+ case 0xc0: return 2;
+ case 0xe0: return 3;
+ case 0xf0: return 4;
+ case 0xf8: return 5;
+ case 0xfc: return 6;
+ case 0xfe: return 7;
+ case 0xff: return 8;
+ default: return -1;
}
}
@@ -724,11 +703,6 @@ bool operator==(const CSubNet& a, const CSubNet& b)
return a.valid == b.valid && a.network == b.network && !memcmp(a.netmask, b.netmask, 16);
}
-bool operator!=(const CSubNet& a, const CSubNet& b)
-{
- return !(a==b);
-}
-
bool operator<(const CSubNet& a, const CSubNet& b)
{
return (a.network < b.network || (a.network == b.network && memcmp(a.netmask, b.netmask, 16) < 0));
diff --git a/src/netaddress.h b/src/netaddress.h
index 38f8709257..f8f2ab99ff 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -38,15 +38,16 @@ class CNetAddr
public:
CNetAddr();
explicit CNetAddr(const struct in_addr& ipv4Addr);
- void Init();
void SetIP(const CNetAddr& ip);
+ private:
/**
* Set raw IPv4 or IPv6 address (in network byte order)
* @note Only NET_IPV4 and NET_IPV6 are allowed for network.
*/
void SetRaw(Network network, const uint8_t *data);
+ public:
/**
* Transform an arbitrary string into a non-routable ipv6 address.
* Useful for mapping resolved addresses back to their source.
@@ -87,7 +88,7 @@ class CNetAddr
bool GetIn6Addr(struct in6_addr* pipv6Addr) const;
friend bool operator==(const CNetAddr& a, const CNetAddr& b);
- friend bool operator!=(const CNetAddr& a, const CNetAddr& b);
+ friend bool operator!=(const CNetAddr& a, const CNetAddr& b) { return !(a == b); }
friend bool operator<(const CNetAddr& a, const CNetAddr& b);
ADD_SERIALIZE_METHODS;
@@ -124,7 +125,7 @@ class CSubNet
bool IsValid() const;
friend bool operator==(const CSubNet& a, const CSubNet& b);
- friend bool operator!=(const CSubNet& a, const CSubNet& b);
+ friend bool operator!=(const CSubNet& a, const CSubNet& b) { return !(a == b); }
friend bool operator<(const CSubNet& a, const CSubNet& b);
ADD_SERIALIZE_METHODS;
@@ -148,12 +149,11 @@ class CService : public CNetAddr
CService(const CNetAddr& ip, unsigned short port);
CService(const struct in_addr& ipv4Addr, unsigned short port);
explicit CService(const struct sockaddr_in& addr);
- void Init();
unsigned short GetPort() const;
bool GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const;
bool SetSockAddr(const struct sockaddr* paddr);
friend bool operator==(const CService& a, const CService& b);
- friend bool operator!=(const CService& a, const CService& b);
+ friend bool operator!=(const CService& a, const CService& b) { return !(a == b); }
friend bool operator<(const CService& a, const CService& b);
std::vector<unsigned char> GetKey() const;
std::string ToString() const;
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 5d3d2f25c8..57835b5427 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -513,11 +513,7 @@ bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, i
return false;
}
socklen_t nRetSize = sizeof(nRet);
-#ifdef WIN32
- if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR)
-#else
- if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR)
-#endif
+ if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (sockopt_arg_type)&nRet, &nRetSize) == SOCKET_ERROR)
{
LogPrintf("getsockopt() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
return false;
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index dcc834c352..56d2d38194 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -180,9 +180,9 @@ void TestGUI()
TransactionView transactionView(platformStyle.get());
auto node = interfaces::MakeNode();
OptionsModel optionsModel(*node);
- vpwallets.insert(vpwallets.begin(), &wallet);
- WalletModel walletModel(std::move(node->getWallets()[0]), *node, platformStyle.get(), &optionsModel);
- vpwallets.erase(vpwallets.begin());
+ AddWallet(&wallet);
+ WalletModel walletModel(std::move(node->getWallets().back()), *node, platformStyle.get(), &optionsModel);
+ RemoveWallet(&wallet);
sendCoinsDialog.setModel(&walletModel);
transactionView.setModel(&walletModel);
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 49e865a64a..6754407dbd 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -69,7 +69,7 @@ UniValue validateaddress(const JSONRPCRequest& request)
{
#ifdef ENABLE_WALLET
- if (!::vpwallets.empty() && IsDeprecatedRPCEnabled("validateaddress")) {
+ if (HasWallets() && IsDeprecatedRPCEnabled("validateaddress")) {
ret.pushKVs(getaddressinfo(request));
}
#endif
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 543e4fc358..7bdf09812b 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -94,6 +94,7 @@ UniValue getrawtransaction(const JSONRPCRequest& request)
" \"hash\" : \"id\", (string) The transaction hash (differs from txid for witness transactions)\n"
" \"size\" : n, (numeric) The serialized transaction size\n"
" \"vsize\" : n, (numeric) The virtual transaction size (differs from size for witness transactions)\n"
+ " \"weight\" : n, (numeric) The transaction's weight (between vsize*4-3 and vsize*4)\n"
" \"version\" : n, (numeric) The version\n"
" \"locktime\" : ttt, (numeric) The lock time\n"
" \"vin\" : [ (array of json objects)\n"
@@ -494,6 +495,7 @@ UniValue decoderawtransaction(const JSONRPCRequest& request)
" \"hash\" : \"id\", (string) The transaction hash (differs from txid for witness transactions)\n"
" \"size\" : n, (numeric) The transaction size\n"
" \"vsize\" : n, (numeric) The virtual transaction size (differs from size for witness transactions)\n"
+ " \"weight\" : n, (numeric) The transaction's weight (between vsize*4 - 3 and vsize*4)\n"
" \"version\" : n, (numeric) The version\n"
" \"locktime\" : ttt, (numeric) The lock time\n"
" \"vin\" : [ (array of json objects)\n"
diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp
index 32330e0548..8cffacbffe 100644
--- a/src/test/blockencodings_tests.cpp
+++ b/src/test/blockencodings_tests.cpp
@@ -52,8 +52,8 @@ static CBlock BuildBlockTestCase() {
}
// Number of shared use_counts we expect for a tx we haven't touched
-// == 2 (mempool + our copy from the GetSharedTx call)
-#define SHARED_TX_OFFSET 2
+// (block + mempool + our copy from the GetSharedTx call)
+constexpr long SHARED_TX_OFFSET{3};
BOOST_AUTO_TEST_CASE(SimpleRoundTripTest)
{
@@ -61,7 +61,7 @@ BOOST_AUTO_TEST_CASE(SimpleRoundTripTest)
TestMemPoolEntryHelper entry;
CBlock block(BuildBlockTestCase());
- pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(*block.vtx[2]));
+ pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(block.vtx[2]));
LOCK(pool.cs);
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
@@ -161,7 +161,7 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
TestMemPoolEntryHelper entry;
CBlock block(BuildBlockTestCase());
- pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(*block.vtx[2]));
+ pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(block.vtx[2]));
LOCK(pool.cs);
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
@@ -188,7 +188,7 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
BOOST_CHECK( partialBlock.IsTxAvailable(1));
BOOST_CHECK( partialBlock.IsTxAvailable(2));
- BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1);
+ BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); // +1 because of partialBlock
CBlock block2;
{
@@ -203,6 +203,7 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
partialBlock.FillBlock(block2, {block.vtx[1]}); // Current implementation doesn't check txn here, but don't require that
partialBlock = tmp;
}
+ BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 2); // +2 because of partialBlock and block2
bool mutated;
BOOST_CHECK(block.hashMerkleRoot != BlockMerkleRoot(block2, &mutated));
@@ -213,13 +214,15 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block3, &mutated).ToString());
BOOST_CHECK(!mutated);
+ BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 3); // +2 because of partialBlock and block2 and block3
+
txhash = block.vtx[2]->GetHash();
block.vtx.clear();
block2.vtx.clear();
block3.vtx.clear();
- BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); // + 1 because of partialBlockCopy.
+ BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1 - 1); // + 1 because of partialBlock; -1 because of block.
}
- BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
+ BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET - 1); // -1 because of block
}
BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
@@ -228,7 +231,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
TestMemPoolEntryHelper entry;
CBlock block(BuildBlockTestCase());
- pool.addUnchecked(block.vtx[1]->GetHash(), entry.FromTx(*block.vtx[1]));
+ pool.addUnchecked(block.vtx[1]->GetHash(), entry.FromTx(block.vtx[1]));
LOCK(pool.cs);
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
@@ -268,9 +271,9 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
txhash = block.vtx[1]->GetHash();
block.vtx.clear();
block2.vtx.clear();
- BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); // + 1 because of partialBlockCopy.
+ BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1 - 1); // + 1 because of partialBlock; -1 because of block.
}
- BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
+ BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET - 1); // -1 because of block
}
BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index b593f9633c..066f6328a6 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -19,7 +19,7 @@
BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup)
CScript
-sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transaction, int whichIn)
+sign_multisig(const CScript& scriptPubKey, const std::vector<CKey>& keys, const CTransaction& transaction, int whichIn)
{
uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, SigVersion::BASE);
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 46a2d13745..a06b573b37 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -1029,7 +1029,7 @@ BOOST_AUTO_TEST_CASE(script_PushData)
}
CScript
-sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transaction)
+sign_multisig(const CScript& scriptPubKey, const std::vector<CKey>& keys, const CTransaction& transaction)
{
uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL, 0, SigVersion::BASE);
@@ -1053,7 +1053,7 @@ sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transac
return result;
}
CScript
-sign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction)
+sign_multisig(const CScript& scriptPubKey, const CKey& key, const CTransaction& transaction)
{
std::vector<CKey> keys;
keys.push_back(key);
diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp
index 94164346f3..eba58e0042 100644
--- a/src/test/serialize_tests.cpp
+++ b/src/test/serialize_tests.cpp
@@ -23,7 +23,7 @@ protected:
CTransactionRef txval;
public:
CSerializeMethodsTestSingle() = default;
- CSerializeMethodsTestSingle(int intvalin, bool boolvalin, std::string stringvalin, const char* charstrvalin, CTransaction txvalin) : intval(intvalin), boolval(boolvalin), stringval(std::move(stringvalin)), txval(MakeTransactionRef(txvalin))
+ CSerializeMethodsTestSingle(int intvalin, bool boolvalin, std::string stringvalin, const char* charstrvalin, const CTransactionRef& txvalin) : intval(intvalin), boolval(boolvalin), stringval(std::move(stringvalin)), txval(txvalin)
{
memcpy(charstrval, charstrvalin, sizeof(charstrval));
}
@@ -350,8 +350,9 @@ BOOST_AUTO_TEST_CASE(class_methods)
std::string stringval("testing");
const char charstrval[16] = "testing charstr";
CMutableTransaction txval;
- CSerializeMethodsTestSingle methodtest1(intval, boolval, stringval, charstrval, txval);
- CSerializeMethodsTestMany methodtest2(intval, boolval, stringval, charstrval, txval);
+ CTransactionRef tx_ref{MakeTransactionRef(txval)};
+ CSerializeMethodsTestSingle methodtest1(intval, boolval, stringval, charstrval, tx_ref);
+ CSerializeMethodsTestMany methodtest2(intval, boolval, stringval, charstrval, tx_ref);
CSerializeMethodsTestSingle methodtest3;
CSerializeMethodsTestMany methodtest4;
CDataStream ss(SER_DISK, PROTOCOL_VERSION);
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index ff20d4b3d7..e9873f4526 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -85,7 +85,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
{
CValidationState state;
if (!ActivateBestChain(state, chainparams)) {
- throw std::runtime_error("ActivateBestChain failed.");
+ throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", FormatStateMessage(state)));
}
}
nScriptCheckThreads = 3;
@@ -123,7 +123,7 @@ TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST)
{
std::vector<CMutableTransaction> noTxns;
CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey);
- coinbaseTxns.push_back(*b.vtx[0]);
+ m_coinbase_txns.push_back(b.vtx[0]);
}
}
@@ -164,12 +164,12 @@ TestChain100Setup::~TestChain100Setup()
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx) {
- CTransaction txn(tx);
- return FromTx(txn);
+ return FromTx(MakeTransactionRef(tx));
}
-CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransaction &txn) {
- return CTxMemPoolEntry(MakeTransactionRef(txn), nFee, nTime, nHeight,
+CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransactionRef& tx)
+{
+ return CTxMemPoolEntry(tx, nFee, nTime, nHeight,
spendsCoinbase, sigOpCost, lp);
}
diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h
index 8136da3aa9..1f91eb622c 100644
--- a/src/test/test_bitcoin.h
+++ b/src/test/test_bitcoin.h
@@ -87,7 +87,7 @@ struct TestChain100Setup : public TestingSetup {
~TestChain100Setup();
- std::vector<CTransaction> coinbaseTxns; // For convenience, coinbase transactions
+ std::vector<CTransactionRef> m_coinbase_txns; // For convenience, coinbase transactions
CKey coinbaseKey; // private/public key needed to spend coinbase transactions
};
@@ -107,8 +107,8 @@ struct TestMemPoolEntryHelper
nFee(0), nTime(0), nHeight(1),
spendsCoinbase(false), sigOpCost(4) { }
- CTxMemPoolEntry FromTx(const CMutableTransaction &tx);
- CTxMemPoolEntry FromTx(const CTransaction &tx);
+ CTxMemPoolEntry FromTx(const CMutableTransaction& tx);
+ CTxMemPoolEntry FromTx(const CTransactionRef& tx);
// Change the default value
TestMemPoolEntryHelper &Fee(CAmount _fee) { nFee = _fee; return *this; }
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index 71f3d727b1..7a52697859 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -48,7 +48,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
{
spends[i].nVersion = 1;
spends[i].vin.resize(1);
- spends[i].vin[0].prevout.hash = coinbaseTxns[0].GetHash();
+ spends[i].vin[0].prevout.hash = m_coinbase_txns[0]->GetHash();
spends[i].vin[0].prevout.n = 0;
spends[i].vout.resize(1);
spends[i].vout[0].nValue = 11*CENT;
@@ -167,7 +167,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
spend_tx.nVersion = 1;
spend_tx.vin.resize(1);
- spend_tx.vin[0].prevout.hash = coinbaseTxns[0].GetHash();
+ spend_tx.vin[0].prevout.hash = m_coinbase_txns[0]->GetHash();
spend_tx.vin[0].prevout.n = 0;
spend_tx.vout.resize(4);
spend_tx.vout[0].nValue = 11*CENT;
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index e8c7b80c3a..1c3acfb1a5 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -176,13 +176,22 @@ BOOST_AUTO_TEST_CASE(util_FormatISO8601Time)
struct TestArgsManager : public ArgsManager
{
- std::map<std::string, std::string>& GetMapArgs() { return mapArgs; }
- const std::map<std::string, std::vector<std::string> >& GetMapMultiArgs() { return mapMultiArgs; }
- const std::unordered_set<std::string>& GetNegatedArgs() { return m_negated_args; }
+ TestArgsManager() { m_network_only_args.clear(); }
+ std::map<std::string, std::vector<std::string> >& GetOverrideArgs() { return m_override_args; }
+ std::map<std::string, std::vector<std::string> >& GetConfigArgs() { return m_config_args; }
void ReadConfigString(const std::string str_config)
{
- std::istringstream stream(str_config);
- ReadConfigStream(stream);
+ std::istringstream streamConfig(str_config);
+ {
+ LOCK(cs_args);
+ m_config_args.clear();
+ }
+ ReadConfigStream(streamConfig);
+ }
+ void SetNetworkOnlyArg(const std::string arg)
+ {
+ LOCK(cs_args);
+ m_network_only_args.insert(arg);
}
};
@@ -192,22 +201,26 @@ BOOST_AUTO_TEST_CASE(util_ParseParameters)
const char *argv_test[] = {"-ignored", "-a", "-b", "-ccc=argument", "-ccc=multiple", "f", "-d=e"};
testArgs.ParseParameters(0, (char**)argv_test);
- BOOST_CHECK(testArgs.GetMapArgs().empty() && testArgs.GetMapMultiArgs().empty());
+ BOOST_CHECK(testArgs.GetOverrideArgs().empty() && testArgs.GetConfigArgs().empty());
testArgs.ParseParameters(1, (char**)argv_test);
- BOOST_CHECK(testArgs.GetMapArgs().empty() && testArgs.GetMapMultiArgs().empty());
+ BOOST_CHECK(testArgs.GetOverrideArgs().empty() && testArgs.GetConfigArgs().empty());
testArgs.ParseParameters(7, (char**)argv_test);
// expectation: -ignored is ignored (program name argument),
// -a, -b and -ccc end up in map, -d ignored because it is after
// a non-option argument (non-GNU option parsing)
- BOOST_CHECK(testArgs.GetMapArgs().size() == 3 && testArgs.GetMapMultiArgs().size() == 3);
+ BOOST_CHECK(testArgs.GetOverrideArgs().size() == 3 && testArgs.GetConfigArgs().empty());
BOOST_CHECK(testArgs.IsArgSet("-a") && testArgs.IsArgSet("-b") && testArgs.IsArgSet("-ccc")
&& !testArgs.IsArgSet("f") && !testArgs.IsArgSet("-d"));
- BOOST_CHECK(testArgs.GetMapMultiArgs().count("-a") && testArgs.GetMapMultiArgs().count("-b") && testArgs.GetMapMultiArgs().count("-ccc")
- && !testArgs.GetMapMultiArgs().count("f") && !testArgs.GetMapMultiArgs().count("-d"));
-
- BOOST_CHECK(testArgs.GetMapArgs()["-a"] == "" && testArgs.GetMapArgs()["-ccc"] == "multiple");
+ BOOST_CHECK(testArgs.GetOverrideArgs().count("-a") && testArgs.GetOverrideArgs().count("-b") && testArgs.GetOverrideArgs().count("-ccc")
+ && !testArgs.GetOverrideArgs().count("f") && !testArgs.GetOverrideArgs().count("-d"));
+
+ BOOST_CHECK(testArgs.GetOverrideArgs()["-a"].size() == 1);
+ BOOST_CHECK(testArgs.GetOverrideArgs()["-a"].front() == "");
+ BOOST_CHECK(testArgs.GetOverrideArgs()["-ccc"].size() == 2);
+ BOOST_CHECK(testArgs.GetOverrideArgs()["-ccc"].front() == "argument");
+ BOOST_CHECK(testArgs.GetOverrideArgs()["-ccc"].back() == "multiple");
BOOST_CHECK(testArgs.GetArgs("-ccc").size() == 2);
}
@@ -223,15 +236,14 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArg)
BOOST_CHECK(testArgs.IsArgSet({'-', opt}) || !opt);
// Nothing else should be in the map
- BOOST_CHECK(testArgs.GetMapArgs().size() == 6 &&
- testArgs.GetMapMultiArgs().size() == 6);
+ BOOST_CHECK(testArgs.GetOverrideArgs().size() == 6 &&
+ testArgs.GetConfigArgs().empty());
// The -no prefix should get stripped on the way in.
BOOST_CHECK(!testArgs.IsArgSet("-nob"));
// The -b option is flagged as negated, and nothing else is
BOOST_CHECK(testArgs.IsArgNegated("-b"));
- BOOST_CHECK(testArgs.GetNegatedArgs().size() == 1);
BOOST_CHECK(!testArgs.IsArgNegated("-a"));
// Check expected values.
@@ -256,8 +268,8 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases)
BOOST_CHECK(!testArgs.IsArgNegated("-foo"));
BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "");
- // A double negative is a positive.
- BOOST_CHECK(testArgs.IsArgNegated("-bar"));
+ // A double negative is a positive, and not marked as negated.
+ BOOST_CHECK(!testArgs.IsArgNegated("-bar"));
BOOST_CHECK(testArgs.GetArg("-bar", "xxx") == "1");
// Config test
@@ -266,12 +278,12 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases)
testArgs.ReadConfigString(conf_test);
// This was passed twice, second one overrides the negative setting,
- // but not the value.
+ // and the value.
BOOST_CHECK(!testArgs.IsArgNegated("-foo"));
- BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "0");
+ BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "1");
- // A double negative is a positive.
- BOOST_CHECK(testArgs.IsArgNegated("-bar"));
+ // A double negative is a positive, and does not count as negated.
+ BOOST_CHECK(!testArgs.IsArgNegated("-bar"));
BOOST_CHECK(testArgs.GetArg("-bar", "xxx") == "1");
// Combined test
@@ -281,18 +293,15 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases)
testArgs.ReadConfigString(combo_test_conf);
// Command line overrides, but doesn't erase old setting
- BOOST_CHECK(!testArgs.IsArgNegated("-foo"));
+ BOOST_CHECK(testArgs.IsArgNegated("-foo"));
BOOST_CHECK(testArgs.GetArg("-foo", "xxx") == "0");
- BOOST_CHECK(testArgs.GetArgs("-foo").size() == 2
- && testArgs.GetArgs("-foo").front() == "0"
- && testArgs.GetArgs("-foo").back() == "1");
+ BOOST_CHECK(testArgs.GetArgs("-foo").size() == 0);
// Command line overrides, but doesn't erase old setting
- BOOST_CHECK(testArgs.IsArgNegated("-bar"));
+ BOOST_CHECK(!testArgs.IsArgNegated("-bar"));
BOOST_CHECK(testArgs.GetArg("-bar", "xxx") == "");
- BOOST_CHECK(testArgs.GetArgs("-bar").size() == 2
- && testArgs.GetArgs("-bar").front() == ""
- && testArgs.GetArgs("-bar").back() == "0");
+ BOOST_CHECK(testArgs.GetArgs("-bar").size() == 1
+ && testArgs.GetArgs("-bar").front() == "");
}
BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
@@ -308,24 +317,39 @@ BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
"h=1\n"
"noh=1\n"
"noi=1\n"
- "i=1\n";
+ "i=1\n"
+ "sec1.ccc=extend1\n"
+ "\n"
+ "[sec1]\n"
+ "ccc=extend2\n"
+ "d=eee\n"
+ "h=1\n"
+ "[sec2]\n"
+ "ccc=extend3\n"
+ "iii=2\n";
TestArgsManager test_args;
test_args.ReadConfigString(str_config);
// expectation: a, b, ccc, d, fff, ggg, h, i end up in map
-
- BOOST_CHECK(test_args.GetMapArgs().size() == 8);
- BOOST_CHECK(test_args.GetMapMultiArgs().size() == 8);
-
- BOOST_CHECK(test_args.GetMapArgs().count("-a")
- && test_args.GetMapArgs().count("-b")
- && test_args.GetMapArgs().count("-ccc")
- && test_args.GetMapArgs().count("-d")
- && test_args.GetMapArgs().count("-fff")
- && test_args.GetMapArgs().count("-ggg")
- && test_args.GetMapArgs().count("-h")
- && test_args.GetMapArgs().count("-i")
+ // so do sec1.ccc, sec1.d, sec1.h, sec2.ccc, sec2.iii
+
+ BOOST_CHECK(test_args.GetOverrideArgs().empty());
+ BOOST_CHECK(test_args.GetConfigArgs().size() == 13);
+
+ BOOST_CHECK(test_args.GetConfigArgs().count("-a")
+ && test_args.GetConfigArgs().count("-b")
+ && test_args.GetConfigArgs().count("-ccc")
+ && test_args.GetConfigArgs().count("-d")
+ && test_args.GetConfigArgs().count("-fff")
+ && test_args.GetConfigArgs().count("-ggg")
+ && test_args.GetConfigArgs().count("-h")
+ && test_args.GetConfigArgs().count("-i")
+ );
+ BOOST_CHECK(test_args.GetConfigArgs().count("-sec1.ccc")
+ && test_args.GetConfigArgs().count("-sec1.h")
+ && test_args.GetConfigArgs().count("-sec2.ccc")
+ && test_args.GetConfigArgs().count("-sec2.iii")
);
BOOST_CHECK(test_args.IsArgSet("-a")
@@ -337,6 +361,7 @@ BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
&& test_args.IsArgSet("-h")
&& test_args.IsArgSet("-i")
&& !test_args.IsArgSet("-zzz")
+ && !test_args.IsArgSet("-iii")
);
BOOST_CHECK(test_args.GetArg("-a", "xxx") == ""
@@ -345,9 +370,10 @@ BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
&& test_args.GetArg("-d", "xxx") == "e"
&& test_args.GetArg("-fff", "xxx") == "0"
&& test_args.GetArg("-ggg", "xxx") == "1"
- && test_args.GetArg("-h", "xxx") == "1" // 1st value takes precedence
- && test_args.GetArg("-i", "xxx") == "0" // 1st value takes precedence
+ && test_args.GetArg("-h", "xxx") == "0"
+ && test_args.GetArg("-i", "xxx") == "1"
&& test_args.GetArg("-zzz", "xxx") == "xxx"
+ && test_args.GetArg("-iii", "xxx") == "xxx"
);
for (bool def : {false, true}) {
@@ -357,9 +383,10 @@ BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
&& !test_args.GetBoolArg("-d", def)
&& !test_args.GetBoolArg("-fff", def)
&& test_args.GetBoolArg("-ggg", def)
- && test_args.GetBoolArg("-h", def)
- && !test_args.GetBoolArg("-i", def)
+ && !test_args.GetBoolArg("-h", def)
+ && test_args.GetBoolArg("-i", def)
&& test_args.GetBoolArg("-zzz", def) == def
+ && test_args.GetBoolArg("-iii", def) == def
);
}
@@ -370,19 +397,15 @@ BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2
&& test_args.GetArgs("-ccc").front() == "argument"
&& test_args.GetArgs("-ccc").back() == "multiple");
- BOOST_CHECK(test_args.GetArgs("-fff").size() == 1
- && test_args.GetArgs("-fff").front() == "0");
+ BOOST_CHECK(test_args.GetArgs("-fff").size() == 0);
BOOST_CHECK(test_args.GetArgs("-nofff").size() == 0);
BOOST_CHECK(test_args.GetArgs("-ggg").size() == 1
&& test_args.GetArgs("-ggg").front() == "1");
BOOST_CHECK(test_args.GetArgs("-noggg").size() == 0);
- BOOST_CHECK(test_args.GetArgs("-h").size() == 2
- && test_args.GetArgs("-h").front() == "1"
- && test_args.GetArgs("-h").back() == "0");
+ BOOST_CHECK(test_args.GetArgs("-h").size() == 0);
BOOST_CHECK(test_args.GetArgs("-noh").size() == 0);
- BOOST_CHECK(test_args.GetArgs("-i").size() == 2
- && test_args.GetArgs("-i").front() == "0"
- && test_args.GetArgs("-i").back() == "1");
+ BOOST_CHECK(test_args.GetArgs("-i").size() == 1
+ && test_args.GetArgs("-i").front() == "1");
BOOST_CHECK(test_args.GetArgs("-noi").size() == 0);
BOOST_CHECK(test_args.GetArgs("-zzz").size() == 0);
@@ -391,25 +414,98 @@ BOOST_AUTO_TEST_CASE(util_ReadConfigStream)
BOOST_CHECK(!test_args.IsArgNegated("-ccc"));
BOOST_CHECK(!test_args.IsArgNegated("-d"));
BOOST_CHECK(test_args.IsArgNegated("-fff"));
- BOOST_CHECK(test_args.IsArgNegated("-ggg")); // IsArgNegated==true when noggg=0
+ BOOST_CHECK(!test_args.IsArgNegated("-ggg"));
BOOST_CHECK(test_args.IsArgNegated("-h")); // last setting takes precedence
BOOST_CHECK(!test_args.IsArgNegated("-i")); // last setting takes precedence
BOOST_CHECK(!test_args.IsArgNegated("-zzz"));
+
+ // Test sections work
+ test_args.SelectConfigNetwork("sec1");
+
+ // same as original
+ BOOST_CHECK(test_args.GetArg("-a", "xxx") == ""
+ && test_args.GetArg("-b", "xxx") == "1"
+ && test_args.GetArg("-fff", "xxx") == "0"
+ && test_args.GetArg("-ggg", "xxx") == "1"
+ && test_args.GetArg("-zzz", "xxx") == "xxx"
+ && test_args.GetArg("-iii", "xxx") == "xxx"
+ );
+ // d is overridden
+ BOOST_CHECK(test_args.GetArg("-d", "xxx") == "eee");
+ // section-specific setting
+ BOOST_CHECK(test_args.GetArg("-h", "xxx") == "1");
+ // section takes priority for multiple values
+ BOOST_CHECK(test_args.GetArg("-ccc", "xxx") == "extend1");
+ // check multiple values works
+ const std::vector<std::string> sec1_ccc_expected = {"extend1","extend2","argument","multiple"};
+ const auto& sec1_ccc_res = test_args.GetArgs("-ccc");
+ BOOST_CHECK_EQUAL_COLLECTIONS(sec1_ccc_res.begin(), sec1_ccc_res.end(), sec1_ccc_expected.begin(), sec1_ccc_expected.end());
+
+ test_args.SelectConfigNetwork("sec2");
+
+ // same as original
+ BOOST_CHECK(test_args.GetArg("-a", "xxx") == ""
+ && test_args.GetArg("-b", "xxx") == "1"
+ && test_args.GetArg("-d", "xxx") == "e"
+ && test_args.GetArg("-fff", "xxx") == "0"
+ && test_args.GetArg("-ggg", "xxx") == "1"
+ && test_args.GetArg("-zzz", "xxx") == "xxx"
+ && test_args.GetArg("-h", "xxx") == "0"
+ );
+ // section-specific setting
+ BOOST_CHECK(test_args.GetArg("-iii", "xxx") == "2");
+ // section takes priority for multiple values
+ BOOST_CHECK(test_args.GetArg("-ccc", "xxx") == "extend3");
+ // check multiple values works
+ const std::vector<std::string> sec2_ccc_expected = {"extend3","argument","multiple"};
+ const auto& sec2_ccc_res = test_args.GetArgs("-ccc");
+ BOOST_CHECK_EQUAL_COLLECTIONS(sec2_ccc_res.begin(), sec2_ccc_res.end(), sec2_ccc_expected.begin(), sec2_ccc_expected.end());
+
+ // Test section only options
+
+ test_args.SetNetworkOnlyArg("-d");
+ test_args.SetNetworkOnlyArg("-ccc");
+ test_args.SetNetworkOnlyArg("-h");
+
+ test_args.SelectConfigNetwork(CBaseChainParams::MAIN);
+ BOOST_CHECK(test_args.GetArg("-d", "xxx") == "e");
+ BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2);
+ BOOST_CHECK(test_args.GetArg("-h", "xxx") == "0");
+
+ test_args.SelectConfigNetwork("sec1");
+ BOOST_CHECK(test_args.GetArg("-d", "xxx") == "eee");
+ BOOST_CHECK(test_args.GetArgs("-d").size() == 1);
+ BOOST_CHECK(test_args.GetArgs("-ccc").size() == 2);
+ BOOST_CHECK(test_args.GetArg("-h", "xxx") == "1");
+
+ test_args.SelectConfigNetwork("sec2");
+ BOOST_CHECK(test_args.GetArg("-d", "xxx") == "xxx");
+ BOOST_CHECK(test_args.GetArgs("-d").size() == 0);
+ BOOST_CHECK(test_args.GetArgs("-ccc").size() == 1);
+ BOOST_CHECK(test_args.GetArg("-h", "xxx") == "0");
}
BOOST_AUTO_TEST_CASE(util_GetArg)
{
TestArgsManager testArgs;
- testArgs.GetMapArgs().clear();
- testArgs.GetMapArgs()["strtest1"] = "string...";
+ testArgs.GetOverrideArgs().clear();
+ testArgs.GetOverrideArgs()["strtest1"] = {"string..."};
// strtest2 undefined on purpose
- testArgs.GetMapArgs()["inttest1"] = "12345";
- testArgs.GetMapArgs()["inttest2"] = "81985529216486895";
+ testArgs.GetOverrideArgs()["inttest1"] = {"12345"};
+ testArgs.GetOverrideArgs()["inttest2"] = {"81985529216486895"};
// inttest3 undefined on purpose
- testArgs.GetMapArgs()["booltest1"] = "";
+ testArgs.GetOverrideArgs()["booltest1"] = {""};
// booltest2 undefined on purpose
- testArgs.GetMapArgs()["booltest3"] = "0";
- testArgs.GetMapArgs()["booltest4"] = "1";
+ testArgs.GetOverrideArgs()["booltest3"] = {"0"};
+ testArgs.GetOverrideArgs()["booltest4"] = {"1"};
+
+ // priorities
+ testArgs.GetOverrideArgs()["pritest1"] = {"a", "b"};
+ testArgs.GetConfigArgs()["pritest2"] = {"a", "b"};
+ testArgs.GetOverrideArgs()["pritest3"] = {"a"};
+ testArgs.GetConfigArgs()["pritest3"] = {"b"};
+ testArgs.GetOverrideArgs()["pritest4"] = {"a","b"};
+ testArgs.GetConfigArgs()["pritest4"] = {"c","d"};
BOOST_CHECK_EQUAL(testArgs.GetArg("strtest1", "default"), "string...");
BOOST_CHECK_EQUAL(testArgs.GetArg("strtest2", "default"), "default");
@@ -420,6 +516,11 @@ BOOST_AUTO_TEST_CASE(util_GetArg)
BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest2", false), false);
BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest3", false), false);
BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest4", false), true);
+
+ BOOST_CHECK_EQUAL(testArgs.GetArg("pritest1", "default"), "b");
+ BOOST_CHECK_EQUAL(testArgs.GetArg("pritest2", "default"), "a");
+ BOOST_CHECK_EQUAL(testArgs.GetArg("pritest3", "default"), "a");
+ BOOST_CHECK_EQUAL(testArgs.GetArg("pritest4", "default"), "b");
}
BOOST_AUTO_TEST_CASE(util_GetChainName)
@@ -432,7 +533,8 @@ BOOST_AUTO_TEST_CASE(util_GetChainName)
const char* argv_both[] = {"cmd", "-testnet", "-regtest"};
// equivalent to "-testnet"
- const char* testnetconf = "testnet=1\nregtest=0\n";
+ // regtest in testnet section is ignored
+ const char* testnetconf = "testnet=1\nregtest=0\n[test]\nregtest=1";
test_args.ParseParameters(0, (char**)argv_testnet);
BOOST_CHECK_EQUAL(test_args.GetChainName(), "main");
@@ -468,6 +570,30 @@ BOOST_AUTO_TEST_CASE(util_GetChainName)
test_args.ParseParameters(3, (char**)argv_both);
test_args.ReadConfigString(testnetconf);
BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
+
+ // check setting the network to test (and thus making
+ // [test] regtest=1 potentially relevant) doesn't break things
+ test_args.SelectConfigNetwork("test");
+
+ test_args.ParseParameters(0, (char**)argv_testnet);
+ test_args.ReadConfigString(testnetconf);
+ BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
+
+ test_args.ParseParameters(2, (char**)argv_testnet);
+ test_args.ReadConfigString(testnetconf);
+ BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
+
+ test_args.ParseParameters(2, (char**)argv_regtest);
+ test_args.ReadConfigString(testnetconf);
+ BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
+
+ test_args.ParseParameters(2, (char**)argv_test_no_reg);
+ test_args.ReadConfigString(testnetconf);
+ BOOST_CHECK_EQUAL(test_args.GetChainName(), "test");
+
+ test_args.ParseParameters(3, (char**)argv_both);
+ test_args.ReadConfigString(testnetconf);
+ BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
}
BOOST_AUTO_TEST_CASE(util_FormatMoney)
diff --git a/src/util.cpp b/src/util.cpp
index f55c9c8c34..9a3067259f 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -84,21 +84,11 @@ const int64_t nStartupTime = GetTime();
const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf";
const char * const BITCOIN_PID_FILENAME = "bitcoind.pid";
-const char * const DEFAULT_DEBUGLOGFILE = "debug.log";
ArgsManager gArgs;
-bool fPrintToConsole = false;
-bool fPrintToDebugLog = true;
-bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS;
-bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS;
-bool fLogIPs = DEFAULT_LOGIPS;
-std::atomic<bool> fReopenDebugLog(false);
CTranslationInterface translationInterface;
-/** Log categories bitfield. */
-std::atomic<uint32_t> logCategories(0);
-
/** Init OpenSSL library multithreading support */
static std::unique_ptr<CCriticalSection[]> ppmutexOpenSSL;
void locking_callback(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS
@@ -147,233 +137,6 @@ public:
}
instance_of_cinit;
-/**
- * LogPrintf() has been broken a couple of times now
- * by well-meaning people adding mutexes in the most straightforward way.
- * It breaks because it may be called by global destructors during shutdown.
- * Since the order of destruction of static/global objects is undefined,
- * defining a mutex as a global object doesn't work (the mutex gets
- * destroyed, and then some later destructor calls OutputDebugStringF,
- * maybe indirectly, and you get a core dump at shutdown trying to lock
- * the mutex).
- */
-
-static std::once_flag debugPrintInitFlag;
-
-/**
- * We use std::call_once() to make sure mutexDebugLog and
- * vMsgsBeforeOpenLog are initialized in a thread-safe manner.
- *
- * NOTE: fileout, mutexDebugLog and sometimes vMsgsBeforeOpenLog
- * are leaked on exit. This is ugly, but will be cleaned up by
- * the OS/libc. When the shutdown sequence is fully audited and
- * tested, explicit destruction of these objects can be implemented.
- */
-static FILE* fileout = nullptr;
-static std::mutex* mutexDebugLog = nullptr;
-static std::list<std::string>* vMsgsBeforeOpenLog;
-
-static int FileWriteStr(const std::string &str, FILE *fp)
-{
- return fwrite(str.data(), 1, str.size(), fp);
-}
-
-static void DebugPrintInit()
-{
- assert(mutexDebugLog == nullptr);
- mutexDebugLog = new std::mutex();
- vMsgsBeforeOpenLog = new std::list<std::string>;
-}
-
-fs::path GetDebugLogPath()
-{
- fs::path logfile(gArgs.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE));
- return AbsPathForConfigVal(logfile);
-}
-
-bool OpenDebugLog()
-{
- std::call_once(debugPrintInitFlag, &DebugPrintInit);
- std::lock_guard<std::mutex> scoped_lock(*mutexDebugLog);
-
- assert(fileout == nullptr);
- assert(vMsgsBeforeOpenLog);
- fs::path pathDebug = GetDebugLogPath();
-
- fileout = fsbridge::fopen(pathDebug, "a");
- if (!fileout) {
- return false;
- }
-
- setbuf(fileout, nullptr); // unbuffered
- // dump buffered messages from before we opened the log
- while (!vMsgsBeforeOpenLog->empty()) {
- FileWriteStr(vMsgsBeforeOpenLog->front(), fileout);
- vMsgsBeforeOpenLog->pop_front();
- }
-
- delete vMsgsBeforeOpenLog;
- vMsgsBeforeOpenLog = nullptr;
- return true;
-}
-
-struct CLogCategoryDesc
-{
- uint32_t flag;
- std::string category;
-};
-
-const CLogCategoryDesc LogCategories[] =
-{
- {BCLog::NONE, "0"},
- {BCLog::NONE, "none"},
- {BCLog::NET, "net"},
- {BCLog::TOR, "tor"},
- {BCLog::MEMPOOL, "mempool"},
- {BCLog::HTTP, "http"},
- {BCLog::BENCH, "bench"},
- {BCLog::ZMQ, "zmq"},
- {BCLog::DB, "db"},
- {BCLog::RPC, "rpc"},
- {BCLog::ESTIMATEFEE, "estimatefee"},
- {BCLog::ADDRMAN, "addrman"},
- {BCLog::SELECTCOINS, "selectcoins"},
- {BCLog::REINDEX, "reindex"},
- {BCLog::CMPCTBLOCK, "cmpctblock"},
- {BCLog::RAND, "rand"},
- {BCLog::PRUNE, "prune"},
- {BCLog::PROXY, "proxy"},
- {BCLog::MEMPOOLREJ, "mempoolrej"},
- {BCLog::LIBEVENT, "libevent"},
- {BCLog::COINDB, "coindb"},
- {BCLog::QT, "qt"},
- {BCLog::LEVELDB, "leveldb"},
- {BCLog::ALL, "1"},
- {BCLog::ALL, "all"},
-};
-
-bool GetLogCategory(uint32_t *f, const std::string *str)
-{
- if (f && str) {
- if (*str == "") {
- *f = BCLog::ALL;
- return true;
- }
- for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
- if (LogCategories[i].category == *str) {
- *f = LogCategories[i].flag;
- return true;
- }
- }
- }
- return false;
-}
-
-std::string ListLogCategories()
-{
- std::string ret;
- int outcount = 0;
- for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
- // Omit the special cases.
- if (LogCategories[i].flag != BCLog::NONE && LogCategories[i].flag != BCLog::ALL) {
- if (outcount != 0) ret += ", ";
- ret += LogCategories[i].category;
- outcount++;
- }
- }
- return ret;
-}
-
-std::vector<CLogCategoryActive> ListActiveLogCategories()
-{
- std::vector<CLogCategoryActive> ret;
- for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
- // Omit the special cases.
- if (LogCategories[i].flag != BCLog::NONE && LogCategories[i].flag != BCLog::ALL) {
- CLogCategoryActive catActive;
- catActive.category = LogCategories[i].category;
- catActive.active = LogAcceptCategory(LogCategories[i].flag);
- ret.push_back(catActive);
- }
- }
- return ret;
-}
-
-/**
- * fStartedNewLine is a state variable held by the calling context that will
- * suppress printing of the timestamp when multiple calls are made that don't
- * end in a newline. Initialize it to true, and hold it, in the calling context.
- */
-static std::string LogTimestampStr(const std::string &str, std::atomic_bool *fStartedNewLine)
-{
- std::string strStamped;
-
- if (!fLogTimestamps)
- return str;
-
- if (*fStartedNewLine) {
- int64_t nTimeMicros = GetTimeMicros();
- strStamped = FormatISO8601DateTime(nTimeMicros/1000000);
- if (fLogTimeMicros) {
- strStamped.pop_back();
- strStamped += strprintf(".%06dZ", nTimeMicros%1000000);
- }
- int64_t mocktime = GetMockTime();
- if (mocktime) {
- strStamped += " (mocktime: " + FormatISO8601DateTime(mocktime) + ")";
- }
- strStamped += ' ' + str;
- } else
- strStamped = str;
-
- if (!str.empty() && str[str.size()-1] == '\n')
- *fStartedNewLine = true;
- else
- *fStartedNewLine = false;
-
- return strStamped;
-}
-
-int LogPrintStr(const std::string &str)
-{
- int ret = 0; // Returns total number of characters written
- static std::atomic_bool fStartedNewLine(true);
-
- std::string strTimestamped = LogTimestampStr(str, &fStartedNewLine);
-
- if (fPrintToConsole)
- {
- // print to console
- ret = fwrite(strTimestamped.data(), 1, strTimestamped.size(), stdout);
- fflush(stdout);
- }
- else if (fPrintToDebugLog)
- {
- std::call_once(debugPrintInitFlag, &DebugPrintInit);
- std::lock_guard<std::mutex> scoped_lock(*mutexDebugLog);
-
- // buffer if we haven't opened the log yet
- if (fileout == nullptr) {
- assert(vMsgsBeforeOpenLog);
- ret = strTimestamped.length();
- vMsgsBeforeOpenLog->push_back(strTimestamped);
- }
- else
- {
- // reopen the log file, if requested
- if (fReopenDebugLog) {
- fReopenDebugLog = false;
- fs::path pathDebug = GetDebugLogPath();
- if (fsbridge::freopen(pathDebug,"a",fileout) != nullptr)
- setbuf(fileout, nullptr); // unbuffered
- }
-
- ret = FileWriteStr(strTimestamped, fileout);
- }
- }
- return ret;
-}
-
/** 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
@@ -455,39 +218,204 @@ static bool InterpretBool(const std::string& strValue)
return (atoi(strValue) != 0);
}
+/** Internal helper functions for ArgsManager */
+class ArgsManagerHelper {
+public:
+ typedef std::map<std::string, std::vector<std::string>> MapArgs;
+
+ /** Determine whether to use config settings in the default section,
+ * See also comments around ArgsManager::ArgsManager() below. */
+ static inline bool UseDefaultSection(const ArgsManager& am, const std::string& arg)
+ {
+ return (am.m_network == CBaseChainParams::MAIN || am.m_network_only_args.count(arg) == 0);
+ }
+
+ /** Convert regular argument into the network-specific setting */
+ static inline std::string NetworkArg(const ArgsManager& am, const std::string& arg)
+ {
+ assert(arg.length() > 1 && arg[0] == '-');
+ return "-" + am.m_network + "." + arg.substr(1);
+ }
+
+ /** Find arguments in a map and add them to a vector */
+ static inline void AddArgs(std::vector<std::string>& res, const MapArgs& map_args, const std::string& arg)
+ {
+ auto it = map_args.find(arg);
+ if (it != map_args.end()) {
+ res.insert(res.end(), it->second.begin(), it->second.end());
+ }
+ }
+
+ /** Return true/false if an argument is set in a map, and also
+ * return the first (or last) of the possibly multiple values it has
+ */
+ static inline std::pair<bool,std::string> GetArgHelper(const MapArgs& map_args, const std::string& arg, bool getLast = false)
+ {
+ auto it = map_args.find(arg);
+
+ if (it == map_args.end() || it->second.empty()) {
+ return std::make_pair(false, std::string());
+ }
+
+ if (getLast) {
+ return std::make_pair(true, it->second.back());
+ } else {
+ return std::make_pair(true, it->second.front());
+ }
+ }
+
+ /* Get the string value of an argument, returning a pair of a boolean
+ * indicating the argument was found, and the value for the argument
+ * if it was found (or the empty string if not found).
+ */
+ static inline std::pair<bool,std::string> GetArg(const ArgsManager &am, const std::string& arg)
+ {
+ LOCK(am.cs_args);
+ std::pair<bool,std::string> found_result(false, std::string());
+
+ // We pass "true" to GetArgHelper in order to return the last
+ // argument value seen from the command line (so "bitcoind -foo=bar
+ // -foo=baz" gives GetArg(am,"foo")=={true,"baz"}
+ found_result = GetArgHelper(am.m_override_args, arg, true);
+ if (found_result.first) {
+ return found_result;
+ }
+
+ // But in contrast we return the first argument seen in a config file,
+ // so "foo=bar \n foo=baz" in the config file gives
+ // GetArg(am,"foo")={true,"bar"}
+ if (!am.m_network.empty()) {
+ found_result = GetArgHelper(am.m_config_args, NetworkArg(am, arg));
+ if (found_result.first) {
+ return found_result;
+ }
+ }
+
+ if (UseDefaultSection(am, arg)) {
+ found_result = GetArgHelper(am.m_config_args, arg);
+ if (found_result.first) {
+ return found_result;
+ }
+ }
+
+ return found_result;
+ }
+
+ /* Special test for -testnet and -regtest args, because we
+ * don't want to be confused by craziness like "[regtest] testnet=1"
+ */
+ static inline bool GetNetBoolArg(const ArgsManager &am, const std::string& net_arg)
+ {
+ std::pair<bool,std::string> found_result(false,std::string());
+ found_result = GetArgHelper(am.m_override_args, net_arg, true);
+ if (!found_result.first) {
+ found_result = GetArgHelper(am.m_config_args, net_arg, true);
+ if (!found_result.first) {
+ return false; // not set
+ }
+ }
+ return InterpretBool(found_result.second); // is set, so evaluate
+ }
+};
+
/**
* Interpret -nofoo as if the user supplied -foo=0.
*
- * This method also tracks when the -no form was supplied, and treats "-foo" as
- * a negated option when this happens. This can be later checked using the
+ * 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 true, indicating the caller should clear the args vector
+ * to indicate a negated option.
+ *
+ * If there was a double negative, it removes "no" from the key, sets the
+ * value to "1" and returns false.
+ *
+ * If there was no "no", it leaves key and value untouched and returns
+ * false.
+ *
+ * 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).
*/
-void ArgsManager::InterpretNegatedOption(std::string& key, std::string& val)
+static bool InterpretNegatedOption(std::string& key, std::string& val)
{
- if (key.substr(0, 3) == "-no") {
+ assert(key[0] == '-');
+
+ size_t option_index = key.find('.');
+ if (option_index == std::string::npos) {
+ option_index = 1;
+ } else {
+ ++option_index;
+ }
+ if (key.substr(option_index, 2) == "no") {
bool bool_val = InterpretBool(val);
+ key.erase(option_index, 2);
if (!bool_val ) {
// Double negatives like -nofoo=0 are supported (but discouraged)
LogPrintf("Warning: parsed potentially confusing double-negative %s=%s\n", key, val);
+ val = "1";
+ } else {
+ return true;
}
- key.erase(1, 2);
- m_negated_args.insert(key);
- val = bool_val ? "0" : "1";
- } else {
- // In an invocation like "bitcoind -nofoo -foo" we want to unmark -foo
- // as negated when we see the second option.
- m_negated_args.erase(key);
}
+ return false;
+}
+
+ArgsManager::ArgsManager() :
+ /* These options would cause cross-contamination if values for
+ * mainnet were used while running on regtest/testnet (or vice-versa).
+ * Setting them as section_only_args ensures that sharing a config file
+ * between mainnet and regtest/testnet won't cause problems due to these
+ * parameters by accident. */
+ m_network_only_args{
+ "-addnode", "-connect",
+ "-port", "-bind",
+ "-rpcport", "-rpcbind",
+ "-wallet",
+ }
+{
+ // nothing to do
+}
+
+void ArgsManager::WarnForSectionOnlyArgs()
+{
+ // if there's no section selected, don't worry
+ if (m_network.empty()) return;
+
+ // if it's okay to use the default section for this network, don't worry
+ if (m_network == CBaseChainParams::MAIN) return;
+
+ for (const auto& arg : m_network_only_args) {
+ std::pair<bool, std::string> found_result;
+
+ // if this option is overridden it's fine
+ found_result = ArgsManagerHelper::GetArgHelper(m_override_args, arg);
+ if (found_result.first) continue;
+
+ // if there's a network-specific value for this option, it's fine
+ found_result = ArgsManagerHelper::GetArgHelper(m_config_args, ArgsManagerHelper::NetworkArg(*this, arg));
+ if (found_result.first) continue;
+
+ // if there isn't a default value for this option, it's fine
+ found_result = ArgsManagerHelper::GetArgHelper(m_config_args, arg);
+ if (!found_result.first) continue;
+
+ // otherwise, issue a warning
+ LogPrintf("Warning: Config setting for %s only applied on %s network when in [%s] section.\n", arg, m_network, m_network);
+ }
+}
+
+void ArgsManager::SelectConfigNetwork(const std::string& network)
+{
+ m_network = network;
}
void ArgsManager::ParseParameters(int argc, const char* const argv[])
{
LOCK(cs_args);
- mapArgs.clear();
- mapMultiArgs.clear();
- m_negated_args.clear();
+ m_override_args.clear();
for (int i = 1; i < argc; i++) {
std::string key(argv[i]);
@@ -510,55 +438,79 @@ void ArgsManager::ParseParameters(int argc, const char* const argv[])
if (key.length() > 1 && key[1] == '-')
key.erase(0, 1);
- // Transform -nofoo to -foo=0
- InterpretNegatedOption(key, val);
-
- mapArgs[key] = val;
- mapMultiArgs[key].push_back(val);
+ // Check for -nofoo
+ if (InterpretNegatedOption(key, val)) {
+ m_override_args[key].clear();
+ } else {
+ m_override_args[key].push_back(val);
+ }
}
}
std::vector<std::string> ArgsManager::GetArgs(const std::string& strArg) const
{
+ std::vector<std::string> result = {};
+ if (IsArgNegated(strArg)) return result; // special case
+
LOCK(cs_args);
- auto it = mapMultiArgs.find(strArg);
- if (it != mapMultiArgs.end()) return it->second;
- return {};
+
+ ArgsManagerHelper::AddArgs(result, m_override_args, strArg);
+ if (!m_network.empty()) {
+ ArgsManagerHelper::AddArgs(result, m_config_args, ArgsManagerHelper::NetworkArg(*this, strArg));
+ }
+
+ if (ArgsManagerHelper::UseDefaultSection(*this, strArg)) {
+ ArgsManagerHelper::AddArgs(result, m_config_args, strArg);
+ }
+
+ return result;
}
bool ArgsManager::IsArgSet(const std::string& strArg) const
{
- LOCK(cs_args);
- return mapArgs.count(strArg);
+ if (IsArgNegated(strArg)) return true; // special case
+ return ArgsManagerHelper::GetArg(*this, strArg).first;
}
bool ArgsManager::IsArgNegated(const std::string& strArg) const
{
LOCK(cs_args);
- return m_negated_args.find(strArg) != m_negated_args.end();
+
+ const auto& ov = m_override_args.find(strArg);
+ if (ov != m_override_args.end()) return ov->second.empty();
+
+ if (!m_network.empty()) {
+ const auto& cfs = m_config_args.find(ArgsManagerHelper::NetworkArg(*this, strArg));
+ if (cfs != m_config_args.end()) return cfs->second.empty();
+ }
+
+ const auto& cf = m_config_args.find(strArg);
+ if (cf != m_config_args.end()) return cf->second.empty();
+
+ return false;
}
std::string ArgsManager::GetArg(const std::string& strArg, const std::string& strDefault) const
{
- LOCK(cs_args);
- auto it = mapArgs.find(strArg);
- if (it != mapArgs.end()) return it->second;
+ if (IsArgNegated(strArg)) return "0";
+ std::pair<bool,std::string> found_res = ArgsManagerHelper::GetArg(*this, strArg);
+ if (found_res.first) return found_res.second;
return strDefault;
}
int64_t ArgsManager::GetArg(const std::string& strArg, int64_t nDefault) const
{
- LOCK(cs_args);
- auto it = mapArgs.find(strArg);
- if (it != mapArgs.end()) return atoi64(it->second);
+ if (IsArgNegated(strArg)) return 0;
+ std::pair<bool,std::string> found_res = ArgsManagerHelper::GetArg(*this, strArg);
+ if (found_res.first) return atoi64(found_res.second);
return nDefault;
}
bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault) const
{
- LOCK(cs_args);
- auto it = mapArgs.find(strArg);
- if (it != mapArgs.end()) return InterpretBool(it->second);
+ if (IsArgNegated(strArg)) return false;
+ std::pair<bool,std::string> found_res = ArgsManagerHelper::GetArg(*this, strArg);
+ if (found_res.first) return InterpretBool(found_res.second);
return fDefault;
}
@@ -581,8 +533,7 @@ bool ArgsManager::SoftSetBoolArg(const std::string& strArg, bool fValue)
void ArgsManager::ForceSetArg(const std::string& strArg, const std::string& strValue)
{
LOCK(cs_args);
- mapArgs[strArg] = strValue;
- mapMultiArgs[strArg] = {strValue};
+ m_override_args[strArg] = {strValue};
}
bool HelpRequested(const ArgsManager& args)
@@ -745,18 +696,23 @@ void ArgsManager::ReadConfigStream(std::istream& stream)
for (boost::program_options::detail::config_file_iterator it(stream, setOptions), end; it != end; ++it)
{
- // Don't overwrite existing settings so command line settings override bitcoin.conf
std::string strKey = std::string("-") + it->string_key;
std::string strValue = it->value[0];
- InterpretNegatedOption(strKey, strValue);
- if (mapArgs.count(strKey) == 0)
- mapArgs[strKey] = strValue;
- mapMultiArgs[strKey].push_back(strValue);
+ if (InterpretNegatedOption(strKey, strValue)) {
+ m_config_args[strKey].clear();
+ } else {
+ m_config_args[strKey].push_back(strValue);
+ }
}
}
void ArgsManager::ReadConfigFile(const std::string& confPath)
{
+ {
+ LOCK(cs_args);
+ m_config_args.clear();
+ }
+
fs::ifstream stream(GetConfigFile(confPath));
// ok to not have a config file
@@ -773,8 +729,8 @@ void ArgsManager::ReadConfigFile(const std::string& confPath)
std::string ArgsManager::GetChainName() const
{
- bool fRegTest = GetBoolArg("-regtest", false);
- bool fTestNet = GetBoolArg("-testnet", false);
+ bool fRegTest = ArgsManagerHelper::GetNetBoolArg(*this, "-regtest");
+ bool fTestNet = ArgsManagerHelper::GetNetBoolArg(*this, "-testnet");
if (fTestNet && fRegTest)
throw std::runtime_error("Invalid combination of -regtest and -testnet.");
@@ -832,21 +788,37 @@ bool TryCreateDirectories(const fs::path& p)
return false;
}
-void FileCommit(FILE *file)
+bool FileCommit(FILE *file)
{
- fflush(file); // harmless if redundantly called
+ if (fflush(file) != 0) { // harmless if redundantly called
+ LogPrintf("%s: fflush failed: %d\n", __func__, errno);
+ return false;
+ }
#ifdef WIN32
HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
- FlushFileBuffers(hFile);
+ if (FlushFileBuffers(hFile) == 0) {
+ LogPrintf("%s: FlushFileBuffers failed: %d\n", __func__, GetLastError());
+ return false;
+ }
#else
#if defined(__linux__) || defined(__NetBSD__)
- fdatasync(fileno(file));
+ if (fdatasync(fileno(file)) != 0 && errno != EINVAL) { // Ignore EINVAL for filesystems that don't support sync
+ LogPrintf("%s: fdatasync failed: %d\n", __func__, errno);
+ return false;
+ }
#elif defined(__APPLE__) && defined(F_FULLFSYNC)
- fcntl(fileno(file), F_FULLFSYNC, 0);
+ if (fcntl(fileno(file), F_FULLFSYNC, 0) == -1) { // Manpage says "value other than -1" is returned on success
+ LogPrintf("%s: fcntl F_FULLFSYNC failed: %d\n", __func__, errno);
+ return false;
+ }
#else
- fsync(fileno(file));
+ 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) {
@@ -926,34 +898,6 @@ void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
#endif
}
-void ShrinkDebugFile()
-{
- // Amount of debug.log to save at end when shrinking (must fit in memory)
- constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000;
- // Scroll debug.log if it's getting too big
- fs::path pathLog = GetDebugLogPath();
- FILE* file = fsbridge::fopen(pathLog, "r");
- // If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE
- // trim it down by saving only the last RECENT_DEBUG_HISTORY_SIZE bytes
- if (file && fs::file_size(pathLog) > 11 * (RECENT_DEBUG_HISTORY_SIZE / 10))
- {
- // Restart the file with some of the end
- std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0);
- fseek(file, -((long)vch.size()), SEEK_END);
- int nBytes = fread(vch.data(), 1, vch.size(), file);
- fclose(file);
-
- file = fsbridge::fopen(pathLog, "w");
- if (file)
- {
- fwrite(vch.data(), 1, nBytes, file);
- fclose(file);
- }
- }
- else if (file != nullptr)
- fclose(file);
-}
-
#ifdef WIN32
fs::path GetSpecialFolderPath(int nFolder, bool fCreate)
{
diff --git a/src/util.h b/src/util.h
index 18d2076a05..ce94f396af 100644
--- a/src/util.h
+++ b/src/util.h
@@ -5,7 +5,7 @@
/**
* Server/client environment: argument handling, config file parsing,
- * logging, thread wrappers, startup time
+ * thread wrappers, startup time
*/
#ifndef BITCOIN_UTIL_H
#define BITCOIN_UTIL_H
@@ -16,6 +16,7 @@
#include <compat.h>
#include <fs.h>
+#include <logging.h>
#include <sync.h>
#include <tinyformat.h>
#include <utiltime.h>
@@ -24,6 +25,7 @@
#include <exception>
#include <map>
#include <memory>
+#include <set>
#include <stdint.h>
#include <string>
#include <unordered_set>
@@ -35,11 +37,6 @@
// Application startup time (used for uptime calculation)
int64_t GetStartupTime();
-static const bool DEFAULT_LOGTIMEMICROS = false;
-static const bool DEFAULT_LOGIPS = false;
-static const bool DEFAULT_LOGTIMESTAMPS = true;
-extern const char * const DEFAULT_DEBUGLOGFILE;
-
/** Signals for translation. */
class CTranslationInterface
{
@@ -48,20 +45,11 @@ public:
boost::signals2::signal<std::string (const char* psz)> Translate;
};
-extern bool fPrintToConsole;
-extern bool fPrintToDebugLog;
-
-extern bool fLogTimestamps;
-extern bool fLogTimeMicros;
-extern bool fLogIPs;
-extern std::atomic<bool> fReopenDebugLog;
extern CTranslationInterface translationInterface;
extern const char * const BITCOIN_CONF_FILENAME;
extern const char * const BITCOIN_PID_FILENAME;
-extern std::atomic<uint32_t> logCategories;
-
/**
* Translation function: Call Translate signal on UI interface, which returns a boost::optional result.
* If no translation slot is registered, nothing is returned, and simply return the input.
@@ -75,95 +63,6 @@ inline std::string _(const char* psz)
void SetupEnvironment();
bool SetupNetworking();
-struct CLogCategoryActive
-{
- 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),
- DB = (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),
- ALL = ~(uint32_t)0,
- };
-}
-/** Return true if log accepts specified category */
-static inline bool LogAcceptCategory(uint32_t category)
-{
- return (logCategories.load(std::memory_order_relaxed) & category) != 0;
-}
-
-/** Returns a string with the log categories. */
-std::string ListLogCategories();
-
-/** Returns a vector of the active log categories. */
-std::vector<CLogCategoryActive> ListActiveLogCategories();
-
-/** Return true if str parses as a log category and set the flags in f */
-bool GetLogCategory(uint32_t *f, const std::string *str);
-
-/** Send a string to the log output */
-int LogPrintStr(const std::string &str);
-
-/** Get format string from VA_ARGS for error reporting */
-template<typename... Args> std::string FormatStringFromLogArgs(const char *fmt, const Args&... args) { return fmt; }
-
-static inline void MarkUsed() {}
-template<typename T, typename... Args> static inline void MarkUsed(const T& t, const Args&... args)
-{
- (void)t;
- MarkUsed(args...);
-}
-
-// 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.
-
-#ifdef USE_COVERAGE
-#define LogPrintf(...) do { MarkUsed(__VA_ARGS__); } while(0)
-#define LogPrint(category, ...) do { MarkUsed(__VA_ARGS__); } while(0)
-#else
-#define LogPrintf(...) do { \
- if (fPrintToConsole || fPrintToDebugLog) { \
- std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \
- try { \
- _log_msg_ = tfm::format(__VA_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: " + FormatStringFromLogArgs(__VA_ARGS__); \
- } \
- LogPrintStr(_log_msg_); \
- } \
-} while(0)
-
-#define LogPrint(category, ...) do { \
- if (LogAcceptCategory((category))) { \
- LogPrintf(__VA_ARGS__); \
- } \
-} while(0)
-#endif
-
template<typename... Args>
bool error(const char* fmt, const Args&... args)
{
@@ -172,7 +71,7 @@ bool error(const char* fmt, const Args&... args)
}
void PrintExceptionContinue(const std::exception *pex, const char* pszThread);
-void FileCommit(FILE *file);
+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);
@@ -198,9 +97,6 @@ void CreatePidFile(const fs::path &path, pid_t pid);
#ifdef WIN32
fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
#endif
-fs::path GetDebugLogPath();
-bool OpenDebugLog();
-void ShrinkDebugFile();
void runCommand(const std::string& strCommand);
/**
@@ -225,18 +121,36 @@ inline bool IsSwitchChar(char c)
class ArgsManager
{
protected:
+ friend class ArgsManagerHelper;
+
mutable CCriticalSection cs_args;
- std::map<std::string, std::string> mapArgs;
- std::map<std::string, std::vector<std::string>> mapMultiArgs;
- std::unordered_set<std::string> m_negated_args;
+ std::map<std::string, std::vector<std::string>> m_override_args;
+ std::map<std::string, std::vector<std::string>> m_config_args;
+ std::string m_network;
+ std::set<std::string> m_network_only_args;
void ReadConfigStream(std::istream& stream);
public:
+ ArgsManager();
+
+ /**
+ * Select the network in use
+ */
+ void SelectConfigNetwork(const std::string& network);
+
void ParseParameters(int argc, const char*const argv[]);
void ReadConfigFile(const std::string& confPath);
/**
+ * 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.
+ */
+ void WarnForSectionOnlyArgs();
+
+ /**
* Return a vector of strings of the given argument
*
* @param strArg Argument to get (e.g. "-foo")
@@ -315,11 +229,6 @@ public:
* @return CBaseChainParams::MAIN by default; raises runtime error if an invalid combination is given.
*/
std::string GetChainName() const;
-
-private:
-
- // Munge -nofoo into -foo=0 and track the value as negated.
- void InterpretNegatedOption(std::string &key, std::string &val);
};
extern ArgsManager gArgs;
diff --git a/src/validation.cpp b/src/validation.cpp
index 8eec66286a..ab44e73d7c 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -142,7 +142,7 @@ private:
* ahead and mark descendants of invalid blocks as FAILED_CHILD at that time,
* instead of putting things in this set.
*/
- std::set<CBlockIndex*> g_failed_blocks;
+ std::set<CBlockIndex*> m_failed_blocks;
public:
CChain chainActive;
@@ -363,7 +363,7 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool
CBlockIndex* tip = chainActive.Tip();
assert(tip != nullptr);
-
+
CBlockIndex index;
index.pprev = tip;
// CheckSequenceLocks() uses chainActive.Height()+1 to evaluate
@@ -1295,7 +1295,7 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
void CChainState::InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) {
if (!state.CorruptionPossible()) {
pindex->nStatus |= BLOCK_FAILED_VALID;
- g_failed_blocks.insert(pindex);
+ m_failed_blocks.insert(pindex);
setDirtyBlockIndex.insert(pindex);
setBlockIndexCandidates.erase(pindex);
InvalidChainFound(pindex);
@@ -1624,22 +1624,27 @@ void static FlushBlockFile(bool fFinalize = false)
LOCK(cs_LastBlockFile);
CDiskBlockPos posOld(nLastBlockFile, 0);
+ bool status = true;
FILE *fileOld = OpenBlockFile(posOld);
if (fileOld) {
if (fFinalize)
- TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nSize);
- FileCommit(fileOld);
+ status &= TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nSize);
+ status &= FileCommit(fileOld);
fclose(fileOld);
}
fileOld = OpenUndoFile(posOld);
if (fileOld) {
if (fFinalize)
- TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nUndoSize);
- FileCommit(fileOld);
+ status &= TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nUndoSize);
+ status &= FileCommit(fileOld);
fclose(fileOld);
}
+
+ if (!status) {
+ AbortNode("Flushing block file to disk failed. This is likely the result of an I/O error.");
+ }
}
static bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize);
@@ -1735,16 +1740,38 @@ public:
// Protected by cs_main
static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS];
+// 0.13.0 was shipped with a segwit deployment defined for testnet, but not for
+// mainnet. We no longer need to support disabling the segwit deployment
+// except for testing purposes, due to limitations of the functional test
+// environment. See test/functional/p2p-segwit.py.
+static bool IsScriptWitnessEnabled(const Consensus::Params& params)
+{
+ return params.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout != 0;
+}
+
static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& consensusparams) {
AssertLockHeld(cs_main);
unsigned int flags = SCRIPT_VERIFY_NONE;
- // Start enforcing P2SH (BIP16)
- if (pindex->nHeight >= consensusparams.BIP16Height) {
+ // BIP16 didn't become active until Apr 1 2012 (on mainnet, and
+ // retroactively applied to testnet)
+ // However, only one historical block violated the P2SH rules (on both
+ // mainnet and testnet), so for simplicity, always leave P2SH
+ // on except for the one violating block.
+ if (consensusparams.BIP16Exception.IsNull() || // no bip16 exception on this chain
+ pindex->phashBlock == nullptr || // this is a new candidate block, eg from TestBlockValidity()
+ *pindex->phashBlock != consensusparams.BIP16Exception) // this block isn't the historical exception
+ {
flags |= SCRIPT_VERIFY_P2SH;
}
+ // Enforce WITNESS rules whenever P2SH is in effect (and the segwit
+ // deployment is defined).
+ if (flags & SCRIPT_VERIFY_P2SH && IsScriptWitnessEnabled(consensusparams)) {
+ flags |= SCRIPT_VERIFY_WITNESS;
+ }
+
// Start enforcing the DERSIG (BIP66) rule
if (pindex->nHeight >= consensusparams.BIP66Height) {
flags |= SCRIPT_VERIFY_DERSIG;
@@ -1760,9 +1787,7 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consens
flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY;
}
- // Start enforcing WITNESS rules using versionbits logic.
- if (IsWitnessEnabled(pindex->pprev, consensusparams)) {
- flags |= SCRIPT_VERIFY_WITNESS;
+ if (IsNullDummyEnabled(pindex->pprev, consensusparams)) {
flags |= SCRIPT_VERIFY_NULLDUMMY;
}
@@ -2190,14 +2215,18 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
void FlushStateToDisk() {
CValidationState state;
const CChainParams& chainparams = Params();
- FlushStateToDisk(chainparams, state, FlushStateMode::ALWAYS);
+ if (!FlushStateToDisk(chainparams, state, FlushStateMode::ALWAYS)) {
+ LogPrintf("%s: failed to flush state (%s)\n", __func__, FormatStateMessage(state));
+ }
}
void PruneAndFlush() {
CValidationState state;
fCheckForPruning = true;
const CChainParams& chainparams = Params();
- FlushStateToDisk(chainparams, state, FlushStateMode::NONE);
+ if (!FlushStateToDisk(chainparams, state, FlushStateMode::NONE)) {
+ LogPrintf("%s: failed to flush state (%s)\n", __func__, FormatStateMessage(state));
+ }
}
static void DoWarning(const std::string& strWarning)
@@ -2691,18 +2720,17 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
assert(trace.pblock && trace.pindex);
GetMainSignals().BlockConnected(trace.pblock, trace.pindex, trace.conflictedTxs);
}
- }
- // When we reach this point, we switched to a new tip (stored in pindexNewTip).
-
- // Notifications/callbacks that can run without cs_main
- // Notify external listeners about the new tip.
- GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);
+ // Notify external listeners about the new tip.
+ // Enqueue while holding cs_main to ensure that UpdatedBlockTip is called in the order in which blocks are connected
+ GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);
- // Always notify the UI if a new block tip was connected
- if (pindexFork != pindexNewTip) {
- uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip);
+ // Always notify the UI if a new block tip was connected
+ if (pindexFork != pindexNewTip) {
+ uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip);
+ }
}
+ // When we reach this point, we switched to a new tip (stored in pindexNewTip).
if (nStopAtHeight && pindexNewTip && pindexNewTip->nHeight >= nStopAtHeight) StartShutdown();
@@ -2797,7 +2825,7 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c
pindex->nStatus |= BLOCK_FAILED_VALID;
setDirtyBlockIndex.insert(pindex);
setBlockIndexCandidates.erase(pindex);
- g_failed_blocks.insert(pindex);
+ m_failed_blocks.insert(pindex);
// DisconnectTip will add transactions to disconnectpool; try to add these
// back to the mempool.
@@ -2843,7 +2871,7 @@ bool CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
// Reset invalid block marker if it was pointing to one of those.
pindexBestInvalid = nullptr;
}
- g_failed_blocks.erase(it->second);
+ m_failed_blocks.erase(it->second);
}
it++;
}
@@ -3113,6 +3141,12 @@ bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& pa
return (VersionBitsState(pindexPrev, params, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == ThresholdState::ACTIVE);
}
+bool IsNullDummyEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params)
+{
+ LOCK(cs_main);
+ return (VersionBitsState(pindexPrev, params, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == ThresholdState::ACTIVE);
+}
+
// Compute at which vout of the block's coinbase transaction the witness
// commitment occurs, or -1 if not found.
static int GetWitnessCommitmentIndex(const CBlock& block)
@@ -3340,7 +3374,7 @@ bool CChainState::AcceptBlockHeader(const CBlockHeader& block, CValidationState&
// has been found invalid (g_failed_blocks), then mark pindexPrev and any blocks
// between them as failed.
if (!pindexPrev->IsValid(BLOCK_VALID_SCRIPTS)) {
- for (const CBlockIndex* failedit : g_failed_blocks) {
+ for (const CBlockIndex* failedit : m_failed_blocks) {
if (pindexPrev->GetAncestor(failedit->nHeight) == failedit) {
assert(failedit->nStatus & BLOCK_FAILED_VALID);
CBlockIndex* invalid_walk = pindexPrev;
@@ -3506,7 +3540,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
}
if (!ret) {
GetMainSignals().BlockChecked(*pblock, state);
- return error("%s: AcceptBlock FAILED (%s)", __func__, state.GetDebugMessage());
+ return error("%s: AcceptBlock FAILED (%s)", __func__, FormatStateMessage(state));
}
}
@@ -3514,7 +3548,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
CValidationState state; // Only used to report errors, not invalidity - ignore it
if (!g_chainstate.ActivateBestChain(state, chainparams, pblock))
- return error("%s: ActivateBestChain failed", __func__);
+ return error("%s: ActivateBestChain failed (%s)", __func__, FormatStateMessage(state));
return true;
}
@@ -3632,7 +3666,9 @@ void PruneBlockFilesManual(int nManualPruneHeight)
{
CValidationState state;
const CChainParams& chainparams = Params();
- FlushStateToDisk(chainparams, state, FlushStateMode::NONE, nManualPruneHeight);
+ if (!FlushStateToDisk(chainparams, state, FlushStateMode::NONE, nManualPruneHeight)) {
+ LogPrintf("%s: failed to flush state (%s)\n", __func__, FormatStateMessage(state));
+ }
}
/**
@@ -3886,6 +3922,7 @@ bool LoadChainTip(const CChainParams& chainparams)
LogPrintf("%s: Connecting genesis block...\n", __func__);
CValidationState state;
if (!ActivateBestChain(state, chainparams)) {
+ LogPrintf("%s: failed to activate chain (%s)\n", __func__, FormatStateMessage(state));
return false;
}
}
@@ -4000,7 +4037,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus()))
return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
if (!g_chainstate.ConnectBlock(block, state, pindex, coins, chainparams))
- return error("VerifyDB(): *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
+ return error("VerifyDB(): *** found unconnectable block at %d, hash=%s (%s)", pindex->nHeight, pindex->GetBlockHash().ToString(), FormatStateMessage(state));
}
}
@@ -4108,6 +4145,9 @@ bool CChainState::RewindBlockIndex(const CChainParams& params)
int nHeight = 1;
while (nHeight <= chainActive.Height()) {
+ // Although SCRIPT_VERIFY_WITNESS is now generally enforced on all
+ // blocks in ConnectBlock, we don't need to go back and
+ // re-download/re-verify blocks from before segwit actually activated.
if (IsWitnessEnabled(chainActive[nHeight - 1], params.GetConsensus()) && !(chainActive[nHeight]->nStatus & BLOCK_OPT_WITNESS)) {
break;
}
@@ -4127,11 +4167,13 @@ bool CChainState::RewindBlockIndex(const CChainParams& params)
break;
}
if (!DisconnectTip(state, params, nullptr)) {
- return error("RewindBlockIndex: unable to disconnect block at height %i", pindex->nHeight);
+ return error("RewindBlockIndex: unable to disconnect block at height %i (%s)", pindex->nHeight, FormatStateMessage(state));
}
// Occasionally flush state to disk.
- if (!FlushStateToDisk(params, state, FlushStateMode::PERIODIC))
+ if (!FlushStateToDisk(params, state, FlushStateMode::PERIODIC)) {
+ LogPrintf("RewindBlockIndex: unable to flush state to disk (%s)\n", FormatStateMessage(state));
return false;
+ }
}
// Reduce validity flag and have-data flags.
@@ -4197,6 +4239,7 @@ bool RewindBlockIndex(const CChainParams& params) {
// it'll get called a bunch real soon.
CValidationState state;
if (!FlushStateToDisk(params, state, FlushStateMode::ALWAYS)) {
+ LogPrintf("RewindBlockIndex: unable to flush state to disk (%s)\n", FormatStateMessage(state));
return false;
}
}
@@ -4206,7 +4249,7 @@ bool RewindBlockIndex(const CChainParams& params) {
void CChainState::UnloadBlockIndex() {
nBlockSequenceId = 1;
- g_failed_blocks.clear();
+ m_failed_blocks.clear();
setBlockIndexCandidates.clear();
}
@@ -4283,7 +4326,7 @@ bool CChainState::LoadGenesisBlock(const CChainParams& chainparams)
CBlockIndex *pindex = AddToBlockIndex(block);
CValidationState state;
if (!ReceivedBlockTransactions(block, state, pindex, blockPos, chainparams.GetConsensus()))
- return error("%s: genesis block not accepted", __func__);
+ return error("%s: genesis block not accepted (%s)", __func__, FormatStateMessage(state));
} catch (const std::runtime_error& e) {
return error("%s: failed to write genesis block: %s", __func__, e.what());
}
@@ -4748,7 +4791,8 @@ bool DumpMempool(void)
}
file << mapDeltas;
- FileCommit(file.Get());
+ if (!FileCommit(file.Get()))
+ throw std::runtime_error("FileCommit failed");
file.fclose();
RenameOver(GetDataDir() / "mempool.dat.new", GetDataDir() / "mempool.dat");
int64_t last = GetTimeMicros();
diff --git a/src/validation.h b/src/validation.h
index 3668484696..b415a85053 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -411,6 +411,9 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
/** Check whether witness commitments are required for block. */
bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params);
+/** Check whether NULLDUMMY (BIP 147) has activated. */
+bool IsNullDummyEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params);
+
/** When there are blocks in the active chain with missing data, rewind the chainstate and remove them from the block index */
bool RewindBlockIndex(const CChainParams& params);
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index 928df4fa65..746263f113 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -139,6 +139,10 @@ void CMainSignals::MempoolEntryRemoved(CTransactionRef ptx, MemPoolRemovalReason
}
void CMainSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
+ // Dependencies exist that require UpdatedBlockTip events to be delivered in the order in which
+ // the chain actually updates. One way to ensure this is for the caller to invoke this signal
+ // in the same critical section where the chain is updated
+
m_internals->m_schedulerClient.AddToProcessQueue([pindexNew, pindexFork, fInitialDownload, this] {
m_internals->UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload);
});
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index b6f4a0e1e1..8b834e4626 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -18,39 +18,38 @@ class WalletInit : public WalletInitInterface {
public:
//! Return the wallets help message.
- std::string GetHelpString(bool showDebug) override;
+ std::string GetHelpString(bool showDebug) const override;
//! Wallets parameter interaction
- bool ParameterInteraction() override;
+ bool ParameterInteraction() const override;
//! Register wallet RPCs.
- void RegisterRPC(CRPCTable &tableRPC) override;
+ void RegisterRPC(CRPCTable &tableRPC) const override;
//! Responsible for reading and validating the -wallet arguments and verifying the wallet database.
// This function will perform salvage on the wallet if requested, as long as only one wallet is
// being loaded (WalletParameterInteraction forbids -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet).
- bool Verify() override;
+ bool Verify() const override;
//! Load wallet databases.
- bool Open() override;
+ bool Open() const override;
//! Complete startup of wallets.
- void Start(CScheduler& scheduler) override;
+ void Start(CScheduler& scheduler) const override;
//! Flush all wallets in preparation for shutdown.
- void Flush() override;
+ void Flush() const override;
//! Stop all wallets. Wallets will be flushed first.
- void Stop() override;
+ void Stop() const override;
//! Close all wallets.
- void Close() override;
+ void Close() const override;
};
-static WalletInit g_wallet_init;
-WalletInitInterface* const g_wallet_init_interface = &g_wallet_init;
+const WalletInitInterface& g_wallet_init_interface = WalletInit();
-std::string WalletInit::GetHelpString(bool showDebug)
+std::string WalletInit::GetHelpString(bool showDebug) const
{
std::string strUsage = HelpMessageGroup(_("Wallet options:"));
strUsage += HelpMessageOpt("-addresstype", strprintf("What type of addresses to use (\"legacy\", \"p2sh-segwit\", or \"bech32\", default: \"%s\")", FormatOutputType(DEFAULT_ADDRESS_TYPE)));
@@ -92,7 +91,7 @@ std::string WalletInit::GetHelpString(bool showDebug)
return strUsage;
}
-bool WalletInit::ParameterInteraction()
+bool WalletInit::ParameterInteraction() const
{
if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
for (const std::string& wallet : gArgs.GetArgs("-wallet")) {
@@ -220,7 +219,7 @@ bool WalletInit::ParameterInteraction()
return true;
}
-void WalletInit::RegisterRPC(CRPCTable &t)
+void WalletInit::RegisterRPC(CRPCTable &t) const
{
if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
return;
@@ -229,7 +228,7 @@ void WalletInit::RegisterRPC(CRPCTable &t)
RegisterWalletRPCCommands(t);
}
-bool WalletInit::Verify()
+bool WalletInit::Verify() const
{
if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
return true;
@@ -304,7 +303,7 @@ bool WalletInit::Verify()
return true;
}
-bool WalletInit::Open()
+bool WalletInit::Open() const
{
if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
LogPrintf("Wallet disabled!\n");
@@ -316,37 +315,37 @@ bool WalletInit::Open()
if (!pwallet) {
return false;
}
- vpwallets.push_back(pwallet);
+ AddWallet(pwallet);
}
return true;
}
-void WalletInit::Start(CScheduler& scheduler)
+void WalletInit::Start(CScheduler& scheduler) const
{
- for (CWalletRef pwallet : vpwallets) {
+ for (CWallet* pwallet : GetWallets()) {
pwallet->postInitProcess(scheduler);
}
}
-void WalletInit::Flush()
+void WalletInit::Flush() const
{
- for (CWalletRef pwallet : vpwallets) {
+ for (CWallet* pwallet : GetWallets()) {
pwallet->Flush(false);
}
}
-void WalletInit::Stop()
+void WalletInit::Stop() const
{
- for (CWalletRef pwallet : vpwallets) {
+ for (CWallet* pwallet : GetWallets()) {
pwallet->Flush(true);
}
}
-void WalletInit::Close()
+void WalletInit::Close() const
{
- for (CWalletRef pwallet : vpwallets) {
+ for (CWallet* pwallet : GetWallets()) {
+ RemoveWallet(pwallet);
delete pwallet;
}
- vpwallets.clear();
}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 56bdc0695c..9b5fb0b062 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -46,14 +46,13 @@ CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
if (request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
// wallet endpoint was used
std::string requestedWallet = urlDecode(request.URI.substr(WALLET_ENDPOINT_BASE.size()));
- for (CWalletRef pwallet : ::vpwallets) {
- if (pwallet->GetName() == requestedWallet) {
- return pwallet;
- }
- }
- throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
+ CWallet* pwallet = GetWallet(requestedWallet);
+ if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
+ return pwallet;
}
- return ::vpwallets.size() == 1 || (request.fHelp && ::vpwallets.size() > 0) ? ::vpwallets[0] : nullptr;
+
+ std::vector<CWallet*> wallets = GetWallets();
+ return wallets.size() == 1 || (request.fHelp && wallets.size() > 0) ? wallets[0] : nullptr;
}
std::string HelpRequiringPassphrase(CWallet * const pwallet)
@@ -67,7 +66,7 @@ bool EnsureWalletIsAvailable(CWallet * const pwallet, bool avoidException)
{
if (pwallet) return true;
if (avoidException) return false;
- if (::vpwallets.empty()) {
+ if (!HasWallets()) {
// Note: It isn't currently possible to trigger this error because
// wallet RPC methods aren't registered unless a wallet is loaded. But
// this error is being kept as a precaution, because it's possible in
@@ -2862,8 +2861,7 @@ UniValue listwallets(const JSONRPCRequest& request)
UniValue obj(UniValue::VARR);
- for (CWalletRef pwallet : vpwallets) {
-
+ for (CWallet* pwallet : GetWallets()) {
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 14c5ad7214..99c963a348 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -74,7 +74,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
// after.
{
CWallet wallet("dummy", WalletDatabase::CreateDummy());
- vpwallets.insert(vpwallets.begin(), &wallet);
+ AddWallet(&wallet);
UniValue keys;
keys.setArray();
UniValue key;
@@ -105,7 +105,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
"downloading and rescanning the relevant blocks (see -reindex and -rescan "
"options).\"}},{\"success\":true}]",
0, oldTip->GetBlockTimeMax(), TIMESTAMP_WINDOW));
- vpwallets.erase(vpwallets.begin());
+ RemoveWallet(&wallet);
}
}
@@ -119,14 +119,14 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
// will pick up both blocks, not just the first.
const int64_t BLOCK_TIME = chainActive.Tip()->GetBlockTimeMax() + 5;
SetMockTime(BLOCK_TIME);
- coinbaseTxns.emplace_back(*CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
- coinbaseTxns.emplace_back(*CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
+ m_coinbase_txns.emplace_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
+ m_coinbase_txns.emplace_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
// Set key birthday to block time increased by the timestamp window, so
// rescan will start at the block time.
const int64_t KEY_TIME = BLOCK_TIME + TIMESTAMP_WINDOW;
SetMockTime(KEY_TIME);
- coinbaseTxns.emplace_back(*CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
+ m_coinbase_txns.emplace_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
LOCK(cs_main);
@@ -140,8 +140,9 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
JSONRPCRequest request;
request.params.setArray();
request.params.push_back((pathTemp / "wallet.backup").string());
- vpwallets.insert(vpwallets.begin(), &wallet);
+ AddWallet(&wallet);
::dumpwallet(request);
+ RemoveWallet(&wallet);
}
// Call importwallet RPC and verify all blocks with timestamps >= BLOCK_TIME
@@ -152,21 +153,21 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
JSONRPCRequest request;
request.params.setArray();
request.params.push_back((pathTemp / "wallet.backup").string());
- vpwallets[0] = &wallet;
+ AddWallet(&wallet);
::importwallet(request);
+ RemoveWallet(&wallet);
LOCK(wallet.cs_wallet);
BOOST_CHECK_EQUAL(wallet.mapWallet.size(), 3U);
- BOOST_CHECK_EQUAL(coinbaseTxns.size(), 103U);
- for (size_t i = 0; i < coinbaseTxns.size(); ++i) {
- bool found = wallet.GetWalletTx(coinbaseTxns[i].GetHash());
+ BOOST_CHECK_EQUAL(m_coinbase_txns.size(), 103U);
+ for (size_t i = 0; i < m_coinbase_txns.size(); ++i) {
+ bool found = wallet.GetWalletTx(m_coinbase_txns[i]->GetHash());
bool expected = i >= 100;
BOOST_CHECK_EQUAL(found, expected);
}
}
SetMockTime(0);
- vpwallets.erase(vpwallets.begin());
}
// Check that GetImmatureCredit() returns a newly calculated value instead of
@@ -178,7 +179,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
{
CWallet wallet("dummy", WalletDatabase::CreateDummy());
- CWalletTx wtx(&wallet, MakeTransactionRef(coinbaseTxns.back()));
+ CWalletTx wtx(&wallet, m_coinbase_txns.back());
LOCK2(cs_main, wallet.cs_wallet);
wtx.hashBlock = chainActive.Tip()->GetBlockHash();
wtx.nIndex = 0;
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 45c85a7912..8c392434fc 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -28,12 +28,50 @@
#include <utilmoneystr.h>
#include <wallet/fees.h>
+#include <algorithm>
#include <assert.h>
#include <future>
#include <boost/algorithm/string/replace.hpp>
-std::vector<CWalletRef> vpwallets;
+static std::vector<CWallet*> vpwallets;
+
+bool AddWallet(CWallet* wallet)
+{
+ assert(wallet);
+ std::vector<CWallet*>::const_iterator i = std::find(vpwallets.begin(), vpwallets.end(), wallet);
+ if (i != vpwallets.end()) return false;
+ vpwallets.push_back(wallet);
+ return true;
+}
+
+bool RemoveWallet(CWallet* wallet)
+{
+ assert(wallet);
+ std::vector<CWallet*>::iterator i = std::find(vpwallets.begin(), vpwallets.end(), wallet);
+ if (i == vpwallets.end()) return false;
+ vpwallets.erase(i);
+ return true;
+}
+
+bool HasWallets()
+{
+ return !vpwallets.empty();
+}
+
+std::vector<CWallet*> GetWallets()
+{
+ return vpwallets;
+}
+
+CWallet* GetWallet(const std::string& name)
+{
+ for (CWallet* wallet : vpwallets) {
+ if (wallet->GetName() == name) return wallet;
+ }
+ return nullptr;
+}
+
/** Transaction fee set by the user */
CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET;
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index b85f374a06..dd165de825 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -32,8 +32,11 @@
#include <utility>
#include <vector>
-typedef CWallet* CWalletRef;
-extern std::vector<CWalletRef> vpwallets;
+bool AddWallet(CWallet* wallet);
+bool RemoveWallet(CWallet* wallet);
+bool HasWallets();
+std::vector<CWallet*> GetWallets();
+CWallet* GetWallet(const std::string& name);
/**
* Settings
@@ -268,7 +271,7 @@ public:
//Get the marginal bytes of spending the specified output
int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* pwallet);
-/**
+/**
* A transaction with a bunch of additional info that only the owner cares about.
* It includes any unrecorded transactions needed to link it back to the block chain.
*/
@@ -653,7 +656,7 @@ struct CoinEligibilityFilter
};
class WalletRescanReserver; //forward declarations for ScanForWalletTransactions/RescanFromTime
-/**
+/**
* A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
* and provides the ability to create new transactions.
*/
@@ -903,7 +906,7 @@ public:
void GetKeyBirthTimes(std::map<CTxDestination, int64_t> &mapKeyBirth) const;
unsigned int ComputeTimeSmart(const CWalletTx& wtx) const;
- /**
+ /**
* Increment the next transaction order id
* @return next transaction order id
*/
@@ -1032,7 +1035,7 @@ public:
}
void GetScriptForMining(std::shared_ptr<CReserveScript> &script);
-
+
unsigned int GetKeyPoolSize()
{
AssertLockHeld(cs_wallet); // set{Ex,In}ternalKeyPool
@@ -1057,7 +1060,7 @@ public:
//! Flush wallet (bitdb flush)
void Flush(bool shutdown=false);
- /**
+ /**
* Address book entry changed.
* @note called with lock cs_wallet held.
*/
@@ -1066,7 +1069,7 @@ public:
const std::string &purpose,
ChangeType status)> NotifyAddressBookChanged;
- /**
+ /**
* Wallet transaction added, removed or updated.
* @note called with lock cs_wallet held.
*/
@@ -1113,7 +1116,7 @@ public:
/* Generates a new HD master key (will not be activated) */
CPubKey GenerateNewHDMasterKey();
-
+
/* Set the current HD master key (will reset the chain child index counters)
Sets the master key's version based on the current wallet version (so the
caller must ensure the current wallet version is correct before calling
@@ -1184,7 +1187,7 @@ public:
};
-/**
+/**
* DEPRECATED Account information.
* Stored in wallet with key "acc"+string account name.
*/
@@ -1230,10 +1233,10 @@ std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key);
class WalletRescanReserver
{
private:
- CWalletRef m_wallet;
+ CWallet* m_wallet;
bool m_could_reserve;
public:
- explicit WalletRescanReserver(CWalletRef w) : m_wallet(w), m_could_reserve(false) {}
+ explicit WalletRescanReserver(CWallet* w) : m_wallet(w), m_could_reserve(false) {}
bool reserve()
{
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index bcc7cf877d..5b275131af 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -756,7 +756,7 @@ void MaybeCompactWalletDB()
return;
}
- for (CWalletRef pwallet : vpwallets) {
+ for (CWallet* pwallet : GetWallets()) {
WalletDatabase& dbh = pwallet->GetDBHandle();
unsigned int nUpdateCounter = dbh.nUpdateCounter;
diff --git a/src/walletinitinterface.h b/src/walletinitinterface.h
index c7eee37ce5..5bfde6faaf 100644
--- a/src/walletinitinterface.h
+++ b/src/walletinitinterface.h
@@ -13,23 +13,23 @@ class CRPCTable;
class WalletInitInterface {
public:
/** Get wallet help string */
- virtual std::string GetHelpString(bool showDebug) = 0;
+ virtual std::string GetHelpString(bool showDebug) const = 0;
/** Check wallet parameter interaction */
- virtual bool ParameterInteraction() = 0;
+ virtual bool ParameterInteraction() const = 0;
/** Register wallet RPC*/
- virtual void RegisterRPC(CRPCTable &) = 0;
+ virtual void RegisterRPC(CRPCTable &) const = 0;
/** Verify wallets */
- virtual bool Verify() = 0;
+ virtual bool Verify() const = 0;
/** Open wallets*/
- virtual bool Open() = 0;
+ virtual bool Open() const = 0;
/** Start wallets*/
- virtual void Start(CScheduler& scheduler) = 0;
+ virtual void Start(CScheduler& scheduler) const = 0;
/** Flush Wallets*/
- virtual void Flush() = 0;
+ virtual void Flush() const = 0;
/** Stop Wallets*/
- virtual void Stop() = 0;
+ virtual void Stop() const = 0;
/** Close wallets */
- virtual void Close() = 0;
+ virtual void Close() const = 0;
virtual ~WalletInitInterface() {}
};
diff --git a/test/functional/feature_bip68_sequence.py b/test/functional/feature_bip68_sequence.py
index e5db9e18c7..eee38ce648 100755
--- a/test/functional/feature_bip68_sequence.py
+++ b/test/functional/feature_bip68_sequence.py
@@ -129,7 +129,7 @@ class BIP68Test(BitcoinTestFramework):
# Track whether any sequence locks used should fail
should_pass = True
-
+
# Track whether this transaction was built with sequence locks
using_sequence_locks = False
@@ -343,7 +343,7 @@ class BIP68Test(BitcoinTestFramework):
tx2.rehash()
self.nodes[0].sendrawtransaction(ToHex(tx2))
-
+
# Now make an invalid spend of tx2 according to BIP68
sequence_value = 100 # 100 block relative locktime
diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py
index 181c7f3369..38b76239e5 100755
--- a/test/functional/feature_block.py
+++ b/test/functional/feature_block.py
@@ -1306,7 +1306,13 @@ class FullBlockTest(BitcoinTestFramework):
self.nodes[0].disconnect_p2ps()
self.nodes[0].add_p2p_connection(P2PDataStore())
network_thread_start()
- self.nodes[0].p2p.wait_for_verack()
+ # We need to wait for the initial getheaders from the peer before we
+ # start populating our blockstore. If we don't, then we may run ahead
+ # to the next subtest before we receive the getheaders. We'd then send
+ # an INV for the next block and receive two getheaders - one for the
+ # IBD and one for the INV. We'd respond to both and could get
+ # unexpectedly disconnected if the DoS score for that error is 50.
+ self.nodes[0].p2p.wait_for_getheaders(timeout=5)
def sync_blocks(self, blocks, success=True, reject_code=None, reject_reason=None, request_block=True, reconnect=False, timeout=60):
"""Sends blocks to test node. Syncs and verifies that tip has advanced to most recent block.
diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py
index a1d22191af..e9924451d1 100755
--- a/test/functional/feature_config_args.py
+++ b/test/functional/feature_config_args.py
@@ -29,8 +29,13 @@ class ConfArgsTest(BitcoinTestFramework):
# Check that using non-existent datadir in conf file fails
conf_file = os.path.join(default_data_dir, "bitcoin.conf")
- with open(conf_file, 'a', encoding='utf8') as f:
+
+ # datadir needs to be set before [regtest] section
+ conf_file_contents = open(conf_file, encoding='utf8').read()
+ with open(conf_file, 'w', encoding='utf8') as f:
f.write("datadir=" + new_data_dir + "\n")
+ f.write(conf_file_contents)
+
self.nodes[0].assert_start_raises_init_error(['-conf=' + conf_file], 'Error reading configuration file: specified data directory "' + new_data_dir + '" does not exist.')
# Create the directory and ensure the config file now works
diff --git a/test/functional/feature_logging.py b/test/functional/feature_logging.py
index 3c7aecf10a..166f8f8694 100755
--- a/test/functional/feature_logging.py
+++ b/test/functional/feature_logging.py
@@ -15,13 +15,17 @@ class LoggingTest(BitcoinTestFramework):
self.num_nodes = 1
self.setup_clean_chain = True
+ def relative_log_path(self, name):
+ return os.path.join(self.nodes[0].datadir, "regtest", name)
+
def run_test(self):
# test default log file name
- assert os.path.isfile(os.path.join(self.nodes[0].datadir, "regtest", "debug.log"))
+ default_log_path = self.relative_log_path("debug.log")
+ assert os.path.isfile(default_log_path)
# test alternative log file name in datadir
self.restart_node(0, ["-debuglogfile=foo.log"])
- assert os.path.isfile(os.path.join(self.nodes[0].datadir, "regtest", "foo.log"))
+ assert os.path.isfile(self.relative_log_path("foo.log"))
# test alternative log file name outside datadir
tempname = os.path.join(self.options.tmpdir, "foo.log")
@@ -29,7 +33,7 @@ class LoggingTest(BitcoinTestFramework):
assert os.path.isfile(tempname)
# check that invalid log (relative) will cause error
- invdir = os.path.join(self.nodes[0].datadir, "regtest", "foo")
+ invdir = self.relative_log_path("foo")
invalidname = os.path.join("foo", "foo.log")
self.stop_node(0)
exp_stderr = "Error: Could not open debug log file \S+$"
@@ -55,6 +59,17 @@ class LoggingTest(BitcoinTestFramework):
self.start_node(0, ["-debuglogfile=%s" % (invalidname)])
assert os.path.isfile(os.path.join(invdir, "foo.log"))
+ # check that -nodebuglogfile disables logging
+ self.stop_node(0)
+ os.unlink(default_log_path)
+ assert not os.path.isfile(default_log_path)
+ self.start_node(0, ["-nodebuglogfile"])
+ assert not os.path.isfile(default_log_path)
+
+ # just sanity check no crash here
+ self.stop_node(0)
+ self.start_node(0, ["-debuglogfile=%s" % os.devnull])
+
if __name__ == '__main__':
LoggingTest().main()
diff --git a/test/functional/feature_maxuploadtarget.py b/test/functional/feature_maxuploadtarget.py
index ce6ec76c61..072ba6c7c7 100755
--- a/test/functional/feature_maxuploadtarget.py
+++ b/test/functional/feature_maxuploadtarget.py
@@ -30,7 +30,7 @@ class TestP2PConn(P2PInterface):
self.block_receive_map[message.block.sha256] += 1
class MaxUploadTest(BitcoinTestFramework):
-
+
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
diff --git a/test/functional/feature_proxy.py b/test/functional/feature_proxy.py
index 2eb1be47a5..60859de7a5 100755
--- a/test/functional/feature_proxy.py
+++ b/test/functional/feature_proxy.py
@@ -182,7 +182,7 @@ class ProxyTest(BitcoinTestFramework):
assert_equal(n1['onion']['proxy'], '%s:%i' % (self.conf2.addr))
assert_equal(n1['onion']['proxy_randomize_credentials'], False)
assert_equal(n1['onion']['reachable'], True)
-
+
n2 = networks_dict(self.nodes[2].getnetworkinfo())
for net in ['ipv4','ipv6','onion']:
assert_equal(n2[net]['proxy'], '%s:%i' % (self.conf2.addr))
diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py
index fa1732c4c5..e835b9d777 100755
--- a/test/functional/feature_segwit.py
+++ b/test/functional/feature_segwit.py
@@ -150,19 +150,11 @@ class SegWitTest(BitcoinTestFramework):
self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][0], True) #block 426
self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][0], True) #block 427
- # TODO: An old node would see these txs without witnesses and be able to mine them
-
- self.log.info("Verify unsigned bare witness txs in versionbits-setting blocks are valid before the fork")
- self.success_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][1], False) #block 428
- self.success_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][1], False) #block 429
-
self.log.info("Verify unsigned p2sh witness txs without a redeem script are invalid")
self.fail_accept(self.nodes[2], "mandatory-script-verify-flag", p2sh_ids[NODE_2][WIT_V0][1], False)
self.fail_accept(self.nodes[2], "mandatory-script-verify-flag", p2sh_ids[NODE_2][WIT_V1][1], False)
- self.log.info("Verify unsigned p2sh witness txs with a redeem script in versionbits-settings blocks are valid before the fork")
- self.success_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][1], False, witness_script(False, self.pubkey[2])) #block 430
- self.success_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][1], False, witness_script(True, self.pubkey[2])) #block 431
+ self.nodes[2].generate(4) # blocks 428-431
self.log.info("Verify previous witness txs skipped for mining can now be mined")
assert_equal(len(self.nodes[2].getrawmempool()), 4)
diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py
index 2ee33aa869..a48939d2e0 100755
--- a/test/functional/interface_rest.py
+++ b/test/functional/interface_rest.py
@@ -186,10 +186,10 @@ class RESTTest (BitcoinTestFramework):
self.test_rest_request("/getutxos/checkmempool", http_method='POST', req_type=ReqType.JSON, status=400, ret_type=RetType.OBJ)
# Test limits
- long_uri = '/'.join(["{}-{}".format(txid, n) for n in range(20)])
+ long_uri = '/'.join(["{}-{}".format(txid, n_) for n_ in range(20)])
self.test_rest_request("/getutxos/checkmempool/{}".format(long_uri), http_method='POST', status=400, ret_type=RetType.OBJ)
- long_uri = '/'.join(['{}-{}'.format(txid, n) for n in range(15)])
+ long_uri = '/'.join(['{}-{}'.format(txid, n_) for n_ in range(15)])
self.test_rest_request("/getutxos/checkmempool/{}".format(long_uri), http_method='POST', status=200)
self.nodes[0].generate(1) # generate block to not affect upcoming tests
diff --git a/test/functional/p2p_mempool.py b/test/functional/p2p_mempool.py
index 485a8af3d0..e54843b26f 100755
--- a/test/functional/p2p_mempool.py
+++ b/test/functional/p2p_mempool.py
@@ -30,6 +30,6 @@ class P2PMempoolTests(BitcoinTestFramework):
#mininode must be disconnected at this point
assert_equal(len(self.nodes[0].getpeerinfo()), 0)
-
+
if __name__ == '__main__':
P2PMempoolTests().main()
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index 5546bf6b29..4fecd4ffee 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -10,6 +10,7 @@ from test_framework.util import *
from test_framework.script import *
from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment, get_witness_script, WITNESS_COMMITMENT_HEADER
from test_framework.key import CECKey, CPubKey
+import math
import time
import random
from binascii import hexlify
@@ -47,7 +48,7 @@ def test_transaction_acceptance(rpc, p2p, tx, with_witness, accepted, reason=Non
with mininode_lock:
assert_equal(p2p.last_message["reject"].reason, reason)
-def test_witness_block(rpc, p2p, block, accepted, with_witness=True):
+def test_witness_block(rpc, p2p, block, accepted, with_witness=True, reason=None):
"""Send a block to the node and check that it's accepted
- Submit the block over the p2p interface
@@ -58,6 +59,10 @@ def test_witness_block(rpc, p2p, block, accepted, with_witness=True):
p2p.send_message(msg_block(block))
p2p.sync_with_ping()
assert_equal(rpc.getbestblockhash() == block.hash, accepted)
+ if (reason != None and not accepted):
+ # Check the rejection reason as well.
+ with mininode_lock:
+ assert_equal(p2p.last_message["reject"].reason, reason)
class TestP2PConn(P2PInterface):
def __init__(self):
@@ -271,6 +276,80 @@ class SegWitTest(BitcoinTestFramework):
self.utxo.pop(0)
self.utxo.append(UTXO(tx4.sha256, 0, tx4.vout[0].nValue))
+ # ~6 months after segwit activation, the SCRIPT_VERIFY_WITNESS flag was
+ # backdated so that it applies to all blocks, going back to the genesis
+ # block.
+ #
+ # Consequently, version 0 witness outputs are never spendable without
+ # witness, and so can't be spent before segwit activation (the point at which
+ # blocks are permitted to contain witnesses).
+ def test_v0_outputs_arent_spendable(self):
+ self.log.info("Testing that v0 witness program outputs aren't spendable before activation")
+
+ assert len(self.utxo), "self.utxo is empty"
+
+ # Create two outputs, a p2wsh and p2sh-p2wsh
+ witness_program = CScript([OP_TRUE])
+ witness_hash = sha256(witness_program)
+ scriptPubKey = CScript([OP_0, witness_hash])
+
+ p2sh_pubkey = hash160(scriptPubKey)
+ p2sh_scriptPubKey = CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])
+
+ value = self.utxo[0].nValue // 3
+
+ tx = CTransaction()
+ tx.vin = [CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b'')]
+ tx.vout = [CTxOut(value, scriptPubKey), CTxOut(value, p2sh_scriptPubKey)]
+ tx.vout.append(CTxOut(value, CScript([OP_TRUE])))
+ tx.rehash()
+ txid = tx.sha256
+
+ # Add it to a block
+ block = self.build_next_block()
+ self.update_witness_block_with_transactions(block, [tx])
+ # Verify that segwit isn't activated. A block serialized with witness
+ # should be rejected prior to activation.
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=True, reason = b'unexpected-witness')
+ # Now send the block without witness. It should be accepted
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=True, with_witness=False)
+
+ # Now try to spend the outputs. This should fail since SCRIPT_VERIFY_WITNESS is always enabled.
+ p2wsh_tx = CTransaction()
+ p2wsh_tx.vin = [CTxIn(COutPoint(txid, 0), b'')]
+ p2wsh_tx.vout = [CTxOut(value, CScript([OP_TRUE]))]
+ p2wsh_tx.wit.vtxinwit.append(CTxInWitness())
+ p2wsh_tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
+ p2wsh_tx.rehash()
+
+ p2sh_p2wsh_tx = CTransaction()
+ p2sh_p2wsh_tx.vin = [CTxIn(COutPoint(txid, 1), CScript([scriptPubKey]))]
+ p2sh_p2wsh_tx.vout = [CTxOut(value, CScript([OP_TRUE]))]
+ p2sh_p2wsh_tx.wit.vtxinwit.append(CTxInWitness())
+ p2sh_p2wsh_tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
+ p2sh_p2wsh_tx.rehash()
+
+ for tx in [p2wsh_tx, p2sh_p2wsh_tx]:
+
+ block = self.build_next_block()
+ self.update_witness_block_with_transactions(block, [tx])
+
+ # When the block is serialized with a witness, the block will be rejected because witness
+ # data isn't allowed in blocks that don't commit to witness data.
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=True, reason=b'unexpected-witness')
+
+ # When the block is serialized without witness, validation fails because the transaction is
+ # invalid (transactions are always validated with SCRIPT_VERIFY_WITNESS so a segwit v0 transaction
+ # without a witness is invalid).
+ # Note: The reject reason for this failure could be
+ # 'block-validation-failed' (if script check threads > 1) or
+ # 'non-mandatory-script-verify-flag (Witness program was passed an
+ # empty witness)' (otherwise).
+ # TODO: support multiple acceptable reject reasons.
+ test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=False)
+
+ self.utxo.pop(0)
+ self.utxo.append(UTXO(txid, 2, value))
# Mine enough blocks for segwit's vb state to be 'started'.
def advance_to_segwit_started(self):
@@ -450,7 +529,7 @@ class SegWitTest(BitcoinTestFramework):
block = self.build_next_block()
assert(len(self.utxo) > 0)
-
+
# Create a P2WSH transaction.
# The witness program will be a bunch of OP_2DROP's, followed by OP_TRUE.
# This should give us plenty of room to tweak the spending tx's
@@ -562,7 +641,7 @@ class SegWitTest(BitcoinTestFramework):
self.log.info("Testing extra witness data in tx")
assert(len(self.utxo) > 0)
-
+
block = self.build_next_block()
witness_program = CScript([OP_DROP, OP_TRUE])
@@ -730,7 +809,7 @@ class SegWitTest(BitcoinTestFramework):
witness_program = CScript([OP_DROP, OP_TRUE])
witness_hash = sha256(witness_program)
scriptPubKey = CScript([OP_0, witness_hash])
-
+
# Create a transaction that splits our utxo into many outputs
tx = CTransaction()
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
@@ -930,8 +1009,10 @@ class SegWitTest(BitcoinTestFramework):
raw_tx = self.nodes[0].getrawtransaction(tx3.hash, 1)
assert_equal(int(raw_tx["hash"], 16), tx3.calc_sha256(True))
assert_equal(raw_tx["size"], len(tx3.serialize_with_witness()))
- vsize = (len(tx3.serialize_with_witness()) + 3*len(tx3.serialize_without_witness()) + 3) / 4
+ weight = len(tx3.serialize_with_witness()) + 3*len(tx3.serialize_without_witness())
+ vsize = math.ceil(weight / 4)
assert_equal(raw_tx["vsize"], vsize)
+ assert_equal(raw_tx["weight"], weight)
assert_equal(len(raw_tx["vin"][0]["txinwitness"]), 1)
assert_equal(raw_tx["vin"][0]["txinwitness"][0], hexlify(witness_program).decode('ascii'))
assert(vsize != raw_tx["size"])
@@ -1476,9 +1557,10 @@ class SegWitTest(BitcoinTestFramework):
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [spend_tx])
- # If we're before activation, then sending this without witnesses
- # should be valid. If we're after activation, then sending this with
- # witnesses should be valid.
+ # If we're after activation, then sending this with witnesses should be valid.
+ # This no longer works before activation, because SCRIPT_VERIFY_WITNESS
+ # is always set.
+ # TODO: rewrite this test to make clear that it only works after activation.
if segwit_activated:
test_witness_block(self.nodes[0].rpc, self.test_node, block, accepted=True)
else:
@@ -1897,6 +1979,7 @@ class SegWitTest(BitcoinTestFramework):
self.test_witness_services() # Verifies NODE_WITNESS
self.test_non_witness_transaction() # non-witness tx's are accepted
self.test_unnecessary_witness_before_segwit_activation()
+ self.test_v0_outputs_arent_spendable()
self.test_block_relay(segwit_activated=False)
# Advance to segwit being 'started'
@@ -1914,7 +1997,6 @@ class SegWitTest(BitcoinTestFramework):
self.test_unnecessary_witness_before_segwit_activation()
self.test_witness_tx_relay_before_segwit_activation()
self.test_block_relay(segwit_activated=False)
- self.test_p2sh_witness(segwit_activated=False)
self.test_standardness_v0(segwit_activated=False)
sync_blocks(self.nodes)
diff --git a/test/functional/rpc_bind.py b/test/functional/rpc_bind.py
index 5b50520d3f..343e162058 100755
--- a/test/functional/rpc_bind.py
+++ b/test/functional/rpc_bind.py
@@ -4,7 +4,6 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test running bitcoind with the -rpcbind and -rpcallowip options."""
-import socket
import sys
from test_framework.test_framework import BitcoinTestFramework, SkipTest
@@ -20,6 +19,11 @@ class RPCBindTest(BitcoinTestFramework):
def setup_network(self):
self.add_nodes(self.num_nodes, None)
+ def add_options(self, parser):
+ parser.add_option("--ipv4", action='store_true', dest="run_ipv4", help="Run ipv4 tests only", default=False)
+ parser.add_option("--ipv6", action='store_true', dest="run_ipv6", help="Run ipv6 tests only", default=False)
+ parser.add_option("--nonloopback", action='store_true', dest="run_nonloopback", help="Run non-loopback tests only", default=False)
+
def run_bind_test(self, allow_ips, connect_to, addresses, expected):
'''
Start a node with requested rpcallowip and rpcbind parameters,
@@ -54,55 +58,69 @@ class RPCBindTest(BitcoinTestFramework):
def run_test(self):
# due to OS-specific network stats queries, this test works only on Linux
+ if sum([self.options.run_ipv4, self.options.run_ipv6, self.options.run_nonloopback]) > 1:
+ raise AssertionError("Only one of --ipv4, --ipv6 and --nonloopback can be set")
+
+ self.log.info("Check for linux")
if not sys.platform.startswith('linux'):
- raise SkipTest("This test can only be run on Linux.")
- # find the first non-loopback interface for testing
- non_loopback_ip = None
+ raise SkipTest("This test can only be run on linux.")
+
+ self.log.info("Check for ipv6")
+ have_ipv6 = test_ipv6_local()
+ if not have_ipv6 and not self.options.run_ipv4:
+ raise SkipTest("This test requires ipv6 support.")
+
+ self.log.info("Check for non-loopback interface")
+ self.non_loopback_ip = None
for name,ip in all_interfaces():
if ip != '127.0.0.1':
- non_loopback_ip = ip
+ self.non_loopback_ip = ip
break
- if non_loopback_ip is None:
- raise SkipTest("This test requires at least one non-loopback IPv4 interface.")
- try:
- s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
- s.connect(("::1",1))
- s.close
- except OSError:
- raise SkipTest("This test requires IPv6 support.")
-
- self.log.info("Using interface %s for testing" % non_loopback_ip)
-
- defaultport = rpc_port(0)
-
- # check default without rpcallowip (IPv4 and IPv6 localhost)
- self.run_bind_test(None, '127.0.0.1', [],
- [('127.0.0.1', defaultport), ('::1', defaultport)])
- # check default with rpcallowip (IPv6 any)
- self.run_bind_test(['127.0.0.1'], '127.0.0.1', [],
- [('::0', defaultport)])
- # check only IPv4 localhost (explicit)
- self.run_bind_test(['127.0.0.1'], '127.0.0.1', ['127.0.0.1'],
- [('127.0.0.1', defaultport)])
- # check only IPv4 localhost (explicit) with alternative port
- self.run_bind_test(['127.0.0.1'], '127.0.0.1:32171', ['127.0.0.1:32171'],
- [('127.0.0.1', 32171)])
- # check only IPv4 localhost (explicit) with multiple alternative ports on same host
- self.run_bind_test(['127.0.0.1'], '127.0.0.1:32171', ['127.0.0.1:32171', '127.0.0.1:32172'],
- [('127.0.0.1', 32171), ('127.0.0.1', 32172)])
- # check only IPv6 localhost (explicit)
- self.run_bind_test(['[::1]'], '[::1]', ['[::1]'],
- [('::1', defaultport)])
- # check both IPv4 and IPv6 localhost (explicit)
- self.run_bind_test(['127.0.0.1'], '127.0.0.1', ['127.0.0.1', '[::1]'],
- [('127.0.0.1', defaultport), ('::1', defaultport)])
+ if self.non_loopback_ip is None and self.options.run_nonloopback:
+ raise SkipTest("This test requires a non-loopback ip address.")
+
+ self.defaultport = rpc_port(0)
+
+ if not self.options.run_nonloopback:
+ self._run_loopback_tests()
+ if not self.options.run_ipv4 and not self.options.run_ipv6:
+ self._run_nonloopback_tests()
+
+ def _run_loopback_tests(self):
+ if self.options.run_ipv4:
+ # check only IPv4 localhost (explicit)
+ self.run_bind_test(['127.0.0.1'], '127.0.0.1', ['127.0.0.1'],
+ [('127.0.0.1', self.defaultport)])
+ # check only IPv4 localhost (explicit) with alternative port
+ self.run_bind_test(['127.0.0.1'], '127.0.0.1:32171', ['127.0.0.1:32171'],
+ [('127.0.0.1', 32171)])
+ # check only IPv4 localhost (explicit) with multiple alternative ports on same host
+ self.run_bind_test(['127.0.0.1'], '127.0.0.1:32171', ['127.0.0.1:32171', '127.0.0.1:32172'],
+ [('127.0.0.1', 32171), ('127.0.0.1', 32172)])
+ else:
+ # check default without rpcallowip (IPv4 and IPv6 localhost)
+ self.run_bind_test(None, '127.0.0.1', [],
+ [('127.0.0.1', self.defaultport), ('::1', self.defaultport)])
+ # check default with rpcallowip (IPv6 any)
+ self.run_bind_test(['127.0.0.1'], '127.0.0.1', [],
+ [('::0', self.defaultport)])
+ # check only IPv6 localhost (explicit)
+ self.run_bind_test(['[::1]'], '[::1]', ['[::1]'],
+ [('::1', self.defaultport)])
+ # check both IPv4 and IPv6 localhost (explicit)
+ self.run_bind_test(['127.0.0.1'], '127.0.0.1', ['127.0.0.1', '[::1]'],
+ [('127.0.0.1', self.defaultport), ('::1', self.defaultport)])
+
+ def _run_nonloopback_tests(self):
+ self.log.info("Using interface %s for testing" % self.non_loopback_ip)
+
# check only non-loopback interface
- self.run_bind_test([non_loopback_ip], non_loopback_ip, [non_loopback_ip],
- [(non_loopback_ip, defaultport)])
+ self.run_bind_test([self.non_loopback_ip], self.non_loopback_ip, [self.non_loopback_ip],
+ [(self.non_loopback_ip, self.defaultport)])
# Check that with invalid rpcallowip, we are denied
- self.run_allowip_test([non_loopback_ip], non_loopback_ip, defaultport)
- assert_raises_rpc_error(-342, "non-JSON HTTP response with '403 Forbidden' from server", self.run_allowip_test, ['1.1.1.1'], non_loopback_ip, defaultport)
+ self.run_allowip_test([self.non_loopback_ip], self.non_loopback_ip, self.defaultport)
+ assert_raises_rpc_error(-342, "non-JSON HTTP response with '403 Forbidden' from server", self.run_allowip_test, ['1.1.1.1'], self.non_loopback_ip, self.defaultport)
if __name__ == '__main__':
RPCBindTest().main()
diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py
index 43982cd09a..5c2b1815e5 100644
--- a/test/functional/test_framework/blocktools.py
+++ b/test/functional/test_framework/blocktools.py
@@ -10,7 +10,24 @@ from .address import (
script_to_p2sh_p2wsh,
script_to_p2wsh,
)
-from .mininode import *
+from .messages import (
+ CBlock,
+ COIN,
+ COutPoint,
+ CTransaction,
+ CTxIn,
+ CTxInWitness,
+ CTxOut,
+ FromHex,
+ ToHex,
+ bytes_to_hex_str,
+ hash256,
+ hex_str_to_bytes,
+ ser_string,
+ ser_uint256,
+ sha256,
+ uint256_from_str,
+)
from .script import (
CScript,
OP_0,
@@ -23,34 +40,34 @@ from .script import (
)
from .util import assert_equal
-# Create a block (with regtest difficulty)
-def create_block(hashprev, coinbase, nTime=None):
+# From BIP141
+WITNESS_COMMITMENT_HEADER = b"\xaa\x21\xa9\xed"
+
+def create_block(hashprev, coinbase, ntime=None):
+ """Create a block (with regtest difficulty)."""
block = CBlock()
- if nTime is None:
+ if ntime is None:
import time
- block.nTime = int(time.time()+600)
+ block.nTime = int(time.time() + 600)
else:
- block.nTime = nTime
+ block.nTime = ntime
block.hashPrevBlock = hashprev
- block.nBits = 0x207fffff # Will break after a difficulty adjustment...
+ block.nBits = 0x207fffff # difficulty retargeting is disabled in REGTEST chainparams
block.vtx.append(coinbase)
block.hashMerkleRoot = block.calc_merkle_root()
block.calc_sha256()
return block
-# From BIP141
-WITNESS_COMMITMENT_HEADER = b"\xaa\x21\xa9\xed"
-
-
def get_witness_script(witness_root, witness_nonce):
- witness_commitment = uint256_from_str(hash256(ser_uint256(witness_root)+ser_uint256(witness_nonce)))
+ witness_commitment = uint256_from_str(hash256(ser_uint256(witness_root) + ser_uint256(witness_nonce)))
output_data = WITNESS_COMMITMENT_HEADER + ser_uint256(witness_commitment)
return CScript([OP_RETURN, output_data])
-
-# According to BIP141, blocks with witness rules active must commit to the
-# hash of all in-block transactions including witness.
def add_witness_commitment(block, nonce=0):
+ """Add a witness commitment to the block's coinbase transaction.
+
+ According to BIP141, blocks with witness rules active must commit to the
+ hash of all in-block transactions including witness."""
# First calculate the merkle root of the block's
# transactions, with witnesses.
witness_nonce = nonce
@@ -65,7 +82,6 @@ def add_witness_commitment(block, nonce=0):
block.hashMerkleRoot = block.calc_merkle_root()
block.rehash()
-
def serialize_script_num(value):
r = bytearray(0)
if value == 0:
@@ -81,55 +97,59 @@ def serialize_script_num(value):
r[-1] |= 0x80
return r
-# Create a coinbase transaction, assuming no miner fees.
-# If pubkey is passed in, the coinbase output will be a P2PK output;
-# otherwise an anyone-can-spend output.
-def create_coinbase(height, pubkey = None):
+def create_coinbase(height, pubkey=None):
+ """Create a coinbase transaction, assuming no miner fees.
+
+ If pubkey is passed in, the coinbase output will be a P2PK output;
+ otherwise an anyone-can-spend output."""
coinbase = CTransaction()
- coinbase.vin.append(CTxIn(COutPoint(0, 0xffffffff),
- ser_string(serialize_script_num(height)), 0xffffffff))
+ coinbase.vin.append(CTxIn(COutPoint(0, 0xffffffff),
+ ser_string(serialize_script_num(height)), 0xffffffff))
coinbaseoutput = CTxOut()
coinbaseoutput.nValue = 50 * COIN
- halvings = int(height/150) # regtest
+ halvings = int(height / 150) # regtest
coinbaseoutput.nValue >>= halvings
- if (pubkey != None):
+ if (pubkey is not None):
coinbaseoutput.scriptPubKey = CScript([pubkey, OP_CHECKSIG])
else:
coinbaseoutput.scriptPubKey = CScript([OP_TRUE])
- coinbase.vout = [ coinbaseoutput ]
+ coinbase.vout = [coinbaseoutput]
coinbase.calc_sha256()
return coinbase
-# Create a transaction.
-# If the scriptPubKey is not specified, make it anyone-can-spend.
-def create_transaction(prevtx, n, sig, value, scriptPubKey=CScript()):
+def create_transaction(prevtx, n, sig, value, script_pub_key=CScript()):
+ """Create a transaction.
+
+ If the script_pub_key is not specified, make it anyone-can-spend."""
tx = CTransaction()
assert(n < len(prevtx.vout))
tx.vin.append(CTxIn(COutPoint(prevtx.sha256, n), sig, 0xffffffff))
- tx.vout.append(CTxOut(value, scriptPubKey))
+ tx.vout.append(CTxOut(value, script_pub_key))
tx.calc_sha256()
return tx
-def get_legacy_sigopcount_block(block, fAccurate=True):
+def get_legacy_sigopcount_block(block, accurate=True):
count = 0
for tx in block.vtx:
- count += get_legacy_sigopcount_tx(tx, fAccurate)
+ count += get_legacy_sigopcount_tx(tx, accurate)
return count
-def get_legacy_sigopcount_tx(tx, fAccurate=True):
+def get_legacy_sigopcount_tx(tx, accurate=True):
count = 0
for i in tx.vout:
- count += i.scriptPubKey.GetSigOpCount(fAccurate)
+ count += i.scriptPubKey.GetSigOpCount(accurate)
for j in tx.vin:
# scriptSig might be of type bytes, so convert to CScript for the moment
- count += CScript(j.scriptSig).GetSigOpCount(fAccurate)
+ count += CScript(j.scriptSig).GetSigOpCount(accurate)
return count
-# Create a scriptPubKey corresponding to either a P2WPKH output for the
-# given pubkey, or a P2WSH output of a 1-of-1 multisig for the given
-# pubkey. Returns the hex encoding of the scriptPubKey.
def witness_script(use_p2wsh, pubkey):
- if (use_p2wsh == False):
+ """Create a scriptPubKey for a pay-to-wtiness TxOut.
+
+ This is either a P2WPKH output for the given pubkey, or a P2WSH output of a
+ 1-of-1 multisig for the given pubkey. Returns the hex encoding of the
+ scriptPubKey."""
+ if not use_p2wsh:
# P2WPKH instead
pubkeyhash = hash160(hex_str_to_bytes(pubkey))
pkscript = CScript([OP_0, pubkeyhash])
@@ -140,9 +160,10 @@ def witness_script(use_p2wsh, pubkey):
pkscript = CScript([OP_0, scripthash])
return bytes_to_hex_str(pkscript)
-# Return a transaction (in hex) that spends the given utxo to a segwit output,
-# optionally wrapping the segwit output using P2SH.
def create_witness_tx(node, use_p2wsh, utxo, pubkey, encode_p2sh, amount):
+ """Return a transaction (in hex) that spends the given utxo to a segwit output.
+
+ Optionally wrap the segwit output using P2SH."""
if use_p2wsh:
program = CScript([OP_1, hex_str_to_bytes(pubkey), OP_1, OP_CHECKMULTISIG])
addr = script_to_p2sh_p2wsh(program) if encode_p2sh else script_to_p2wsh(program)
@@ -152,12 +173,13 @@ def create_witness_tx(node, use_p2wsh, utxo, pubkey, encode_p2sh, amount):
assert_equal(node.getaddressinfo(addr)['scriptPubKey'], witness_script(use_p2wsh, pubkey))
return node.createrawtransaction([utxo], {addr: amount})
-# Create a transaction spending a given utxo to a segwit output corresponding
-# to the given pubkey: use_p2wsh determines whether to use P2WPKH or P2WSH;
-# encode_p2sh determines whether to wrap in P2SH.
-# sign=True will have the given node sign the transaction.
-# insert_redeem_script will be added to the scriptSig, if given.
def send_to_witness(use_p2wsh, node, utxo, pubkey, encode_p2sh, amount, sign=True, insert_redeem_script=""):
+ """Create a transaction spending a given utxo to a segwit output.
+
+ The output corresponds to the given pubkey: use_p2wsh determines whether to
+ use P2WPKH or P2WSH; encode_p2sh determines whether to wrap in P2SH.
+ sign=True will have the given node sign the transaction.
+ insert_redeem_script will be added to the scriptSig, if given."""
tx_to_witness = create_witness_tx(node, use_p2wsh, utxo, pubkey, encode_p2sh, amount)
if (sign):
signed = node.signrawtransactionwithwallet(tx_to_witness)
diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py
index f0082bd2a3..44650d7584 100644
--- a/test/functional/test_framework/script.py
+++ b/test/functional/test_framework/script.py
@@ -379,7 +379,7 @@ class CScriptNum():
r.append(0x80 if neg else 0)
elif neg:
r[-1] |= 0x80
- return bytes(bytes([len(r)]) + r)
+ return bytes([len(r)]) + r
class CScript(bytes):
@@ -404,9 +404,9 @@ class CScript(bytes):
other = CScriptNum.encode(other)
elif isinstance(other, int):
if 0 <= other <= 16:
- other = bytes(bytes([CScriptOp.encode_op_n(other)]))
+ other = bytes([CScriptOp.encode_op_n(other)])
elif other == -1:
- other = bytes(bytes([OP_1NEGATE]))
+ other = bytes([OP_1NEGATE])
else:
other = CScriptOp.encode_op_pushdata(bn2vch(other))
elif isinstance(other, (bytes, bytearray)):
diff --git a/test/functional/test_framework/socks5.py b/test/functional/test_framework/socks5.py
index 4721809a3b..581de0ed5d 100644
--- a/test/functional/test_framework/socks5.py
+++ b/test/functional/test_framework/socks5.py
@@ -4,12 +4,14 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Dummy Socks5 server for testing."""
-import socket, threading, queue
+import socket
+import threading
+import queue
import logging
logger = logging.getLogger("TestFramework.socks5")
-### Protocol constants
+# Protocol constants
class Command:
CONNECT = 0x01
@@ -18,7 +20,7 @@ class AddressType:
DOMAINNAME = 0x03
IPV6 = 0x04
-### Utility functions
+# Utility functions
def recvall(s, n):
"""Receive n bytes from a socket, or fail."""
rv = bytearray()
@@ -30,7 +32,7 @@ def recvall(s, n):
n -= len(d)
return rv
-### Implementation classes
+# Implementation classes
class Socks5Configuration():
"""Proxy configuration."""
def __init__(self):
@@ -141,7 +143,7 @@ class Socks5Server():
thread = threading.Thread(None, conn.handle)
thread.daemon = True
thread.start()
-
+
def start(self):
assert(not self.running)
self.running = True
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index 0f0d031f35..04d1de8d91 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -78,7 +78,17 @@ class TestNode():
# For those callers that need more flexibility, they can just set the args property directly.
# Note that common args are set in the config file (see initialize_datadir)
self.extra_args = extra_args
- self.args = [self.binary, "-datadir=" + self.datadir, "-logtimemicros", "-debug", "-debugexclude=libevent", "-debugexclude=leveldb", "-mocktime=" + str(mocktime), "-uacomment=testnode%d" % i]
+ self.args = [
+ self.binary,
+ "-datadir=" + self.datadir,
+ "-logtimemicros",
+ "-debug",
+ "-debugexclude=libevent",
+ "-debugexclude=leveldb",
+ "-mocktime=" + str(mocktime),
+ "-uacomment=testnode%d" % i,
+ "-noprinttoconsole"
+ ]
self.cli = TestNodeCLI(os.getenv("BITCOINCLI", "bitcoin-cli"), self.datadir)
self.use_cli = use_cli
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index f22322fbbc..4ec3175cd6 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -294,6 +294,7 @@ def initialize_datadir(dirname, n):
os.makedirs(datadir)
with open(os.path.join(datadir, "bitcoin.conf"), 'w', encoding='utf8') as f:
f.write("regtest=1\n")
+ f.write("[regtest]\n")
f.write("port=" + str(p2p_port(n)) + "\n")
f.write("rpcport=" + str(rpc_port(n)) + "\n")
f.write("server=1\n")
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 518c16b5f1..da43280ced 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -120,6 +120,9 @@ BASE_SCRIPTS = [
'feature_nulldummy.py',
'mempool_accept.py',
'wallet_import_rescan.py',
+ 'rpc_bind.py --ipv4',
+ 'rpc_bind.py --ipv6',
+ 'rpc_bind.py --nonloopback',
'mining_basic.py',
'wallet_bumpfee.py',
'rpc_named_arguments.py',
@@ -160,7 +163,6 @@ EXTENDED_SCRIPTS = [
'p2p_timeouts.py',
# vv Tests less than 60s vv
'p2p_feefilter.py',
- 'rpc_bind.py',
# vv Tests less than 30s vv
'feature_assumevalid.py',
'example_test.py',
diff --git a/test/functional/wallet_importprunedfunds.py b/test/functional/wallet_importprunedfunds.py
index 4d349db23f..5f5bfcf683 100755
--- a/test/functional/wallet_importprunedfunds.py
+++ b/test/functional/wallet_importprunedfunds.py
@@ -16,7 +16,7 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
self.nodes[0].generate(101)
self.sync_all()
-
+
# address
address1 = self.nodes[0].getnewaddress()
# pubkey
diff --git a/test/functional/wallet_keypool.py b/test/functional/wallet_keypool.py
index 9825e4d894..505014e48f 100755
--- a/test/functional/wallet_keypool.py
+++ b/test/functional/wallet_keypool.py
@@ -17,7 +17,7 @@ class KeyPoolTest(BitcoinTestFramework):
addr_before_encrypting_data = nodes[0].getaddressinfo(addr_before_encrypting)
wallet_info_old = nodes[0].getwalletinfo()
assert(addr_before_encrypting_data['hdmasterkeyid'] == wallet_info_old['hdmasterkeyid'])
-
+
# Encrypt wallet and wait to terminate
nodes[0].node_encrypt_wallet('test')
# Restart node 0
diff --git a/test/functional/wallet_txn_clone.py b/test/functional/wallet_txn_clone.py
index d742ec4618..7577c4a0d2 100755
--- a/test/functional/wallet_txn_clone.py
+++ b/test/functional/wallet_txn_clone.py
@@ -92,7 +92,8 @@ class TxnMallTest(BitcoinTestFramework):
# Node0's balance should be starting balance, plus 50BTC for another
# matured block, minus tx1 and tx2 amounts, and minus transaction fees:
expected = starting_balance + fund_foo_tx["fee"] + fund_bar_tx["fee"]
- if self.options.mine_block: expected += 50
+ if self.options.mine_block:
+ expected += 50
expected += tx1["amount"] + tx1["fee"]
expected += tx2["amount"] + tx2["fee"]
assert_equal(self.nodes[0].getbalance(), expected)
@@ -131,7 +132,7 @@ class TxnMallTest(BitcoinTestFramework):
tx1 = self.nodes[0].gettransaction(txid1)
tx1_clone = self.nodes[0].gettransaction(txid1_clone)
tx2 = self.nodes[0].gettransaction(txid2)
-
+
# Verify expected confirmations
assert_equal(tx1["confirmations"], -2)
assert_equal(tx1_clone["confirmations"], 2)
diff --git a/test/functional/wallet_txn_doublespend.py b/test/functional/wallet_txn_doublespend.py
index f16756eeaa..8419d6b545 100755
--- a/test/functional/wallet_txn_doublespend.py
+++ b/test/functional/wallet_txn_doublespend.py
@@ -27,7 +27,7 @@ class TxnMallTest(BitcoinTestFramework):
for i in range(4):
assert_equal(self.nodes[i].getbalance(), starting_balance)
self.nodes[i].getnewaddress("") # bug workaround, coins generated assigned to first getnewaddress!
-
+
# Assign coins to foo and bar accounts:
node0_address_foo = self.nodes[0].getnewaddress("foo")
fund_foo_txid = self.nodes[0].sendfrom("", node0_address_foo, 1219)
@@ -64,7 +64,7 @@ class TxnMallTest(BitcoinTestFramework):
# Create two spends using 1 50 BTC coin each
txid1 = self.nodes[0].sendfrom("foo", node1_address, 40, 0)
txid2 = self.nodes[0].sendfrom("bar", node1_address, 20, 0)
-
+
# Have node0 mine a block:
if (self.options.mine_block):
self.nodes[0].generate(1)
@@ -76,7 +76,8 @@ class TxnMallTest(BitcoinTestFramework):
# Node0's balance should be starting balance, plus 50BTC for another
# matured block, minus 40, minus 20, and minus transaction fees:
expected = starting_balance + fund_foo_tx["fee"] + fund_bar_tx["fee"]
- if self.options.mine_block: expected += 50
+ if self.options.mine_block:
+ expected += 50
expected += tx1["amount"] + tx1["fee"]
expected += tx2["amount"] + tx2["fee"]
assert_equal(self.nodes[0].getbalance(), expected)
@@ -93,7 +94,7 @@ class TxnMallTest(BitcoinTestFramework):
else:
assert_equal(tx1["confirmations"], 0)
assert_equal(tx2["confirmations"], 0)
-
+
# Now give doublespend and its parents to miner:
self.nodes[2].sendrawtransaction(fund_foo_tx["hex"])
self.nodes[2].sendrawtransaction(fund_bar_tx["hex"])
diff --git a/test/util/data/blanktxv1.json b/test/util/data/blanktxv1.json
index 9fe2de649b..3d5a1cccae 100644
--- a/test/util/data/blanktxv1.json
+++ b/test/util/data/blanktxv1.json
@@ -4,6 +4,7 @@
"version": 1,
"size": 10,
"vsize": 10,
+ "weight": 40,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/blanktxv2.json b/test/util/data/blanktxv2.json
index e97626e421..8374a34adc 100644
--- a/test/util/data/blanktxv2.json
+++ b/test/util/data/blanktxv2.json
@@ -4,6 +4,7 @@
"version": 2,
"size": 10,
"vsize": 10,
+ "weight": 40,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/tt-delin1-out.json b/test/util/data/tt-delin1-out.json
index de647f98b6..9fc2ddc376 100644
--- a/test/util/data/tt-delin1-out.json
+++ b/test/util/data/tt-delin1-out.json
@@ -4,6 +4,7 @@
"version": 1,
"size": 3040,
"vsize": 3040,
+ "weight": 12160,
"locktime": 0,
"vin": [
{
diff --git a/test/util/data/tt-delout1-out.json b/test/util/data/tt-delout1-out.json
index 067ffe74e7..922d048900 100644
--- a/test/util/data/tt-delout1-out.json
+++ b/test/util/data/tt-delout1-out.json
@@ -4,6 +4,7 @@
"version": 1,
"size": 3155,
"vsize": 3155,
+ "weight": 12620,
"locktime": 0,
"vin": [
{
diff --git a/test/util/data/tt-locktime317000-out.json b/test/util/data/tt-locktime317000-out.json
index af7903d1dd..c97206f1ea 100644
--- a/test/util/data/tt-locktime317000-out.json
+++ b/test/util/data/tt-locktime317000-out.json
@@ -4,6 +4,7 @@
"version": 1,
"size": 3189,
"vsize": 3189,
+ "weight": 12756,
"locktime": 317000,
"vin": [
{
diff --git a/test/util/data/txcreate1.json b/test/util/data/txcreate1.json
index 83a86649e0..ca9eacd546 100644
--- a/test/util/data/txcreate1.json
+++ b/test/util/data/txcreate1.json
@@ -4,6 +4,7 @@
"version": 2,
"size": 201,
"vsize": 201,
+ "weight": 804,
"locktime": 0,
"vin": [
{
diff --git a/test/util/data/txcreate2.json b/test/util/data/txcreate2.json
index cca00f752b..ee9b9c3c17 100644
--- a/test/util/data/txcreate2.json
+++ b/test/util/data/txcreate2.json
@@ -4,6 +4,7 @@
"version": 2,
"size": 19,
"vsize": 19,
+ "weight": 76,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreatedata1.json b/test/util/data/txcreatedata1.json
index 15a4246ae5..39909c2e3f 100644
--- a/test/util/data/txcreatedata1.json
+++ b/test/util/data/txcreatedata1.json
@@ -4,6 +4,7 @@
"version": 1,
"size": 176,
"vsize": 176,
+ "weight": 704,
"locktime": 0,
"vin": [
{
diff --git a/test/util/data/txcreatedata2.json b/test/util/data/txcreatedata2.json
index cb93c27971..2958006e58 100644
--- a/test/util/data/txcreatedata2.json
+++ b/test/util/data/txcreatedata2.json
@@ -4,6 +4,7 @@
"version": 2,
"size": 176,
"vsize": 176,
+ "weight": 704,
"locktime": 0,
"vin": [
{
diff --git a/test/util/data/txcreatedata_seq0.json b/test/util/data/txcreatedata_seq0.json
index 4b5a7cab4a..a6656b5ad5 100644
--- a/test/util/data/txcreatedata_seq0.json
+++ b/test/util/data/txcreatedata_seq0.json
@@ -4,6 +4,7 @@
"version": 2,
"size": 85,
"vsize": 85,
+ "weight": 340,
"locktime": 0,
"vin": [
{
diff --git a/test/util/data/txcreatedata_seq1.json b/test/util/data/txcreatedata_seq1.json
index dea48ba373..e5980427b1 100644
--- a/test/util/data/txcreatedata_seq1.json
+++ b/test/util/data/txcreatedata_seq1.json
@@ -4,6 +4,7 @@
"version": 1,
"size": 126,
"vsize": 126,
+ "weight": 504,
"locktime": 0,
"vin": [
{
diff --git a/test/util/data/txcreatemultisig1.json b/test/util/data/txcreatemultisig1.json
index 72e20c8691..c32e755db1 100644
--- a/test/util/data/txcreatemultisig1.json
+++ b/test/util/data/txcreatemultisig1.json
@@ -4,6 +4,7 @@
"version": 1,
"size": 124,
"vsize": 124,
+ "weight": 496,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreatemultisig2.json b/test/util/data/txcreatemultisig2.json
index 7d94ce7396..f97d265894 100644
--- a/test/util/data/txcreatemultisig2.json
+++ b/test/util/data/txcreatemultisig2.json
@@ -4,6 +4,7 @@
"version": 1,
"size": 42,
"vsize": 42,
+ "weight": 168,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreatemultisig3.json b/test/util/data/txcreatemultisig3.json
index 6c5b49d876..b355d7b191 100644
--- a/test/util/data/txcreatemultisig3.json
+++ b/test/util/data/txcreatemultisig3.json
@@ -4,6 +4,7 @@
"version": 1,
"size": 53,
"vsize": 53,
+ "weight": 212,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreatemultisig4.json b/test/util/data/txcreatemultisig4.json
index 9a5d2f4a06..a00dbe3f5d 100644
--- a/test/util/data/txcreatemultisig4.json
+++ b/test/util/data/txcreatemultisig4.json
@@ -4,6 +4,7 @@
"version": 1,
"size": 42,
"vsize": 42,
+ "weight": 168,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreatemultisig5.json b/test/util/data/txcreatemultisig5.json
index 20e9bb077b..ea07822ddd 100644
--- a/test/util/data/txcreatemultisig5.json
+++ b/test/util/data/txcreatemultisig5.json
@@ -4,6 +4,7 @@
"version": 2,
"size": 42,
"vsize": 42,
+ "weight": 168,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreateoutpubkey1.json b/test/util/data/txcreateoutpubkey1.json
index 2704ed7673..32097b3ebe 100644
--- a/test/util/data/txcreateoutpubkey1.json
+++ b/test/util/data/txcreateoutpubkey1.json
@@ -4,6 +4,7 @@
"version": 1,
"size": 54,
"vsize": 54,
+ "weight": 216,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreateoutpubkey2.json b/test/util/data/txcreateoutpubkey2.json
index 4ba5dcb282..c0ee181ede 100644
--- a/test/util/data/txcreateoutpubkey2.json
+++ b/test/util/data/txcreateoutpubkey2.json
@@ -4,6 +4,7 @@
"version": 1,
"size": 41,
"vsize": 41,
+ "weight": 164,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreateoutpubkey3.json b/test/util/data/txcreateoutpubkey3.json
index 0a5d489e15..4d904df3c8 100644
--- a/test/util/data/txcreateoutpubkey3.json
+++ b/test/util/data/txcreateoutpubkey3.json
@@ -4,6 +4,7 @@
"version": 1,
"size": 42,
"vsize": 42,
+ "weight": 168,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreatescript1.json b/test/util/data/txcreatescript1.json
index 5072452fed..af1c4c35e2 100644
--- a/test/util/data/txcreatescript1.json
+++ b/test/util/data/txcreatescript1.json
@@ -4,6 +4,7 @@
"version": 1,
"size": 20,
"vsize": 20,
+ "weight": 80,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreatescript2.json b/test/util/data/txcreatescript2.json
index 94b669ffb6..32dd644579 100644
--- a/test/util/data/txcreatescript2.json
+++ b/test/util/data/txcreatescript2.json
@@ -4,6 +4,7 @@
"version": 1,
"size": 42,
"vsize": 42,
+ "weight": 168,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreatescript3.json b/test/util/data/txcreatescript3.json
index 31b6459214..b9192d9a82 100644
--- a/test/util/data/txcreatescript3.json
+++ b/test/util/data/txcreatescript3.json
@@ -4,6 +4,7 @@
"version": 1,
"size": 53,
"vsize": 53,
+ "weight": 212,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreatescript4.json b/test/util/data/txcreatescript4.json
index eecdf858b7..2271ecfa0a 100644
--- a/test/util/data/txcreatescript4.json
+++ b/test/util/data/txcreatescript4.json
@@ -4,6 +4,7 @@
"version": 1,
"size": 42,
"vsize": 42,
+ "weight": 168,
"locktime": 0,
"vin": [
],
diff --git a/test/util/data/txcreatesignv1.json b/test/util/data/txcreatesignv1.json
index 92a3f76a07..64e5137f4b 100644
--- a/test/util/data/txcreatesignv1.json
+++ b/test/util/data/txcreatesignv1.json
@@ -4,6 +4,7 @@
"version": 1,
"size": 224,
"vsize": 224,
+ "weight": 896,
"locktime": 0,
"vin": [
{