aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml30
-rw-r--r--appveyor.yml3
-rw-r--r--build_msvc/.gitignore1
-rw-r--r--build_msvc/README.md6
-rw-r--r--build_msvc/libbitcoin_cli/libbitcoin_cli.vcxproj.in (renamed from build_msvc/libbitcoin_cli/libbitcoin_cli.vcxproj)2
-rw-r--r--build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in (renamed from build_msvc/libbitcoin_common/libbitcoin_common.vcxproj)38
-rw-r--r--build_msvc/libbitcoin_crypto/libbitcoin_crypto.vcxproj.in (renamed from build_msvc/libbitcoin_crypto/libbitcoin_crypto.vcxproj)20
-rw-r--r--build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in (renamed from build_msvc/libbitcoin_server/libbitcoin_server.vcxproj)42
-rw-r--r--build_msvc/libbitcoin_util/libbitcoin_util.vcxproj.in (renamed from build_msvc/libbitcoin_util/libbitcoin_util.vcxproj)18
-rw-r--r--build_msvc/libbitcoin_wallet/libbitcoin_wallet.vcxproj.in (renamed from build_msvc/libbitcoin_wallet/libbitcoin_wallet.vcxproj)13
-rw-r--r--build_msvc/libbitcoin_zmq/libbitcoin_zmq.vcxproj.in (renamed from build_msvc/libbitcoin_zmq/libbitcoin_zmq.vcxproj)5
-rw-r--r--build_msvc/msvc-autogen.py63
-rw-r--r--depends/config.site.in9
-rw-r--r--src/Makefile.am2
-rw-r--r--src/Makefile.bench.include1
-rw-r--r--src/Makefile.test.include2
-rw-r--r--src/bench/bench_bitcoin.cpp2
-rw-r--r--src/bench/gcs_filter.cpp43
-rw-r--r--src/bitcoin-cli.cpp2
-rw-r--r--src/bitcoin-tx.cpp2
-rw-r--r--src/bitcoind.cpp2
-rw-r--r--src/blockfilter.cpp260
-rw-r--r--src/blockfilter.h145
-rw-r--r--src/bloom.cpp6
-rw-r--r--src/core_write.cpp3
-rw-r--r--src/interfaces/wallet.cpp6
-rw-r--r--src/net_processing.cpp130
-rw-r--r--src/net_processing.h2
-rw-r--r--src/noui.cpp2
-rw-r--r--src/policy/policy.cpp23
-rw-r--r--src/qt/bitcoin.cpp10
-rw-r--r--src/qt/bitcoingui.cpp2
-rw-r--r--src/qt/splashscreen.cpp4
-rw-r--r--src/qt/transactiontablemodel.cpp4
-rw-r--r--src/rpc/blockchain.cpp15
-rw-r--r--src/rpc/rawtransaction.cpp4
-rw-r--r--src/script/ismine.cpp3
-rw-r--r--src/script/sign.cpp10
-rw-r--r--src/script/standard.cpp57
-rw-r--r--src/script/standard.h5
-rw-r--r--src/streams.h167
-rw-r--r--src/test/blockfilter_tests.cpp142
-rw-r--r--src/test/data/blockfilters.json9
-rw-r--r--src/test/miner_tests.cpp2
-rw-r--r--src/test/scheduler_tests.cpp4
-rw-r--r--src/test/script_standard_tests.cpp47
-rw-r--r--src/test/streams_tests.cpp80
-rw-r--r--src/test/test_bitcoin.cpp10
-rw-r--r--src/test/test_bitcoin_fuzzy.cpp12
-rw-r--r--src/test/txindex_tests.cpp2
-rw-r--r--src/txmempool.h3
-rw-r--r--src/undo.h1
-rw-r--r--src/util.cpp2
-rw-r--r--src/util.h23
-rw-r--r--src/validation.cpp29
-rw-r--r--src/validation.h8
-rw-r--r--src/validationinterface.cpp1
-rw-r--r--src/validationinterface.h4
-rw-r--r--src/wallet/coinselection.cpp3
-rw-r--r--src/wallet/feebumper.cpp2
-rw-r--r--src/wallet/rpcwallet.cpp23
-rw-r--r--src/wallet/wallet.cpp21
-rw-r--r--src/wallet/wallet.h39
-rwxr-xr-xtest/functional/feature_rbf.py8
-rwxr-xr-xtest/functional/p2p_invalid_tx.py9
-rwxr-xr-xtest/functional/test_framework/messages.py21
-rwxr-xr-xtest/functional/test_framework/test_node.py18
-rwxr-xr-xtest/lint/check-rpc-mappings.py4
68 files changed, 1251 insertions, 440 deletions
diff --git a/.travis.yml b/.travis.yml
index aafdc2e89d..e6e6d91e30 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,7 +14,8 @@ stages:
env:
global:
- MAKEJOBS=-j3
- - RUN_TESTS=false
+ - RUN_UNIT_TESTS=true
+ - RUN_FUNCTIONAL_TESTS=true
- RUN_BENCH=false # Set to true for any one job that has debug enabled, to quickly check bench is not crashing or hitting assertions
- DOCKER_NAME_TAG=ubuntu:18.04
- LC_ALL=C.UTF-8
@@ -59,10 +60,10 @@ script:
- cd bitcoin-$HOST
- BEGIN_FOLD configure; DOCKER_EXEC ./configure --cache-file=../config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( cat config.log && false); END_FOLD
- BEGIN_FOLD build; DOCKER_EXEC make $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && DOCKER_EXEC make $GOAL V=1 ; false ); END_FOLD
- - if [ "$RUN_TESTS" = "true" ]; then BEGIN_FOLD unit-tests; DOCKER_EXEC LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib make $MAKEJOBS check VERBOSE=1; END_FOLD; fi
+ - if [ "$RUN_UNIT_TESTS" = "true" ]; then BEGIN_FOLD unit-tests; DOCKER_EXEC LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib make $MAKEJOBS check VERBOSE=1; END_FOLD; fi
- if [ "$RUN_BENCH" = "true" ]; then BEGIN_FOLD bench; DOCKER_EXEC LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib $OUTDIR/bin/bench_bitcoin -scaling=0.001 ; END_FOLD; fi
- if [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then extended="--extended --exclude feature_pruning,feature_dbcrash"; fi
- - if [ "$RUN_TESTS" = "true" ]; then BEGIN_FOLD functional-tests; DOCKER_EXEC test/functional/test_runner.py --combinedlogslen=4000 --coverage --quiet --failfast ${extended}; END_FOLD; fi
+ - if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then BEGIN_FOLD functional-tests; DOCKER_EXEC test/functional/test_runner.py --combinedlogslen=4000 --coverage --quiet --failfast ${extended}; END_FOLD; fi
after_script:
- echo $TRAVIS_COMMIT_RANGE
- echo $TRAVIS_COMMIT_LOG
@@ -74,6 +75,8 @@ jobs:
HOST=arm-linux-gnueabihf
PACKAGES="g++-arm-linux-gnueabihf"
DEP_OPTS="NO_QT=1"
+ RUN_UNIT_TESTS=false
+ RUN_FUNCTIONAL_TESTS=false
GOAL="install"
BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports"
# Win32
@@ -83,7 +86,6 @@ jobs:
DPKG_ADD_ARCH="i386"
DEP_OPTS="NO_QT=1"
PACKAGES="python3 nsis g++-mingw-w64-i686 wine-binfmt wine32"
- RUN_TESTS=true
GOAL="install"
BITCOIN_CONFIG="--enable-reduce-exports"
# Win64
@@ -92,7 +94,6 @@ jobs:
HOST=x86_64-w64-mingw32
DEP_OPTS="NO_QT=1"
PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine-binfmt wine64"
- RUN_TESTS=true
GOAL="install"
BITCOIN_CONFIG="--enable-reduce-exports"
# 32-bit + dash
@@ -101,7 +102,6 @@ jobs:
HOST=i686-pc-linux-gnu
PACKAGES="g++-multilib python3-zmq"
DEP_OPTS="NO_QT=1"
- RUN_TESTS=true
GOAL="install"
BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++"
CONFIG_SHELL="/bin/dash"
@@ -111,26 +111,32 @@ jobs:
HOST=x86_64-unknown-linux-gnu
PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools protobuf-compiler libdbus-1-dev libharfbuzz-dev libprotobuf-dev"
DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1"
- RUN_TESTS=true
- RUN_BENCH=true
GOAL="install"
BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports --enable-debug CXXFLAGS=\"-g0 -O2\""
-# x86_64 Linux (Qt5 & system libs)
+# x86_64 Linux (no depends, only system libs)
- stage: test
env: >-
HOST=x86_64-unknown-linux-gnu
PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev"
NO_DEPENDS=1
- RUN_TESTS=true
GOAL="install"
BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --enable-glibc-back-compat --enable-reduce-exports --with-gui=qt5 CPPFLAGS=-DDEBUG_LOCKORDER"
+# x86_64 Linux (sanitizers)
+ - stage: test
+ env: >-
+ HOST=x86_64-unknown-linux-gnu
+ PACKAGES="clang python3-zmq qtbase5-dev qttools5-dev-tools libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev"
+ NO_DEPENDS=1
+ RUN_BENCH=true
+ RUN_FUNCTIONAL_TESTS=false # Disabled for now, can be combined with the other x86_64 linux NO_DEPENDS job when functional tests pass the sanitizers
+ GOAL="install"
+ BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --enable-glibc-back-compat --enable-reduce-exports --with-gui=qt5 CPPFLAGS=-DDEBUG_LOCKORDER --with-sanitizers=undefined CC=clang CXX=clang++"
# x86_64 Linux, No wallet
- stage: test
env: >-
HOST=x86_64-unknown-linux-gnu
PACKAGES="python3"
DEP_OPTS="NO_WALLET=1"
- RUN_TESTS=true
GOAL="install"
BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports"
# Cross-Mac
@@ -139,6 +145,8 @@ jobs:
HOST=x86_64-apple-darwin14
PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev python3-setuptools-git"
OSX_SDK=10.11
+ RUN_UNIT_TESTS=false
+ RUN_FUNCTIONAL_TESTS=false
GOAL="all deploy"
BITCOIN_CONFIG="--enable-gui --enable-reduce-exports --enable-werror"
- stage: lint
diff --git a/appveyor.yml b/appveyor.yml
index c6a5a91ba5..85b1a999d1 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -6,6 +6,8 @@ platform: x64
environment:
APPVEYOR_SAVE_CACHE_ON_ERROR: true
cache: C:\tools\vcpkg\installed\
+init:
+- cmd: set PATH=C:\Python36-x64;%PATH%
before_build:
- ps: >-
$packages = @(
@@ -28,6 +30,7 @@ before_build:
git -C C:\Tools\vcpkg pull # This is a temporary fix, can be removed after appveyor update its image to include Microsoft/vcpkg#4046
Invoke-Expression -Command "vcpkg install $all_packages"
+- cmd: python build_msvc\msvc-autogen.py
build:
project: build_msvc\bitcoin.sln
parallel: true
diff --git a/build_msvc/.gitignore b/build_msvc/.gitignore
index fbcd1077b3..d5aa22c05e 100644
--- a/build_msvc/.gitignore
+++ b/build_msvc/.gitignore
@@ -8,3 +8,4 @@ packages/*
*/Release
*/x64
*.vcxproj.user
+*.vcxproj
diff --git a/build_msvc/README.md b/build_msvc/README.md
index 6de464e92f..5fb08df8d7 100644
--- a/build_msvc/README.md
+++ b/build_msvc/README.md
@@ -47,4 +47,10 @@ The instructions below use vcpkg to install the dependencies.
leveldb:x64-windows-static
```
+- Use Python to generate *.vcxproj from Makefile
+
+```
+ PS >python msvc-autogen.py
+```
+
- Build in Visual Studio. \ No newline at end of file
diff --git a/build_msvc/libbitcoin_cli/libbitcoin_cli.vcxproj b/build_msvc/libbitcoin_cli/libbitcoin_cli.vcxproj.in
index 623d24da10..b7265054fb 100644
--- a/build_msvc/libbitcoin_cli/libbitcoin_cli.vcxproj
+++ b/build_msvc/libbitcoin_cli/libbitcoin_cli.vcxproj.in
@@ -20,7 +20,7 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
- <ClCompile Include="..\..\src\rpc\client.cpp" />
+@SOURCE_FILES@
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
diff --git a/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj b/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in
index e6d95ed5f3..42145c15ad 100644
--- a/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj
+++ b/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in
@@ -165,43 +165,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
- <ClInclude Include="..\..\src\base58.h" />
- <ClInclude Include="..\..\src\bech32.h" />
- <ClInclude Include="..\..\src\chainparams.h" />
- <ClInclude Include="..\..\src\coins.h" />
- <ClInclude Include="..\..\src\compressor.h" />
- <ClInclude Include="..\..\src\key.h" />
- <ClInclude Include="..\..\src\keystore.h" />
- <ClInclude Include="..\..\src\netaddress.h" />
- <ClInclude Include="..\..\src\netbase.h" />
- <ClInclude Include="..\..\src\policy\feerate.h" />
- <ClInclude Include="..\..\src\protocol.h" />
- <ClInclude Include="..\..\src\scheduler.h" />
- <ClInclude Include="..\..\src\script\sign.h" />
- <ClInclude Include="..\..\src\script\standard.h" />
- <ClInclude Include="..\..\src\warnings.h" />
- </ItemGroup>
- <ItemGroup>
- <ClCompile Include="..\..\src\base58.cpp" />
- <ClCompile Include="..\..\src\bech32.cpp" />
- <ClCompile Include="..\..\src\chainparams.cpp" />
- <ClCompile Include="..\..\src\coins.cpp" />
- <ClCompile Include="..\..\src\compressor.cpp" />
- <ClCompile Include="..\..\src\core_read.cpp" />
- <ClCompile Include="..\..\src\core_write.cpp" />
- <ClCompile Include="..\..\src\key.cpp" />
- <ClCompile Include="..\..\src\key_io.cpp" />
- <ClCompile Include="..\..\src\keystore.cpp" />
- <ClCompile Include="..\..\src\netaddress.cpp" />
- <ClCompile Include="..\..\src\netbase.cpp" />
- <ClCompile Include="..\..\src\policy\feerate.cpp" />
- <ClCompile Include="..\..\src\protocol.cpp" />
- <ClCompile Include="..\..\src\scheduler.cpp" />
- <ClCompile Include="..\..\src\script\descriptor.cpp" />
- <ClCompile Include="..\..\src\script\sign.cpp" />
- <ClCompile Include="..\..\src\script\ismine.cpp" />
- <ClCompile Include="..\..\src\script\standard.cpp" />
- <ClCompile Include="..\..\src\warnings.cpp" />
+@SOURCE_FILES@
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
diff --git a/build_msvc/libbitcoin_crypto/libbitcoin_crypto.vcxproj b/build_msvc/libbitcoin_crypto/libbitcoin_crypto.vcxproj.in
index 50519d045f..a05125723a 100644
--- a/build_msvc/libbitcoin_crypto/libbitcoin_crypto.vcxproj
+++ b/build_msvc/libbitcoin_crypto/libbitcoin_crypto.vcxproj.in
@@ -151,25 +151,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
- <ClInclude Include="..\..\src\crypto\aes.h" />
- <ClInclude Include="..\..\src\crypto\chacha20.h" />
- <ClInclude Include="..\..\src\crypto\common.h" />
- <ClInclude Include="..\..\src\crypto\hmac_sha256.h" />
- <ClInclude Include="..\..\src\crypto\hmac_sha512.h" />
- <ClInclude Include="..\..\src\crypto\ripemd160.h" />
- <ClInclude Include="..\..\src\crypto\sha1.h" />
- <ClInclude Include="..\..\src\crypto\sha256.h" />
- <ClInclude Include="..\..\src\crypto\sha512.h" />
- </ItemGroup>
- <ItemGroup>
- <ClCompile Include="..\..\src\crypto\aes.cpp" />
- <ClCompile Include="..\..\src\crypto\chacha20.cpp" />
- <ClCompile Include="..\..\src\crypto\hmac_sha256.cpp" />
- <ClCompile Include="..\..\src\crypto\hmac_sha512.cpp" />
- <ClCompile Include="..\..\src\crypto\ripemd160.cpp" />
- <ClCompile Include="..\..\src\crypto\sha1.cpp" />
- <ClCompile Include="..\..\src\crypto\sha256.cpp" />
- <ClCompile Include="..\..\src\crypto\sha512.cpp" />
+@SOURCE_FILES@
</ItemGroup>
<Import Label="configTarget" Project="..\common.vcxproj" />
</Project>
diff --git a/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj b/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in
index 9d4ac1a7f7..0a165d0b75 100644
--- a/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj
+++ b/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in
@@ -154,53 +154,13 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
- <ClCompile Include="..\..\src\addrdb.cpp" />
- <ClCompile Include="..\..\src\addrman.cpp" />
- <ClCompile Include="..\..\src\blockencodings.cpp" />
- <ClCompile Include="..\..\src\bloom.cpp" />
- <ClCompile Include="..\..\src\chain.cpp" />
- <ClCompile Include="..\..\src\checkpoints.cpp" />
- <ClCompile Include="..\..\src\consensus\tx_verify.cpp" />
- <ClCompile Include="..\..\src\dbwrapper.cpp" />
- <ClCompile Include="..\..\src\httprpc.cpp" />
- <ClCompile Include="..\..\src\httpserver.cpp" />
- <ClCompile Include="..\..\src\index\base.cpp" />
- <ClCompile Include="..\..\src\init.cpp" />
- <ClCompile Include="..\..\src\merkleblock.cpp" />
- <ClCompile Include="..\..\src\miner.cpp" />
- <ClCompile Include="..\..\src\net.cpp" />
- <ClCompile Include="..\..\src\net_processing.cpp" />
- <ClCompile Include="..\..\src\noui.cpp" />
- <ClCompile Include="..\..\src\outputtype.cpp" />
- <ClCompile Include="..\..\src\policy\fees.cpp" />
- <ClCompile Include="..\..\src\policy\policy.cpp" />
- <ClCompile Include="..\..\src\policy\rbf.cpp" />
- <ClCompile Include="..\..\src\pow.cpp" />
- <ClCompile Include="..\..\src\rest.cpp" />
- <ClCompile Include="..\..\src\shutdown.cpp" />
- <ClCompile Include="..\..\src\rpc\blockchain.cpp" />
- <ClCompile Include="..\..\src\rpc\mining.cpp" />
- <ClCompile Include="..\..\src\rpc\misc.cpp" />
<ClCompile Include="..\..\src\rpc\net.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)\netrpc.obj</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)\netrpc.obj</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)\netrpc.obj</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)\netrpc.obj</ObjectFileName>
</ClCompile>
- <ClCompile Include="..\..\src\rpc\rawtransaction.cpp" />
- <ClCompile Include="..\..\src\rpc\server.cpp" />
- <ClCompile Include="..\..\src\rpc\util.cpp" />
- <ClCompile Include="..\..\src\script\ismine.cpp" />
- <ClCompile Include="..\..\src\script\sigcache.cpp" />
- <ClCompile Include="..\..\src\timedata.cpp" />
- <ClCompile Include="..\..\src\torcontrol.cpp" />
- <ClCompile Include="..\..\src\txdb.cpp" />
- <ClCompile Include="..\..\src\txmempool.cpp" />
- <ClCompile Include="..\..\src\ui_interface.cpp" />
- <ClCompile Include="..\..\src\validation.cpp" />
- <ClCompile Include="..\..\src\validationinterface.cpp" />
- <ClCompile Include="..\..\src\versionbits.cpp" />
- <ClCompile Include="..\..\src\index\txindex.cpp" />
+@SOURCE_FILES@
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
diff --git a/build_msvc/libbitcoin_util/libbitcoin_util.vcxproj b/build_msvc/libbitcoin_util/libbitcoin_util.vcxproj.in
index 9e960682e5..dc17c98e98 100644
--- a/build_msvc/libbitcoin_util/libbitcoin_util.vcxproj
+++ b/build_msvc/libbitcoin_util/libbitcoin_util.vcxproj.in
@@ -174,23 +174,7 @@
</ProjectReference>
</ItemDefinitionGroup>
<ItemGroup>
- <ClCompile Include="..\..\src\chainparamsbase.cpp" />
- <ClCompile Include="..\..\src\clientversion.cpp" />
- <ClCompile Include="..\..\src\compat\glibcxx_sanity.cpp" />
- <ClCompile Include="..\..\src\compat\glibc_sanity.cpp" />
- <ClCompile Include="..\..\src\compat\strnlen.cpp" />
- <ClCompile Include="..\..\src\fs.cpp" />
- <ClCompile Include="..\..\src\logging.cpp" />
- <ClCompile Include="..\..\src\random.cpp" />
- <ClCompile Include="..\..\src\rpc\protocol.cpp" />
- <ClCompile Include="..\..\src\support\cleanse.cpp" />
- <ClCompile Include="..\..\src\support\lockedpool.cpp" />
- <ClCompile Include="..\..\src\sync.cpp" />
- <ClCompile Include="..\..\src\threadinterrupt.cpp" />
- <ClCompile Include="..\..\src\util.cpp" />
- <ClCompile Include="..\..\src\utilmoneystr.cpp" />
- <ClCompile Include="..\..\src\utilstrencodings.cpp" />
- <ClCompile Include="..\..\src\utiltime.cpp" />
+@SOURCE_FILES@
</ItemGroup>
<Import Label="configTarget" Project="..\common.vcxproj" />
</Project>
diff --git a/build_msvc/libbitcoin_wallet/libbitcoin_wallet.vcxproj b/build_msvc/libbitcoin_wallet/libbitcoin_wallet.vcxproj.in
index 64f3e16289..1bb7be6f7f 100644
--- a/build_msvc/libbitcoin_wallet/libbitcoin_wallet.vcxproj
+++ b/build_msvc/libbitcoin_wallet/libbitcoin_wallet.vcxproj.in
@@ -20,18 +20,7 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
- <ClCompile Include="..\..\src\wallet\coinselection.cpp" />
- <ClCompile Include="..\..\src\wallet\coincontrol.cpp" />
- <ClCompile Include="..\..\src\wallet\crypter.cpp" />
- <ClCompile Include="..\..\src\wallet\db.cpp" />
- <ClCompile Include="..\..\src\wallet\feebumper.cpp" />
- <ClCompile Include="..\..\src\wallet\fees.cpp" />
- <ClCompile Include="..\..\src\wallet\init.cpp" />
- <ClCompile Include="..\..\src\wallet\rpcdump.cpp" />
- <ClCompile Include="..\..\src\wallet\rpcwallet.cpp" />
- <ClCompile Include="..\..\src\wallet\wallet.cpp" />
- <ClCompile Include="..\..\src\wallet\walletdb.cpp" />
- <ClCompile Include="..\..\src\wallet\walletutil.cpp" />
+@SOURCE_FILES@
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
diff --git a/build_msvc/libbitcoin_zmq/libbitcoin_zmq.vcxproj b/build_msvc/libbitcoin_zmq/libbitcoin_zmq.vcxproj.in
index d7fbdd94b7..e396c1ad0c 100644
--- a/build_msvc/libbitcoin_zmq/libbitcoin_zmq.vcxproj
+++ b/build_msvc/libbitcoin_zmq/libbitcoin_zmq.vcxproj.in
@@ -20,10 +20,7 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
- <ClCompile Include="..\..\src\zmq\zmqabstractnotifier.cpp" />
- <ClCompile Include="..\..\src\zmq\zmqnotificationinterface.cpp" />
- <ClCompile Include="..\..\src\zmq\zmqpublishnotifier.cpp" />
- <ClCompile Include="..\..\src\zmq\zmqrpc.cpp" />
+@SOURCE_FILES@
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
diff --git a/build_msvc/msvc-autogen.py b/build_msvc/msvc-autogen.py
new file mode 100644
index 0000000000..8888487e75
--- /dev/null
+++ b/build_msvc/msvc-autogen.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python3
+
+import os
+import re
+
+SOURCE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'src'))
+
+libs = [
+ 'libbitcoin_cli',
+ 'libbitcoin_common',
+ 'libbitcoin_crypto',
+ 'libbitcoin_server',
+ 'libbitcoin_util',
+ 'libbitcoin_wallet',
+ 'libbitcoin_zmq',
+]
+
+ignore_list = [
+ 'rpc/net.cpp',
+ 'interfaces/handler.cpp',
+ 'interfaces/node.cpp',
+ 'interfaces/wallet.cpp',
+]
+
+lib_sources = {}
+
+
+def parse_makefile(makefile):
+ with open(makefile, 'r', encoding='utf-8') as file:
+ current_lib = ''
+ for line in file.read().splitlines():
+ if current_lib:
+ source = line.split()[0]
+ if source.endswith('.cpp') and not source.startswith('$') and source not in ignore_list:
+ lib_sources[current_lib].append(source.replace('/', '\\'))
+ if not line.endswith('\\'):
+ current_lib = ''
+ continue
+ for lib in libs:
+ _lib = lib.replace('-', '_')
+ if re.search(_lib + '.*_SOURCES \\= \\\\', line):
+ current_lib = lib
+ lib_sources[current_lib] = []
+ break
+
+
+def main():
+ for makefile_name in os.listdir(SOURCE_DIR):
+ if 'Makefile' in makefile_name:
+ parse_makefile(os.path.join(SOURCE_DIR, makefile_name))
+ for key, value in lib_sources.items():
+ vcxproj_filename = os.path.abspath(os.path.join(os.path.dirname(__file__), key, key + '.vcxproj'))
+ content = ''
+ for source_filename in value:
+ content += ' <ClCompile Include="..\\..\\src\\' + source_filename + '" />\n'
+ with open(vcxproj_filename + '.in', 'r', encoding='utf-8') as vcxproj_in_file:
+ with open(vcxproj_filename, 'w', encoding='utf-8') as vcxproj_file:
+ vcxproj_file.write(vcxproj_in_file.read().replace(
+ '@SOURCE_FILES@\n', content))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/depends/config.site.in b/depends/config.site.in
index 8444dc26f2..b7a5e795c8 100644
--- a/depends/config.site.in
+++ b/depends/config.site.in
@@ -61,9 +61,12 @@ fi
CPPFLAGS="-I$depends_prefix/include/ $CPPFLAGS"
LDFLAGS="-L$depends_prefix/lib $LDFLAGS"
-CC="@CC@"
-CXX="@CXX@"
-OBJC="${CC}"
+if test -n "@CC@" -a -z "${CC}"; then
+ CC="@CC@"
+fi
+if test -n "@CXX@" -a -z "${CXX}"; then
+ CXX="@CXX@"
+fi
PYTHONPATH=$depends_prefix/native/lib/python/dist-packages:$PYTHONPATH
if test -n "@AR@"; then
diff --git a/src/Makefile.am b/src/Makefile.am
index d1693fa85c..3701ee8f3c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -96,6 +96,7 @@ BITCOIN_CORE_H = \
bech32.h \
bloom.h \
blockencodings.h \
+ blockfilter.h \
chain.h \
chainparams.h \
chainparamsbase.h \
@@ -219,6 +220,7 @@ libbitcoin_server_a_SOURCES = \
addrman.cpp \
bloom.cpp \
blockencodings.cpp \
+ blockfilter.cpp \
chain.cpp \
checkpoints.cpp \
consensus/tx_verify.cpp \
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index f5293585a0..76177630ab 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -22,6 +22,7 @@ bench_bench_bitcoin_SOURCES = \
bench/rollingbloom.cpp \
bench/crypto_hash.cpp \
bench/ccoins_caching.cpp \
+ bench/gcs_filter.cpp \
bench/merkle_root.cpp \
bench/mempool_eviction.cpp \
bench/verify_script.cpp \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 6f401636f5..9e7d0dc745 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -9,6 +9,7 @@ TEST_BINARY=test/test_bitcoin$(EXEEXT)
JSON_TEST_FILES = \
test/data/base58_encode_decode.json \
+ test/data/blockfilters.json \
test/data/key_io_valid.json \
test/data/key_io_invalid.json \
test/data/script_tests.json \
@@ -39,6 +40,7 @@ BITCOIN_TESTS =\
test/bip32_tests.cpp \
test/blockchain_tests.cpp \
test/blockencodings_tests.cpp \
+ test/blockfilter_tests.cpp \
test/bloom_tests.cpp \
test/bswap_tests.cpp \
test/checkqueue_tests.cpp \
diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp
index 603b858e54..d7b8083e7c 100644
--- a/src/bench/bench_bitcoin.cpp
+++ b/src/bench/bench_bitcoin.cpp
@@ -13,6 +13,8 @@
#include <memory>
+const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
+
static const int64_t DEFAULT_BENCH_EVALUATIONS = 5;
static const char* DEFAULT_BENCH_FILTER = ".*";
static const char* DEFAULT_BENCH_SCALING = "1.0";
diff --git a/src/bench/gcs_filter.cpp b/src/bench/gcs_filter.cpp
new file mode 100644
index 0000000000..6f4e384e3b
--- /dev/null
+++ b/src/bench/gcs_filter.cpp
@@ -0,0 +1,43 @@
+// Copyright (c) 2018 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <bench/bench.h>
+#include <blockfilter.h>
+
+static void ConstructGCSFilter(benchmark::State& state)
+{
+ GCSFilter::ElementSet elements;
+ for (int i = 0; i < 10000; ++i) {
+ GCSFilter::Element element(32);
+ element[0] = static_cast<unsigned char>(i);
+ element[1] = static_cast<unsigned char>(i >> 8);
+ elements.insert(std::move(element));
+ }
+
+ uint64_t siphash_k0 = 0;
+ while (state.KeepRunning()) {
+ GCSFilter filter(siphash_k0, 0, 20, 1 << 20, elements);
+
+ siphash_k0++;
+ }
+}
+
+static void MatchGCSFilter(benchmark::State& state)
+{
+ GCSFilter::ElementSet elements;
+ for (int i = 0; i < 10000; ++i) {
+ GCSFilter::Element element(32);
+ element[0] = static_cast<unsigned char>(i);
+ element[1] = static_cast<unsigned char>(i >> 8);
+ elements.insert(std::move(element));
+ }
+ GCSFilter filter(0, 0, 20, 1 << 20, elements);
+
+ while (state.KeepRunning()) {
+ filter.Match(GCSFilter::Element());
+ }
+}
+
+BENCHMARK(ConstructGCSFilter, 1000);
+BENCHMARK(MatchGCSFilter, 50 * 1000);
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index db713f58d2..c9414e67c7 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -24,6 +24,8 @@
#include <univalue.h>
+const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
+
static const char DEFAULT_RPCCONNECT[] = "127.0.0.1";
static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
static const bool DEFAULT_NAMED=false;
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 5fef4724c9..20f0218ac1 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -31,6 +31,8 @@ static bool fCreateBlank;
static std::map<std::string,UniValue> registers;
static const int CONTINUE_EXECUTION=-1;
+const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
+
static void SetupBitcoinTxArgs()
{
gArgs.AddArg("-?", "This help message", false, OptionsCategory::OPTIONS);
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index 06f8622426..bf04d95b50 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -23,6 +23,8 @@
#include <stdio.h>
+const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
+
/* Introduction text for doxygen: */
/*! \mainpage Developer documentation
diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp
new file mode 100644
index 0000000000..38fcfacf7f
--- /dev/null
+++ b/src/blockfilter.cpp
@@ -0,0 +1,260 @@
+// Copyright (c) 2018 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <blockfilter.h>
+#include <hash.h>
+#include <primitives/transaction.h>
+#include <script/script.h>
+#include <streams.h>
+
+/// SerType used to serialize parameters in GCS filter encoding.
+static constexpr int GCS_SER_TYPE = SER_NETWORK;
+
+/// Protocol version used to serialize parameters in GCS filter encoding.
+static constexpr int GCS_SER_VERSION = 0;
+
+template <typename OStream>
+static void GolombRiceEncode(BitStreamWriter<OStream>& bitwriter, uint8_t P, uint64_t x)
+{
+ // Write quotient as unary-encoded: q 1's followed by one 0.
+ uint64_t q = x >> P;
+ while (q > 0) {
+ int nbits = q <= 64 ? static_cast<int>(q) : 64;
+ bitwriter.Write(~0ULL, nbits);
+ q -= nbits;
+ }
+ bitwriter.Write(0, 1);
+
+ // Write the remainder in P bits. Since the remainder is just the bottom
+ // P bits of x, there is no need to mask first.
+ bitwriter.Write(x, P);
+}
+
+template <typename IStream>
+static uint64_t GolombRiceDecode(BitStreamReader<IStream>& bitreader, uint8_t P)
+{
+ // Read unary-encoded quotient: q 1's followed by one 0.
+ uint64_t q = 0;
+ while (bitreader.Read(1) == 1) {
+ ++q;
+ }
+
+ uint64_t r = bitreader.Read(P);
+
+ return (q << P) + r;
+}
+
+// Map a value x that is uniformly distributed in the range [0, 2^64) to a
+// value uniformly distributed in [0, n) by returning the upper 64 bits of
+// x * n.
+//
+// See: https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
+static uint64_t MapIntoRange(uint64_t x, uint64_t n)
+{
+#ifdef __SIZEOF_INT128__
+ return (static_cast<unsigned __int128>(x) * static_cast<unsigned __int128>(n)) >> 64;
+#else
+ // To perform the calculation on 64-bit numbers without losing the
+ // result to overflow, split the numbers into the most significant and
+ // least significant 32 bits and perform multiplication piece-wise.
+ //
+ // See: https://stackoverflow.com/a/26855440
+ uint64_t x_hi = x >> 32;
+ uint64_t x_lo = x & 0xFFFFFFFF;
+ uint64_t n_hi = n >> 32;
+ uint64_t n_lo = n & 0xFFFFFFFF;
+
+ uint64_t ac = x_hi * n_hi;
+ uint64_t ad = x_hi * n_lo;
+ uint64_t bc = x_lo * n_hi;
+ uint64_t bd = x_lo * n_lo;
+
+ uint64_t mid34 = (bd >> 32) + (bc & 0xFFFFFFFF) + (ad & 0xFFFFFFFF);
+ uint64_t upper64 = ac + (bc >> 32) + (ad >> 32) + (mid34 >> 32);
+ return upper64;
+#endif
+}
+
+uint64_t GCSFilter::HashToRange(const Element& element) const
+{
+ uint64_t hash = CSipHasher(m_siphash_k0, m_siphash_k1)
+ .Write(element.data(), element.size())
+ .Finalize();
+ return MapIntoRange(hash, m_F);
+}
+
+std::vector<uint64_t> GCSFilter::BuildHashedSet(const ElementSet& elements) const
+{
+ std::vector<uint64_t> hashed_elements;
+ hashed_elements.reserve(elements.size());
+ for (const Element& element : elements) {
+ hashed_elements.push_back(HashToRange(element));
+ }
+ std::sort(hashed_elements.begin(), hashed_elements.end());
+ return hashed_elements;
+}
+
+GCSFilter::GCSFilter(uint64_t siphash_k0, uint64_t siphash_k1, uint8_t P, uint32_t M)
+ : m_siphash_k0(siphash_k0), m_siphash_k1(siphash_k1), m_P(P), m_M(M), m_N(0), m_F(0)
+{}
+
+GCSFilter::GCSFilter(uint64_t siphash_k0, uint64_t siphash_k1, uint8_t P, uint32_t M,
+ std::vector<unsigned char> encoded_filter)
+ : GCSFilter(siphash_k0, siphash_k1, P, M)
+{
+ m_encoded = std::move(encoded_filter);
+
+ VectorReader stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);
+
+ uint64_t N = ReadCompactSize(stream);
+ m_N = static_cast<uint32_t>(N);
+ if (m_N != N) {
+ throw std::ios_base::failure("N must be <2^32");
+ }
+ m_F = static_cast<uint64_t>(m_N) * static_cast<uint64_t>(m_M);
+
+ // Verify that the encoded filter contains exactly N elements. If it has too much or too little
+ // data, a std::ios_base::failure exception will be raised.
+ BitStreamReader<VectorReader> bitreader(stream);
+ for (uint64_t i = 0; i < m_N; ++i) {
+ GolombRiceDecode(bitreader, m_P);
+ }
+ if (!stream.empty()) {
+ throw std::ios_base::failure("encoded_filter contains excess data");
+ }
+}
+
+GCSFilter::GCSFilter(uint64_t siphash_k0, uint64_t siphash_k1, uint8_t P, uint32_t M,
+ const ElementSet& elements)
+ : GCSFilter(siphash_k0, siphash_k1, P, M)
+{
+ size_t N = elements.size();
+ m_N = static_cast<uint32_t>(N);
+ if (m_N != N) {
+ throw std::invalid_argument("N must be <2^32");
+ }
+ m_F = static_cast<uint64_t>(m_N) * static_cast<uint64_t>(m_M);
+
+ CVectorWriter stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);
+
+ WriteCompactSize(stream, m_N);
+
+ if (elements.empty()) {
+ return;
+ }
+
+ BitStreamWriter<CVectorWriter> bitwriter(stream);
+
+ uint64_t last_value = 0;
+ for (uint64_t value : BuildHashedSet(elements)) {
+ uint64_t delta = value - last_value;
+ GolombRiceEncode(bitwriter, m_P, delta);
+ last_value = value;
+ }
+
+ bitwriter.Flush();
+}
+
+bool GCSFilter::MatchInternal(const uint64_t* element_hashes, size_t size) const
+{
+ VectorReader stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);
+
+ // Seek forward by size of N
+ uint64_t N = ReadCompactSize(stream);
+ assert(N == m_N);
+
+ BitStreamReader<VectorReader> bitreader(stream);
+
+ uint64_t value = 0;
+ size_t hashes_index = 0;
+ for (uint32_t i = 0; i < m_N; ++i) {
+ uint64_t delta = GolombRiceDecode(bitreader, m_P);
+ value += delta;
+
+ while (true) {
+ if (hashes_index == size) {
+ return false;
+ } else if (element_hashes[hashes_index] == value) {
+ return true;
+ } else if (element_hashes[hashes_index] > value) {
+ break;
+ }
+
+ hashes_index++;
+ }
+ }
+
+ return false;
+}
+
+bool GCSFilter::Match(const Element& element) const
+{
+ uint64_t query = HashToRange(element);
+ return MatchInternal(&query, 1);
+}
+
+bool GCSFilter::MatchAny(const ElementSet& elements) const
+{
+ const std::vector<uint64_t> queries = BuildHashedSet(elements);
+ return MatchInternal(queries.data(), queries.size());
+}
+
+static GCSFilter::ElementSet BasicFilterElements(const CBlock& block,
+ const CBlockUndo& block_undo)
+{
+ GCSFilter::ElementSet elements;
+
+ for (const CTransactionRef& tx : block.vtx) {
+ for (const CTxOut& txout : tx->vout) {
+ const CScript& script = txout.scriptPubKey;
+ if (script[0] == OP_RETURN) continue;
+ elements.emplace(script.begin(), script.end());
+ }
+ }
+
+ for (const CTxUndo& tx_undo : block_undo.vtxundo) {
+ for (const Coin& prevout : tx_undo.vprevout) {
+ const CScript& script = prevout.out.scriptPubKey;
+ elements.emplace(script.begin(), script.end());
+ }
+ }
+
+ return elements;
+}
+
+BlockFilter::BlockFilter(BlockFilterType filter_type, const CBlock& block, const CBlockUndo& block_undo)
+ : m_filter_type(filter_type), m_block_hash(block.GetHash())
+{
+ switch (m_filter_type) {
+ case BlockFilterType::BASIC:
+ m_filter = GCSFilter(m_block_hash.GetUint64(0), m_block_hash.GetUint64(1),
+ BASIC_FILTER_P, BASIC_FILTER_M,
+ BasicFilterElements(block, block_undo));
+ break;
+
+ default:
+ throw std::invalid_argument("unknown filter_type");
+ }
+}
+
+uint256 BlockFilter::GetHash() const
+{
+ const std::vector<unsigned char>& data = GetEncodedFilter();
+
+ uint256 result;
+ CHash256().Write(data.data(), data.size()).Finalize(result.begin());
+ return result;
+}
+
+uint256 BlockFilter::ComputeHeader(const uint256& prev_header) const
+{
+ const uint256& filter_hash = GetHash();
+
+ uint256 result;
+ CHash256()
+ .Write(filter_hash.begin(), filter_hash.size())
+ .Write(prev_header.begin(), prev_header.size())
+ .Finalize(result.begin());
+ return result;
+}
diff --git a/src/blockfilter.h b/src/blockfilter.h
new file mode 100644
index 0000000000..46833ac0be
--- /dev/null
+++ b/src/blockfilter.h
@@ -0,0 +1,145 @@
+// Copyright (c) 2018 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_BLOCKFILTER_H
+#define BITCOIN_BLOCKFILTER_H
+
+#include <set>
+#include <stdint.h>
+#include <vector>
+
+#include <primitives/block.h>
+#include <serialize.h>
+#include <uint256.h>
+#include <undo.h>
+
+/**
+ * This implements a Golomb-coded set as defined in BIP 158. It is a
+ * compact, probabilistic data structure for testing set membership.
+ */
+class GCSFilter
+{
+public:
+ typedef std::vector<unsigned char> Element;
+ typedef std::set<Element> ElementSet;
+
+private:
+ uint64_t m_siphash_k0;
+ uint64_t m_siphash_k1;
+ uint8_t m_P; //!< Golomb-Rice coding parameter
+ uint32_t m_M; //!< Inverse false positive rate
+ uint32_t m_N; //!< Number of elements in the filter
+ uint64_t m_F; //!< Range of element hashes, F = N * M
+ std::vector<unsigned char> m_encoded;
+
+ /** Hash a data element to an integer in the range [0, N * M). */
+ uint64_t HashToRange(const Element& element) const;
+
+ std::vector<uint64_t> BuildHashedSet(const ElementSet& elements) const;
+
+ /** Helper method used to implement Match and MatchAny */
+ bool MatchInternal(const uint64_t* sorted_element_hashes, size_t size) const;
+
+public:
+
+ /** Constructs an empty filter. */
+ GCSFilter(uint64_t siphash_k0 = 0, uint64_t siphash_k1 = 0, uint8_t P = 0, uint32_t M = 0);
+
+ /** Reconstructs an already-created filter from an encoding. */
+ GCSFilter(uint64_t siphash_k0, uint64_t siphash_k1, uint8_t P, uint32_t M,
+ std::vector<unsigned char> encoded_filter);
+
+ /** Builds a new filter from the params and set of elements. */
+ GCSFilter(uint64_t siphash_k0, uint64_t siphash_k1, uint8_t P, uint32_t M,
+ const ElementSet& elements);
+
+ uint8_t GetP() const { return m_P; }
+ uint32_t GetN() const { return m_N; }
+ uint32_t GetM() const { return m_M; }
+ const std::vector<unsigned char>& GetEncoded() const { return m_encoded; }
+
+ /**
+ * Checks if the element may be in the set. False positives are possible
+ * with probability 1/M.
+ */
+ bool Match(const Element& element) const;
+
+ /**
+ * Checks if any of the given elements may be in the set. False positives
+ * are possible with probability 1/M per element checked. This is more
+ * efficient that checking Match on multiple elements separately.
+ */
+ bool MatchAny(const ElementSet& elements) const;
+};
+
+constexpr uint8_t BASIC_FILTER_P = 19;
+constexpr uint32_t BASIC_FILTER_M = 784931;
+
+enum BlockFilterType : uint8_t
+{
+ BASIC = 0,
+};
+
+/**
+ * Complete block filter struct as defined in BIP 157. Serialization matches
+ * payload of "cfilter" messages.
+ */
+class BlockFilter
+{
+private:
+ BlockFilterType m_filter_type;
+ uint256 m_block_hash;
+ GCSFilter m_filter;
+
+public:
+
+ // Construct a new BlockFilter of the specified type from a block.
+ BlockFilter(BlockFilterType filter_type, const CBlock& block, const CBlockUndo& block_undo);
+
+ BlockFilterType GetFilterType() const { return m_filter_type; }
+
+ const GCSFilter& GetFilter() const { return m_filter; }
+
+ const std::vector<unsigned char>& GetEncodedFilter() const
+ {
+ return m_filter.GetEncoded();
+ }
+
+ // Compute the filter hash.
+ uint256 GetHash() const;
+
+ // Compute the filter header given the previous one.
+ uint256 ComputeHeader(const uint256& prev_header) const;
+
+ template <typename Stream>
+ void Serialize(Stream& s) const {
+ s << m_block_hash
+ << static_cast<uint8_t>(m_filter_type)
+ << m_filter.GetEncoded();
+ }
+
+ template <typename Stream>
+ void Unserialize(Stream& s) {
+ std::vector<unsigned char> encoded_filter;
+ uint8_t filter_type;
+
+ s >> m_block_hash
+ >> filter_type
+ >> encoded_filter;
+
+ m_filter_type = static_cast<BlockFilterType>(filter_type);
+
+ switch (m_filter_type) {
+ case BlockFilterType::BASIC:
+ m_filter = GCSFilter(m_block_hash.GetUint64(0), m_block_hash.GetUint64(1),
+ BASIC_FILTER_P, BASIC_FILTER_M, std::move(encoded_filter));
+ break;
+
+ default:
+ throw std::ios_base::failure("unknown filter_type");
+ }
+ }
+};
+
+#endif // BITCOIN_BLOCKFILTER_H
diff --git a/src/bloom.cpp b/src/bloom.cpp
index 94aae742f1..7732cee275 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -153,11 +153,11 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx)
insert(COutPoint(hash, i));
else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY)
{
- txnouttype type;
std::vector<std::vector<unsigned char> > vSolutions;
- if (Solver(txout.scriptPubKey, type, vSolutions) &&
- (type == TX_PUBKEY || type == TX_MULTISIG))
+ txnouttype type = Solver(txout.scriptPubKey, vSolutions);
+ if (type == TX_PUBKEY || type == TX_MULTISIG) {
insert(COutPoint(hash, i));
+ }
}
break;
}
diff --git a/src/core_write.cpp b/src/core_write.cpp
index 6331a3d880..55dcb1661d 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -141,8 +141,7 @@ void ScriptToUniv(const CScript& script, UniValue& out, bool include_address)
out.pushKV("hex", HexStr(script.begin(), script.end()));
std::vector<std::vector<unsigned char>> solns;
- txnouttype type;
- Solver(script, type, solns);
+ txnouttype type = Solver(script, solns);
out.pushKV("type", GetTxnOutputType(type));
CTxDestination address;
diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp
index 55a6f771e5..703c0811ac 100644
--- a/src/interfaces/wallet.cpp
+++ b/src/interfaces/wallet.cpp
@@ -57,7 +57,7 @@ public:
};
//! Construct wallet tx struct.
-WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
+static WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
WalletTx result;
result.tx = wtx.tx;
@@ -85,7 +85,7 @@ WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
}
//! Construct wallet tx status struct.
-WalletTxStatus MakeWalletTxStatus(const CWalletTx& wtx)
+static WalletTxStatus MakeWalletTxStatus(const CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
WalletTxStatus result;
auto mi = ::mapBlockIndex.find(wtx.hashBlock);
@@ -104,7 +104,7 @@ WalletTxStatus MakeWalletTxStatus(const CWalletTx& wtx)
}
//! Construct wallet TxOut struct.
-WalletTxOut MakeWalletTxOut(CWallet& wallet, const CWalletTx& wtx, int n, int depth)
+static WalletTxOut MakeWalletTxOut(CWallet& wallet, const CWalletTx& wtx, int n, int depth) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
WalletTxOut result;
result.txout = wtx.tx->vout[n];
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 88999ba735..a6a8814dff 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -442,7 +442,7 @@ static void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) EXCLUSIV
* lNodesAnnouncingHeaderAndIDs, and keeping that list under a certain size by
* removing the first element if necessary.
*/
-static void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman* connman)
+static void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman* connman) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(cs_main);
CNodeState* nodestate = State(nodeid);
@@ -831,7 +831,7 @@ void Misbehaving(NodeId pnode, int howmuch, const std::string& message) EXCLUSIV
// active chain if they are no more than a month older (both in time, and in
// best equivalent proof of work) than the best header chain we know about and
// we fully-validated them at some point.
-static bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Params& consensusParams)
+static bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(cs_main);
if (chainActive.Contains(pindex)) return true;
@@ -1260,7 +1260,7 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c
}
}
-void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnman* connman, const std::atomic<bool>& interruptMsgProc)
+void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnman* connman, const std::atomic<bool>& interruptMsgProc) LOCKS_EXCLUDED(cs_main)
{
AssertLockNotHeld(cs_main);
@@ -1618,8 +1618,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return true;
}
- else if (strCommand == NetMsgType::VERSION)
- {
+ if (strCommand == NetMsgType::VERSION) {
// Each connection can only send one version message
if (pfrom->nVersion != 0)
{
@@ -1662,8 +1661,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return false;
}
- if (nVersion < MIN_PEER_PROTO_VERSION)
- {
+ if (nVersion < MIN_PEER_PROTO_VERSION) {
// disconnect from peers older than this proto version
LogPrint(BCLog::NET, "peer=%d using obsolete version %i; disconnecting\n", pfrom->GetId(), nVersion);
if (enable_bip61) {
@@ -1674,8 +1672,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return false;
}
- if (nVersion == 10300)
- nVersion = 300;
if (!vRecv.empty())
vRecv >> addrFrom >> nNonce;
if (!vRecv.empty()) {
@@ -1796,9 +1792,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return true;
}
-
- else if (pfrom->nVersion == 0)
- {
+ if (pfrom->nVersion == 0) {
// Must have a version message before anything else
LOCK(cs_main);
Misbehaving(pfrom->GetId(), 1);
@@ -1842,18 +1836,17 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
}
pfrom->fSuccessfullyConnected = true;
+ return true;
}
- else if (!pfrom->fSuccessfullyConnected)
- {
+ if (!pfrom->fSuccessfullyConnected) {
// Must have a verack message before anything else
LOCK(cs_main);
Misbehaving(pfrom->GetId(), 1);
return false;
}
- else if (strCommand == NetMsgType::ADDR)
- {
+ if (strCommand == NetMsgType::ADDR) {
std::vector<CAddress> vAddr;
vRecv >> vAddr;
@@ -1900,16 +1893,16 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
pfrom->fGetAddr = false;
if (pfrom->fOneShot)
pfrom->fDisconnect = true;
+ return true;
}
- else if (strCommand == NetMsgType::SENDHEADERS)
- {
+ if (strCommand == NetMsgType::SENDHEADERS) {
LOCK(cs_main);
State(pfrom->GetId())->fPreferHeaders = true;
+ return true;
}
- else if (strCommand == NetMsgType::SENDCMPCT)
- {
+ if (strCommand == NetMsgType::SENDCMPCT) {
bool fAnnounceUsingCMPCTBLOCK = false;
uint64_t nCMPCTBLOCKVersion = 0;
vRecv >> fAnnounceUsingCMPCTBLOCK >> nCMPCTBLOCKVersion;
@@ -1929,11 +1922,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
State(pfrom->GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 1);
}
}
+ return true;
}
-
- else if (strCommand == NetMsgType::INV)
- {
+ if (strCommand == NetMsgType::INV) {
std::vector<CInv> vInv;
vRecv >> vInv;
if (vInv.size() > MAX_INV_SZ)
@@ -1987,11 +1979,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
}
}
}
+ return true;
}
-
- else if (strCommand == NetMsgType::GETDATA)
- {
+ if (strCommand == NetMsgType::GETDATA) {
std::vector<CInv> vInv;
vRecv >> vInv;
if (vInv.size() > MAX_INV_SZ)
@@ -2009,11 +2000,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end());
ProcessGetData(pfrom, chainparams, connman, interruptMsgProc);
+ return true;
}
-
- else if (strCommand == NetMsgType::GETBLOCKS)
- {
+ if (strCommand == NetMsgType::GETBLOCKS) {
CBlockLocator locator;
uint256 hashStop;
vRecv >> locator >> hashStop;
@@ -2078,11 +2068,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
break;
}
}
+ return true;
}
-
- else if (strCommand == NetMsgType::GETBLOCKTXN)
- {
+ if (strCommand == NetMsgType::GETBLOCKTXN) {
BlockTransactionsRequest req;
vRecv >> req;
@@ -2128,11 +2117,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
assert(ret);
SendBlockTransactions(block, req, pfrom, connman);
+ return true;
}
-
- else if (strCommand == NetMsgType::GETHEADERS)
- {
+ if (strCommand == NetMsgType::GETHEADERS) {
CBlockLocator locator;
uint256 hashStop;
vRecv >> locator >> hashStop;
@@ -2196,11 +2184,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// in the SendMessages logic.
nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip();
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders));
+ return true;
}
-
- else if (strCommand == NetMsgType::TX)
- {
+ if (strCommand == NetMsgType::TX) {
// Stop processing the transaction early if
// We are in blocks only mode and peer is either not whitelisted or whitelistrelay is off
if (!fRelayTxes && (!pfrom->fWhitelisted || !gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)))
@@ -2384,10 +2371,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
Misbehaving(pfrom->GetId(), nDoS);
}
}
+ return true;
}
-
- else if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
+ if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
{
CBlockHeaderAndShortTxIDs cmpctblock;
vRecv >> cmpctblock;
@@ -2605,10 +2592,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
MarkBlockAsReceived(pblock->GetHash());
}
}
-
+ return true;
}
- else if (strCommand == NetMsgType::BLOCKTXN && !fImporting && !fReindex) // Ignore blocks received while importing
+ if (strCommand == NetMsgType::BLOCKTXN && !fImporting && !fReindex) // Ignore blocks received while importing
{
BlockTransactions resp;
vRecv >> resp;
@@ -2680,10 +2667,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
mapBlockSource.erase(pblock->GetHash());
}
}
+ return true;
}
-
- else if (strCommand == NetMsgType::HEADERS && !fImporting && !fReindex) // Ignore headers received while importing
+ if (strCommand == NetMsgType::HEADERS && !fImporting && !fReindex) // Ignore headers received while importing
{
std::vector<CBlockHeader> headers;
@@ -2708,7 +2695,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return ProcessHeadersMessage(pfrom, connman, headers, chainparams, should_punish);
}
- else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
+ if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
{
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
vRecv >> *pblock;
@@ -2734,11 +2721,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
LOCK(cs_main);
mapBlockSource.erase(pblock->GetHash());
}
+ return true;
}
-
- else if (strCommand == NetMsgType::GETADDR)
- {
+ if (strCommand == NetMsgType::GETADDR) {
// This asymmetric behavior for inbound and outbound connections was introduced
// to prevent a fingerprinting attack: an attacker can send specific fake addresses
// to users' AddrMan and later request them by sending getaddr messages.
@@ -2762,11 +2748,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
FastRandomContext insecure_rand;
for (const CAddress &addr : vAddr)
pfrom->PushAddress(addr, insecure_rand);
+ return true;
}
-
- else if (strCommand == NetMsgType::MEMPOOL)
- {
+ if (strCommand == NetMsgType::MEMPOOL) {
if (!(pfrom->GetLocalServices() & NODE_BLOOM) && !pfrom->fWhitelisted)
{
LogPrint(BCLog::NET, "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom->GetId());
@@ -2783,11 +2768,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
LOCK(pfrom->cs_inventory);
pfrom->fSendMempool = true;
+ return true;
}
-
- else if (strCommand == NetMsgType::PING)
- {
+ if (strCommand == NetMsgType::PING) {
if (pfrom->nVersion > BIP0031_VERSION)
{
uint64_t nonce = 0;
@@ -2805,11 +2789,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// return very quickly.
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::PONG, nonce));
}
+ return true;
}
-
- else if (strCommand == NetMsgType::PONG)
- {
+ if (strCommand == NetMsgType::PONG) {
int64_t pingUsecEnd = nTimeReceived;
uint64_t nonce = 0;
size_t nAvail = vRecv.in_avail();
@@ -2862,11 +2845,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (bPingFinished) {
pfrom->nPingNonceSent = 0;
}
+ return true;
}
-
- else if (strCommand == NetMsgType::FILTERLOAD)
- {
+ if (strCommand == NetMsgType::FILTERLOAD) {
CBloomFilter filter;
vRecv >> filter;
@@ -2883,11 +2865,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
pfrom->pfilter->UpdateEmptyFull();
pfrom->fRelayTxes = true;
}
+ return true;
}
-
- else if (strCommand == NetMsgType::FILTERADD)
- {
+ if (strCommand == NetMsgType::FILTERADD) {
std::vector<unsigned char> vData;
vRecv >> vData;
@@ -2908,19 +2889,19 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
LOCK(cs_main);
Misbehaving(pfrom->GetId(), 100);
}
+ return true;
}
-
- else if (strCommand == NetMsgType::FILTERCLEAR)
- {
+ if (strCommand == NetMsgType::FILTERCLEAR) {
LOCK(pfrom->cs_filter);
if (pfrom->GetLocalServices() & NODE_BLOOM) {
pfrom->pfilter.reset(new CBloomFilter());
}
pfrom->fRelayTxes = true;
+ return true;
}
- else if (strCommand == NetMsgType::FEEFILTER) {
+ if (strCommand == NetMsgType::FEEFILTER) {
CAmount newFeeFilter = 0;
vRecv >> newFeeFilter;
if (MoneyRange(newFeeFilter)) {
@@ -2930,24 +2911,21 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
}
LogPrint(BCLog::NET, "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom->GetId());
}
+ return true;
}
- else if (strCommand == NetMsgType::NOTFOUND) {
+ if (strCommand == NetMsgType::NOTFOUND) {
// We do not care about the NOTFOUND message, but logging an Unknown Command
// message would be undesirable as we transmit it ourselves.
+ return true;
}
- else {
- // Ignore unknown commands for extensibility
- LogPrint(BCLog::NET, "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->GetId());
- }
-
-
-
+ // Ignore unknown commands for extensibility
+ LogPrint(BCLog::NET, "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->GetId());
return true;
}
-static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman* connman, bool enable_bip61)
+static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman* connman, bool enable_bip61) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(cs_main);
CNodeState &state = *State(pnode->GetId());
diff --git a/src/net_processing.h b/src/net_processing.h
index 7caefc80ca..f16d00032e 100644
--- a/src/net_processing.h
+++ b/src/net_processing.h
@@ -61,7 +61,7 @@ public:
bool SendMessages(CNode* pto) override EXCLUSIVE_LOCKS_REQUIRED(pto->cs_sendProcessing);
/** Consider evicting an outbound peer based on the amount of time they've been behind our tip */
- void ConsiderEviction(CNode *pto, int64_t time_in_seconds);
+ void ConsiderEviction(CNode *pto, int64_t time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Evict extra outbound peers. If we think our tip may be stale, connect to an extra outbound */
void CheckForStaleTipAndEvictPeers(const Consensus::Params &consensusParams);
/** If we have extra outbound peers, try to disconnect the one with the oldest block announcement */
diff --git a/src/noui.cpp b/src/noui.cpp
index e6d01e7b26..3a1ec2d050 100644
--- a/src/noui.cpp
+++ b/src/noui.cpp
@@ -12,6 +12,8 @@
#include <stdint.h>
#include <string>
+#include <boost/signals2/connection.hpp>
+
static bool noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style)
{
bool fSecure = style & CClientUIInterface::SECURE;
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index b8f7963a0c..47d6644551 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -57,11 +57,11 @@ bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
{
std::vector<std::vector<unsigned char> > vSolutions;
- if (!Solver(scriptPubKey, whichType, vSolutions))
- return false;
+ whichType = Solver(scriptPubKey, vSolutions);
- if (whichType == TX_MULTISIG)
- {
+ if (whichType == TX_NONSTANDARD || whichType == TX_WITNESS_UNKNOWN) {
+ return false;
+ } else if (whichType == TX_MULTISIG) {
unsigned char m = vSolutions.front()[0];
unsigned char n = vSolutions.back()[0];
// Support up to x-of-3 multisig txns as standard
@@ -70,10 +70,11 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
if (m < 1 || m > n)
return false;
} else if (whichType == TX_NULL_DATA &&
- (!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes))
+ (!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes)) {
return false;
+ }
- return whichType != TX_NONSTANDARD && whichType != TX_WITNESS_UNKNOWN;
+ return true;
}
bool IsStandardTx(const CTransaction& tx, std::string& reason)
@@ -166,14 +167,10 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
const CTxOut& prev = mapInputs.AccessCoin(tx.vin[i].prevout).out;
std::vector<std::vector<unsigned char> > vSolutions;
- txnouttype whichType;
- // get the scriptPubKey corresponding to this input:
- const CScript& prevScript = prev.scriptPubKey;
- if (!Solver(prevScript, whichType, vSolutions))
+ txnouttype whichType = Solver(prev.scriptPubKey, vSolutions);
+ if (whichType == TX_NONSTANDARD) {
return false;
-
- if (whichType == TX_SCRIPTHASH)
- {
+ } else if (whichType == TX_SCRIPTHASH) {
std::vector<std::vector<unsigned char> > stack;
// convert the scriptSig into a stack, so we can inspect the redeemScript
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SigVersion::BASE))
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 85fb88d338..712d20b71e 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -76,13 +76,10 @@ static void InitMessage(const std::string &message)
LogPrintf("init message: %s\n", message);
}
-/*
- Translate string to current locale using Qt.
- */
-static std::string Translate(const char* psz)
-{
+/** Translate string to current locale using Qt. */
+const std::function<std::string(const char*)> G_TRANSLATION_FUN = [](const char* psz) {
return QCoreApplication::translate("bitcoin-core", psz).toStdString();
-}
+};
static QString GetLangTerritory()
{
@@ -618,7 +615,6 @@ int main(int argc, char *argv[])
// Now that QSettings are accessible, initialize translations
QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator;
initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator);
- translationInterface.Translate.connect(Translate);
// Show help message immediately after parsing command-line options (for "-lang") and setting locale,
// but before showing splash screen.
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index cefa9004ed..5321cd94fd 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -57,6 +57,8 @@
#include <QUrlQuery>
#include <QVBoxLayout>
+#include <boost/bind.hpp>
+
const std::string BitcoinGUI::DEFAULT_UIPLATFORM =
#if defined(Q_OS_MAC)
"macosx"
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index e438d22919..0b111cc6d7 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -14,8 +14,8 @@
#include <interfaces/handler.h>
#include <interfaces/node.h>
#include <interfaces/wallet.h>
-#include <util.h>
#include <ui_interface.h>
+#include <util.h>
#include <version.h>
#include <QApplication>
@@ -24,6 +24,8 @@
#include <QPainter>
#include <QRadialGradient>
+#include <boost/bind.hpp>
+
SplashScreen::SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const NetworkStyle *networkStyle) :
QWidget(0, f), curAlignment(0), m_node(node)
{
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index e379b70553..4fa941b630 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -16,10 +16,10 @@
#include <core_io.h>
#include <interfaces/handler.h>
#include <interfaces/node.h>
-#include <validation.h>
#include <sync.h>
#include <uint256.h>
#include <util.h>
+#include <validation.h>
#include <QColor>
#include <QDateTime>
@@ -27,6 +27,8 @@
#include <QIcon>
#include <QList>
+#include <boost/bind.hpp>
+
// Amount column is right-aligned it contains numbers
static int column_alignments[] = {
Qt::AlignLeft|Qt::AlignVCenter, /* status */
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 51bc218d39..a77fea8ea8 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -18,6 +18,7 @@
#include <key_io.h>
#include <policy/feerate.h>
#include <policy/policy.h>
+#include <policy/rbf.h>
#include <primitives/transaction.h>
#include <rpc/server.h>
#include <script/descriptor.h>
@@ -379,7 +380,8 @@ static std::string EntryDescriptionString()
" ... ]\n"
" \"spentby\" : [ (array) unconfirmed transactions spending outputs from this transaction\n"
" \"transactionid\", (string) child transaction id\n"
- " ... ]\n";
+ " ... ]\n"
+ " \"bip125-replaceable\" : true|false, (boolean) Whether this transaction could be replaced due to BIP125 (replace-by-fee)\n";
}
static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) EXCLUSIVE_LOCKS_REQUIRED(::mempool.cs)
@@ -429,6 +431,17 @@ static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) EXCLUSIVE_LOCK
}
info.pushKV("spentby", spent);
+
+ // Add opt-in RBF status
+ bool rbfStatus = false;
+ RBFTransactionState rbfState = IsRBFOptIn(tx, mempool);
+ if (rbfState == RBFTransactionState::UNKNOWN) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Transaction is not in mempool");
+ } else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125) {
+ rbfStatus = true;
+ }
+
+ info.pushKV("bip125-replaceable", rbfStatus);
}
UniValue mempoolToJSON(bool fVerbose)
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 314184ab06..7ca097f8cf 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -562,7 +562,6 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request)
+ HelpExampleRpc("decoderawtransaction", "\"hexstring\"")
);
- LOCK(cs_main);
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL});
CMutableTransaction mtx;
@@ -627,9 +626,8 @@ static UniValue decodescript(const JSONRPCRequest& request)
// P2SH and witness programs cannot be wrapped in P2WSH, if this script
// is a witness program, don't return addresses for a segwit programs.
if (type.get_str() == "pubkey" || type.get_str() == "pubkeyhash" || type.get_str() == "multisig" || type.get_str() == "nonstandard") {
- txnouttype which_type;
std::vector<std::vector<unsigned char>> solutions_data;
- Solver(script, which_type, solutions_data);
+ txnouttype which_type = Solver(script, solutions_data);
// Uncompressed pubkeys cannot be used with segwit checksigs.
// If the script contains an uncompressed pubkey, skip encoding of a segwit program.
if ((which_type == TX_PUBKEY) || (which_type == TX_MULTISIG)) {
diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp
index e3a6278c75..1433ebf42f 100644
--- a/src/script/ismine.cpp
+++ b/src/script/ismine.cpp
@@ -60,8 +60,7 @@ IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey,
IsMineResult ret = IsMineResult::NO;
std::vector<valtype> vSolutions;
- txnouttype whichType;
- Solver(scriptPubKey, whichType, vSolutions);
+ txnouttype whichType = Solver(scriptPubKey, vSolutions);
CKeyID keyID;
switch (whichType)
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 1982e8a832..23af1bd97f 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -101,8 +101,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
std::vector<unsigned char> sig;
std::vector<valtype> vSolutions;
- if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
- return false;
+ whichTypeRet = Solver(scriptPubKey, vSolutions);
switch (whichTypeRet)
{
@@ -329,9 +328,8 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI
}
// Get scripts
- txnouttype script_type;
std::vector<std::vector<unsigned char>> solutions;
- Solver(txout.scriptPubKey, script_type, solutions);
+ txnouttype script_type = Solver(txout.scriptPubKey, solutions);
SigVersion sigversion = SigVersion::BASE;
CScript next_script = txout.scriptPubKey;
@@ -342,7 +340,7 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI
next_script = std::move(redeem_script);
// Get redeemScript type
- Solver(next_script, script_type, solutions);
+ script_type = Solver(next_script, solutions);
stack.script.pop_back();
}
if (script_type == TX_WITNESS_V0_SCRIPTHASH && !stack.witness.empty() && !stack.witness.back().empty()) {
@@ -352,7 +350,7 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI
next_script = std::move(witness_script);
// Get witnessScript type
- Solver(next_script, script_type, solutions);
+ script_type = Solver(next_script, solutions);
stack.witness.pop_back();
stack.script = std::move(stack.witness);
stack.witness.clear();
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index bfbf9f13db..08ba1b1e0f 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -87,7 +87,7 @@ static bool MatchMultisig(const CScript& script, unsigned int& required, std::ve
return (it + 1 == script.end());
}
-bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet)
+txnouttype Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned char>>& vSolutionsRet)
{
vSolutionsRet.clear();
@@ -95,33 +95,28 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::v
// it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
if (scriptPubKey.IsPayToScriptHash())
{
- typeRet = TX_SCRIPTHASH;
std::vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
vSolutionsRet.push_back(hashBytes);
- return true;
+ return TX_SCRIPTHASH;
}
int witnessversion;
std::vector<unsigned char> witnessprogram;
if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_KEYHASH_SIZE) {
- typeRet = TX_WITNESS_V0_KEYHASH;
vSolutionsRet.push_back(witnessprogram);
- return true;
+ return TX_WITNESS_V0_KEYHASH;
}
if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
- typeRet = TX_WITNESS_V0_SCRIPTHASH;
vSolutionsRet.push_back(witnessprogram);
- return true;
+ return TX_WITNESS_V0_SCRIPTHASH;
}
if (witnessversion != 0) {
- typeRet = TX_WITNESS_UNKNOWN;
vSolutionsRet.push_back(std::vector<unsigned char>{(unsigned char)witnessversion});
vSolutionsRet.push_back(std::move(witnessprogram));
- return true;
+ return TX_WITNESS_UNKNOWN;
}
- typeRet = TX_NONSTANDARD;
- return false;
+ return TX_NONSTANDARD;
}
// Provably prunable, data-carrying output
@@ -130,47 +125,39 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::v
// byte passes the IsPushOnly() test we don't care what exactly is in the
// script.
if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) {
- typeRet = TX_NULL_DATA;
- return true;
+ return TX_NULL_DATA;
}
std::vector<unsigned char> data;
if (MatchPayToPubkey(scriptPubKey, data)) {
- typeRet = TX_PUBKEY;
vSolutionsRet.push_back(std::move(data));
- return true;
+ return TX_PUBKEY;
}
if (MatchPayToPubkeyHash(scriptPubKey, data)) {
- typeRet = TX_PUBKEYHASH;
vSolutionsRet.push_back(std::move(data));
- return true;
+ return TX_PUBKEYHASH;
}
unsigned int required;
std::vector<std::vector<unsigned char>> keys;
if (MatchMultisig(scriptPubKey, required, keys)) {
- typeRet = TX_MULTISIG;
vSolutionsRet.push_back({static_cast<unsigned char>(required)}); // safe as required is in range 1..16
vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end());
vSolutionsRet.push_back({static_cast<unsigned char>(keys.size())}); // safe as size is in range 1..16
- return true;
+ return TX_MULTISIG;
}
vSolutionsRet.clear();
- typeRet = TX_NONSTANDARD;
- return false;
+ return TX_NONSTANDARD;
}
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
{
std::vector<valtype> vSolutions;
- txnouttype whichType;
- if (!Solver(scriptPubKey, whichType, vSolutions))
- return false;
+ txnouttype whichType = Solver(scriptPubKey, vSolutions);
- if (whichType == TX_PUBKEY)
- {
+ if (whichType == TX_PUBKEY) {
CPubKey pubKey(vSolutions[0]);
if (!pubKey.IsValid())
return false;
@@ -212,11 +199,11 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet)
{
addressRet.clear();
- typeRet = TX_NONSTANDARD;
std::vector<valtype> vSolutions;
- if (!Solver(scriptPubKey, typeRet, vSolutions))
+ typeRet = Solver(scriptPubKey, vSolutions);
+ if (typeRet == TX_NONSTANDARD) {
return false;
- if (typeRet == TX_NULL_DATA){
+ } else if (typeRet == TX_NULL_DATA) {
// This is data, not addresses
return false;
}
@@ -324,14 +311,12 @@ CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
CScript GetScriptForWitness(const CScript& redeemscript)
{
- txnouttype typ;
std::vector<std::vector<unsigned char> > vSolutions;
- if (Solver(redeemscript, typ, vSolutions)) {
- if (typ == TX_PUBKEY) {
- return GetScriptForDestination(WitnessV0KeyHash(Hash160(vSolutions[0].begin(), vSolutions[0].end())));
- } else if (typ == TX_PUBKEYHASH) {
- return GetScriptForDestination(WitnessV0KeyHash(vSolutions[0]));
- }
+ txnouttype typ = Solver(redeemscript, vSolutions);
+ if (typ == TX_PUBKEY) {
+ return GetScriptForDestination(WitnessV0KeyHash(Hash160(vSolutions[0].begin(), vSolutions[0].end())));
+ } else if (typ == TX_PUBKEYHASH) {
+ return GetScriptForDestination(WitnessV0KeyHash(vSolutions[0]));
}
return GetScriptForDestination(WitnessV0ScriptHash(redeemscript));
}
diff --git a/src/script/standard.h b/src/script/standard.h
index b16ac83e77..fc20fb6a08 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -135,11 +135,10 @@ const char* GetTxnOutputType(txnouttype t);
* script hash, for P2PKH it will contain the key hash, etc.
*
* @param[in] scriptPubKey Script to parse
- * @param[out] typeRet The script type
* @param[out] vSolutionsRet Vector of parsed pubkeys and hashes
- * @return True if script matches standard template
+ * @return The script type. TX_NONSTANDARD represents a failed solve.
*/
-bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
+txnouttype Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned char>>& vSolutionsRet);
/**
* Parse a standard scriptPubKey for the destination address. Assigns result to
diff --git a/src/streams.h b/src/streams.h
index 096ebfc9c2..d4a309be3c 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -139,6 +139,80 @@ private:
size_t nPos;
};
+/** Minimal stream for reading from an existing vector by reference
+ */
+class VectorReader
+{
+private:
+ const int m_type;
+ const int m_version;
+ const std::vector<unsigned char>& m_data;
+ size_t m_pos = 0;
+
+public:
+
+ /*
+ * @param[in] type Serialization Type
+ * @param[in] version Serialization Version (including any flags)
+ * @param[in] data Referenced byte vector to overwrite/append
+ * @param[in] pos Starting position. Vector index where reads should start.
+ */
+ VectorReader(int type, int version, const std::vector<unsigned char>& data, size_t pos)
+ : m_type(type), m_version(version), m_data(data)
+ {
+ seek(pos);
+ }
+
+ /*
+ * (other params same as above)
+ * @param[in] args A list of items to deserialize starting at pos.
+ */
+ template <typename... Args>
+ VectorReader(int type, int version, const std::vector<unsigned char>& data, size_t pos,
+ Args&&... args)
+ : VectorReader(type, version, data, pos)
+ {
+ ::UnserializeMany(*this, std::forward<Args>(args)...);
+ }
+
+ template<typename T>
+ VectorReader& operator>>(T& obj)
+ {
+ // Unserialize from this stream
+ ::Unserialize(*this, obj);
+ return (*this);
+ }
+
+ int GetVersion() const { return m_version; }
+ int GetType() const { return m_type; }
+
+ size_t size() const { return m_data.size() - m_pos; }
+ bool empty() const { return m_data.size() == m_pos; }
+
+ void read(char* dst, size_t n)
+ {
+ if (n == 0) {
+ return;
+ }
+
+ // Read from the beginning of the buffer
+ size_t pos_next = m_pos + n;
+ if (pos_next > m_data.size()) {
+ throw std::ios_base::failure("VectorReader::read(): end of data");
+ }
+ memcpy(dst, m_data.data() + m_pos, n);
+ m_pos = pos_next;
+ }
+
+ void seek(size_t n)
+ {
+ m_pos += n;
+ if (m_pos > m_data.size()) {
+ throw std::ios_base::failure("VectorReader::seek(): end of data");
+ }
+ }
+};
+
/** Double ended buffer combining vector and stream-like interfaces.
*
* >> and << read and write unformatted data using the above serialization templates.
@@ -436,12 +510,105 @@ public:
}
};
+template <typename IStream>
+class BitStreamReader
+{
+private:
+ IStream& m_istream;
+
+ /// Buffered byte read in from the input stream. A new byte is read into the
+ /// buffer when m_offset reaches 8.
+ uint8_t m_buffer{0};
+
+ /// Number of high order bits in m_buffer already returned by previous
+ /// Read() calls. The next bit to be returned is at this offset from the
+ /// most significant bit position.
+ int m_offset{8};
+
+public:
+ explicit BitStreamReader(IStream& istream) : m_istream(istream) {}
+
+ /** Read the specified number of bits from the stream. The data is returned
+ * in the nbits least signficant bits of a 64-bit uint.
+ */
+ uint64_t Read(int nbits) {
+ if (nbits < 0 || nbits > 64) {
+ throw std::out_of_range("nbits must be between 0 and 64");
+ }
+
+ uint64_t data = 0;
+ while (nbits > 0) {
+ if (m_offset == 8) {
+ m_istream >> m_buffer;
+ m_offset = 0;
+ }
+ int bits = std::min(8 - m_offset, nbits);
+ data <<= bits;
+ data |= static_cast<uint8_t>(m_buffer << m_offset) >> (8 - bits);
+ m_offset += bits;
+ nbits -= bits;
+ }
+ return data;
+ }
+};
+template <typename OStream>
+class BitStreamWriter
+{
+private:
+ OStream& m_ostream;
+ /// Buffered byte waiting to be written to the output stream. The byte is
+ /// written buffer when m_offset reaches 8 or Flush() is called.
+ uint8_t m_buffer{0};
+ /// Number of high order bits in m_buffer already written by previous
+ /// Write() calls and not yet flushed to the stream. The next bit to be
+ /// written to is at this offset from the most significant bit position.
+ int m_offset{0};
+public:
+ explicit BitStreamWriter(OStream& ostream) : m_ostream(ostream) {}
+ ~BitStreamWriter()
+ {
+ Flush();
+ }
+
+ /** Write the nbits least significant bits of a 64-bit int to the output
+ * stream. Data is buffered until it completes an octet.
+ */
+ void Write(uint64_t data, int nbits) {
+ if (nbits < 0 || nbits > 64) {
+ throw std::out_of_range("nbits must be between 0 and 64");
+ }
+
+ while (nbits > 0) {
+ int bits = std::min(8 - m_offset, nbits);
+ m_buffer |= (data << (64 - nbits)) >> (64 - 8 + m_offset);
+ m_offset += bits;
+ nbits -= bits;
+
+ if (m_offset == 8) {
+ Flush();
+ }
+ }
+ }
+
+ /** Flush any unwritten bits to the output stream, padding with 0's to the
+ * next byte boundary.
+ */
+ void Flush() {
+ if (m_offset == 0) {
+ return;
+ }
+
+ m_ostream << m_buffer;
+ m_buffer = 0;
+ m_offset = 0;
+ }
+};
diff --git a/src/test/blockfilter_tests.cpp b/src/test/blockfilter_tests.cpp
new file mode 100644
index 0000000000..e3cb05f09e
--- /dev/null
+++ b/src/test/blockfilter_tests.cpp
@@ -0,0 +1,142 @@
+// Copyright (c) 2018 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <test/data/blockfilters.json.h>
+#include <test/test_bitcoin.h>
+
+#include <blockfilter.h>
+#include <core_io.h>
+#include <serialize.h>
+#include <streams.h>
+#include <univalue.h>
+#include <utilstrencodings.h>
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_AUTO_TEST_SUITE(blockfilter_tests)
+
+BOOST_AUTO_TEST_CASE(gcsfilter_test)
+{
+ GCSFilter::ElementSet included_elements, excluded_elements;
+ for (int i = 0; i < 100; ++i) {
+ GCSFilter::Element element1(32);
+ element1[0] = i;
+ included_elements.insert(std::move(element1));
+
+ GCSFilter::Element element2(32);
+ element2[1] = i;
+ excluded_elements.insert(std::move(element2));
+ }
+
+ GCSFilter filter(0, 0, 10, 1 << 10, included_elements);
+ for (const auto& element : included_elements) {
+ BOOST_CHECK(filter.Match(element));
+
+ auto insertion = excluded_elements.insert(element);
+ BOOST_CHECK(filter.MatchAny(excluded_elements));
+ excluded_elements.erase(insertion.first);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(blockfilter_basic_test)
+{
+ CScript included_scripts[5], excluded_scripts[2];
+
+ // First two are outputs on a single transaction.
+ included_scripts[0] << std::vector<unsigned char>(0, 65) << OP_CHECKSIG;
+ included_scripts[1] << OP_DUP << OP_HASH160 << std::vector<unsigned char>(1, 20) << OP_EQUALVERIFY << OP_CHECKSIG;
+
+ // Third is an output on in a second transaction.
+ included_scripts[2] << OP_1 << std::vector<unsigned char>(2, 33) << OP_1 << OP_CHECKMULTISIG;
+
+ // Last two are spent by a single transaction.
+ included_scripts[3] << OP_0 << std::vector<unsigned char>(3, 32);
+ included_scripts[4] << OP_4 << OP_ADD << OP_8 << OP_EQUAL;
+
+ // OP_RETURN output is an output on the second transaction.
+ excluded_scripts[0] << OP_RETURN << std::vector<unsigned char>(4, 40);
+
+ // This script is not related to the block at all.
+ excluded_scripts[1] << std::vector<unsigned char>(5, 33) << OP_CHECKSIG;
+
+ CMutableTransaction tx_1;
+ tx_1.vout.emplace_back(100, included_scripts[0]);
+ tx_1.vout.emplace_back(200, included_scripts[1]);
+
+ CMutableTransaction tx_2;
+ tx_2.vout.emplace_back(300, included_scripts[2]);
+ tx_2.vout.emplace_back(0, excluded_scripts[0]);
+
+ CBlock block;
+ block.vtx.push_back(MakeTransactionRef(tx_1));
+ block.vtx.push_back(MakeTransactionRef(tx_2));
+
+ CBlockUndo block_undo;
+ block_undo.vtxundo.emplace_back();
+ block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(400, included_scripts[3]), 1000, true);
+ block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(500, included_scripts[4]), 10000, false);
+
+ BlockFilter block_filter(BlockFilterType::BASIC, block, block_undo);
+ const GCSFilter& filter = block_filter.GetFilter();
+
+ for (const CScript& script : included_scripts) {
+ BOOST_CHECK(filter.Match(GCSFilter::Element(script.begin(), script.end())));
+ }
+ for (const CScript& script : excluded_scripts) {
+ BOOST_CHECK(!filter.Match(GCSFilter::Element(script.begin(), script.end())));
+ }
+}
+
+BOOST_AUTO_TEST_CASE(blockfilters_json_test)
+{
+ UniValue json;
+ std::string json_data(json_tests::blockfilters,
+ json_tests::blockfilters + sizeof(json_tests::blockfilters));
+ if (!json.read(json_data) || !json.isArray()) {
+ BOOST_ERROR("Parse error.");
+ return;
+ }
+
+ const UniValue& tests = json.get_array();
+ for (unsigned int i = 0; i < tests.size(); i++) {
+ UniValue test = tests[i];
+ std::string strTest = test.write();
+
+ if (test.size() == 1) {
+ continue;
+ } else if (test.size() < 7) {
+ BOOST_ERROR("Bad test: " << strTest);
+ continue;
+ }
+
+ unsigned int pos = 0;
+ /*int block_height =*/ test[pos++].get_int();
+ /*uint256 block_hash =*/ ParseHashStr(test[pos++].get_str(), "block_hash");
+
+ CBlock block;
+ BOOST_REQUIRE(DecodeHexBlk(block, test[pos++].get_str()));
+
+ CBlockUndo block_undo;
+ block_undo.vtxundo.emplace_back();
+ CTxUndo& tx_undo = block_undo.vtxundo.back();
+ const UniValue& prev_scripts = test[pos++].get_array();
+ for (unsigned int ii = 0; ii < prev_scripts.size(); ii++) {
+ std::vector<unsigned char> raw_script = ParseHex(prev_scripts[ii].get_str());
+ CTxOut txout(0, CScript(raw_script.begin(), raw_script.end()));
+ tx_undo.vprevout.emplace_back(txout, 0, false);
+ }
+
+ uint256 prev_filter_header_basic = ParseHashStr(test[pos++].get_str(), "prev_filter_header_basic");
+ std::vector<unsigned char> filter_basic = ParseHex(test[pos++].get_str());
+ uint256 filter_header_basic = ParseHashStr(test[pos++].get_str(), "filter_header_basic");
+
+ BlockFilter computed_filter_basic(BlockFilterType::BASIC, block, block_undo);
+ BOOST_CHECK(computed_filter_basic.GetFilter().GetEncoded() == filter_basic);
+
+ uint256 computed_header_basic = computed_filter_basic.ComputeHeader(prev_filter_header_basic);
+ BOOST_CHECK(computed_header_basic == filter_header_basic);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/data/blockfilters.json b/src/test/data/blockfilters.json
new file mode 100644
index 0000000000..2f00728ff6
--- /dev/null
+++ b/src/test/data/blockfilters.json
@@ -0,0 +1,9 @@
+[
+["Block Height,Block Hash,Block,[Prev Output Scripts for Block],Previous Basic Header,Basic Filter,Basic Header,Notes"],
+[0,"000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943","0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff001d1aa4ae180101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000",[],"0000000000000000000000000000000000000000000000000000000000000000","019dfca8","21584579b7eb08997773e5aeff3a7f932700042d0ed2a6129012b7d7ae81b750","Genesis block"],
+[2,"000000006c02c8ea6e4ff69651f7fcde348fb9d557a06e6957b65552002a7820","0100000006128e87be8b1b4dea47a7247d5528d2702c96826c7a648497e773b800000000e241352e3bec0a95a6217e10c3abb54adfa05abb12c126695595580fb92e222032e7494dffff001d00d235340101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0432e7494d010e062f503253482fffffffff0100f2052a010000002321038a7f6ef1c8ca0c588aa53fa860128077c9e6c11e6830f4d7ee4e763a56b7718fac00000000",[],"d7bdac13a59d745b1add0d2ce852f1a0442e8945fc1bf3848d3cbffd88c24fe1","0174a170","186afd11ef2b5e7e3504f2e8cbf8df28a1fd251fe53d60dff8b1467d1b386cf0",""],
+[3,"000000008b896e272758da5297bcd98fdc6d97c9b765ecec401e286dc1fdbe10","0100000020782a005255b657696ea057d5b98f34defcf75196f64f6eeac8026c0000000041ba5afc532aae03151b8aa87b65e1594f97504a768e010c98c0add79216247186e7494dffff001d058dc2b60101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0486e7494d0151062f503253482fffffffff0100f2052a01000000232103f6d9ff4c12959445ca5549c811683bf9c88e637b222dd2e0311154c4c85cf423ac00000000",[],"186afd11ef2b5e7e3504f2e8cbf8df28a1fd251fe53d60dff8b1467d1b386cf0","016cf7a0","8d63aadf5ab7257cb6d2316a57b16f517bff1c6388f124ec4c04af1212729d2a",""],
+[926485,"000000000000015d6077a411a8f5cc95caf775ccf11c54e27df75ce58d187313","0000002060bbab0edbf3ef8a49608ee326f8fd75c473b7e3982095e2d100000000000000c30134f8c9b6d2470488d7a67a888f6fa12f8692e0c3411fbfb92f0f68f67eedae03ca57ef13021acc22dc4105010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff2f0315230e0004ae03ca57043e3d1e1d0c8796bf579aef0c0000000000122f4e696e6a61506f6f6c2f5345475749542fffffffff038427a112000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9ed5c748e121c0fe146d973a4ac26fa4a68b0549d46ee22d25f50a5e46fe1b377ee00000000000000002952534b424c4f434b3acd16772ad61a3c5f00287480b720f6035d5e54c9efc71be94bb5e3727f10909001200000000000000000000000000000000000000000000000000000000000000000000000000100000000010145310e878941a1b2bc2d33797ee4d89d95eaaf2e13488063a2aa9a74490f510a0100000023220020b6744de4f6ec63cc92f7c220cdefeeb1b1bed2b66c8e5706d80ec247d37e65a1ffffffff01002d3101000000001976a9143ebc40e411ed3c76f86711507ab952300890397288ac0400473044022001dd489a5d4e2fbd8a3ade27177f6b49296ba7695c40dbbe650ea83f106415fd02200b23a0602d8ff1bdf79dee118205fc7e9b40672bf31563e5741feb53fb86388501483045022100f88f040e90cc5dc6c6189d04718376ac19ed996bf9e4a3c29c3718d90ffd27180220761711f16c9e3a44f71aab55cbc0634907a1fa8bb635d971a9a01d368727bea10169522103b3623117e988b76aaabe3d63f56a4fc88b228a71e64c4cc551d1204822fe85cb2103dd823066e096f72ed617a41d3ca56717db335b1ea47a1b4c5c9dbdd0963acba621033d7c89bd9da29fa8d44db7906a9778b53121f72191184a9fee785c39180e4be153ae00000000010000000120925534261de4dcebb1ed5ab1b62bfe7a3ef968fb111dc2c910adfebc6e3bdf010000006b483045022100f50198f5ae66211a4f485190abe4dc7accdabe3bc214ebc9ea7069b97097d46e0220316a70a03014887086e335fc1b48358d46cd6bdc9af3b57c109c94af76fc915101210316cff587a01a2736d5e12e53551b18d73780b83c3bfb4fcf209c869b11b6415effffffff0220a10700000000001976a91450333046115eaa0ac9e0216565f945070e44573988ac2e7cd01a000000001976a914c01a7ca16b47be50cbdbc60724f701d52d75156688ac00000000010000000203a25f58630d7a1ea52550365fd2156683f56daf6ca73a4b4bbd097e66516322010000006a47304402204efc3d70e4ca3049c2a425025edf22d5ca355f9ec899dbfbbeeb2268533a0f2b02204780d3739653035af4814ea52e1396d021953f948c29754edd0ee537364603dc012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff03a25f58630d7a1ea52550365fd2156683f56daf6ca73a4b4bbd097e66516322000000006a47304402202d96defdc5b4af71d6ba28c9a6042c2d5ee7bc6de565d4db84ef517445626e03022022da80320e9e489c8f41b74833dfb6a54a4eb5087cdb46eb663eef0b25caa526012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff0200e1f5050000000017a914b7e6f7ff8658b2d1fb107e3d7be7af4742e6b1b3876f88fc00000000001976a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac0000000001000000043ffd60d3818431c495b89be84afac205d5d1ed663009291c560758bbd0a66df5010000006b483045022100f344607de9df42049688dcae8ff1db34c0c7cd25ec05516e30d2bc8f12ac9b2f022060b648f6a21745ea6d9782e17bcc4277b5808326488a1f40d41e125879723d3a012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffffa5379401cce30f84731ef1ba65ce27edf2cc7ce57704507ebe8714aa16a96b92010000006a473044022020c37a63bf4d7f564c2192528709b6a38ab8271bd96898c6c2e335e5208661580220435c6f1ad4d9305d2c0a818b2feb5e45d443f2f162c0f61953a14d097fd07064012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff70e731e193235ff12c3184510895731a099112ffca4b00246c60003c40f843ce000000006a473044022053760f74c29a879e30a17b5f03a5bb057a5751a39f86fa6ecdedc36a1b7db04c022041d41c9b95f00d2d10a0373322a9025dba66c942196bc9d8adeb0e12d3024728012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff66b7a71b3e50379c8e85fc18fe3f1a408fc985f257036c34702ba205cef09f6f000000006a4730440220499bf9e2db3db6e930228d0661395f65431acae466634d098612fd80b08459ee022040e069fc9e3c60009f521cef54c38aadbd1251aee37940e6018aadb10f194d6a012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff0200e1f5050000000017a9148fc37ad460fdfbd2b44fe446f6e3071a4f64faa6878f447f0b000000001976a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac00000000",["a914feb8a29635c56d9cd913122f90678756bf23887687","76a914c01a7ca16b47be50cbdbc60724f701d52d75156688ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac"],"da49977ba1ee0d620a2c4f8f646b03cd0d230f5c6c994722e3ba884889f0be1a","09027acea61b6cc3fb33f5d52f7d088a6b2f75d234e89ca800","4cd9dd007a325199102f1fc0b7d77ca25ee3c84d46018c4353ecfcb56c0d3e7a","Duplicate pushdata 913bcc2be49cb534c20474c4dee1e9c4c317e7eb"],
+[987876,"0000000000000c00901f2049055e2a437c819d79a3d54fd63e6af796cd7b8a79","000000202694f74969fdb542090e95a56bc8aa2d646e27033850e32f1c5f000000000000f7e53676b3f12d5beb524ed617f2d25f5a93b5f4f52c1ba2678260d72712f8dd0a6dfe5740257e1a4b1768960101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff1603e4120ff9c30a1c216900002f424d4920546573742fffffff0001205fa012000000001e76a914c486de584a735ec2f22da7cd9681614681f92173d83d0aa68688ac00000000",[],"e9d729b72d533c29abe5276d5cf6c152f3723f10efe000b1e0c9ca5265a8beb6","010c0b40","e6137ae5a8424c40da1e5023c16975cc97b09300b4c050e6b1c713add3836c40","Coinbase tx has unparseable output script"],
+[1263442,"000000006f27ddfe1dd680044a34548f41bed47eba9e6f0b310da21423bc5f33","000000201c8d1a529c39a396db2db234d5ec152fa651a2872966daccbde028b400000000083f14492679151dbfaa1a825ef4c18518e780c1f91044180280a7d33f4a98ff5f45765aaddc001d38333b9a02010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff230352471300fe5f45765afe94690a000963676d696e6572343208000000000000000000ffffffff024423a804000000001976a914f2c25ac3d59f3d674b1d1d0a25c27339aaac0ba688ac0000000000000000266a24aa21a9edcb26cb3052426b9ebb4d19c819ef87c19677bbf3a7c46ef0855bd1b2abe83491012000000000000000000000000000000000000000000000000000000000000000000000000002000000000101d20978463906ba4ff5e7192494b88dd5eb0de85d900ab253af909106faa22cc5010000000004000000014777ff000000000016001446c29eabe8208a33aa1023c741fa79aa92e881ff0347304402207d7ca96134f2bcfdd6b536536fdd39ad17793632016936f777ebb32c22943fda02206014d2fb8a6aa58279797f861042ba604ebd2f8f61e5bddbd9d3be5a245047b201004b632103eeaeba7ce5dc2470221e9517fb498e8d6bd4e73b85b8be655196972eb9ccd5566754b2752103a40b74d43df244799d041f32ce1ad515a6cd99501701540e38750d883ae21d3a68ac00000000",["002027a5000c7917f785d8fc6e5a55adfca8717ecb973ebb7743849ff956d896a7ed"],"a4a4d6c6034da8aa06f01fe71f1fffbd79e032006b07f6c7a2c60a66aa310c01","0385acb4f0fe889ef0","3588f34fbbc11640f9ed40b2a66a4e096215d50389691309c1dac74d4268aa81","Includes witness data"]
+]
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 2da06b8d31..2b9641b6d4 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -90,7 +90,7 @@ static CBlockIndex CreateBlockIndex(int nHeight)
return index;
}
-static bool TestSequenceLocks(const CTransaction &tx, int flags)
+static bool TestSequenceLocks(const CTransaction &tx, int flags) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
LOCK(mempool.cs);
return CheckSequenceLocks(tx, flags);
diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp
index 001d8eb64b..2af0ab22da 100644
--- a/src/test/scheduler_tests.cpp
+++ b/src/test/scheduler_tests.cpp
@@ -138,11 +138,11 @@ BOOST_AUTO_TEST_CASE(singlethreadedscheduler_ordered)
// the callbacks should run in exactly the order in which they were enqueued
for (int i = 0; i < 100; ++i) {
queue1.AddToProcessQueue([i, &counter1]() {
- BOOST_CHECK_EQUAL(i, counter1++);
+ assert(i == counter1++);
});
queue2.AddToProcessQueue([i, &counter2]() {
- BOOST_CHECK_EQUAL(i, counter2++);
+ assert(i == counter2++);
});
}
diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp
index bf57272ab2..b3e4b12918 100644
--- a/src/test/script_standard_tests.cpp
+++ b/src/test/script_standard_tests.cpp
@@ -25,22 +25,19 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
}
CScript s;
- txnouttype whichType;
std::vector<std::vector<unsigned char> > solutions;
// TX_PUBKEY
s.clear();
s << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK_EQUAL(whichType, TX_PUBKEY);
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_PUBKEY);
BOOST_CHECK_EQUAL(solutions.size(), 1U);
BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0]));
// TX_PUBKEYHASH
s.clear();
s << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK_EQUAL(whichType, TX_PUBKEYHASH);
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_PUBKEYHASH);
BOOST_CHECK_EQUAL(solutions.size(), 1U);
BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID()));
@@ -48,8 +45,7 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
CScript redeemScript(s); // initialize with leftover P2PKH script
s.clear();
s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK_EQUAL(whichType, TX_SCRIPTHASH);
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_SCRIPTHASH);
BOOST_CHECK_EQUAL(solutions.size(), 1U);
BOOST_CHECK(solutions[0] == ToByteVector(CScriptID(redeemScript)));
@@ -59,8 +55,7 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
ToByteVector(pubkeys[0]) <<
ToByteVector(pubkeys[1]) <<
OP_2 << OP_CHECKMULTISIG;
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK_EQUAL(whichType, TX_MULTISIG);
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_MULTISIG);
BOOST_CHECK_EQUAL(solutions.size(), 4U);
BOOST_CHECK(solutions[0] == std::vector<unsigned char>({1}));
BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0]));
@@ -73,8 +68,7 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
ToByteVector(pubkeys[1]) <<
ToByteVector(pubkeys[2]) <<
OP_3 << OP_CHECKMULTISIG;
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK_EQUAL(whichType, TX_MULTISIG);
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_MULTISIG);
BOOST_CHECK_EQUAL(solutions.size(), 5U);
BOOST_CHECK(solutions[0] == std::vector<unsigned char>({2}));
BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0]));
@@ -88,15 +82,13 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
std::vector<unsigned char>({0}) <<
std::vector<unsigned char>({75}) <<
std::vector<unsigned char>({255});
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK_EQUAL(whichType, TX_NULL_DATA);
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NULL_DATA);
BOOST_CHECK_EQUAL(solutions.size(), 0U);
// TX_WITNESS_V0_KEYHASH
s.clear();
s << OP_0 << ToByteVector(pubkeys[0].GetID());
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK_EQUAL(whichType, TX_WITNESS_V0_KEYHASH);
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_WITNESS_V0_KEYHASH);
BOOST_CHECK_EQUAL(solutions.size(), 1U);
BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID()));
@@ -107,16 +99,14 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
s.clear();
s << OP_0 << ToByteVector(scriptHash);
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK_EQUAL(whichType, TX_WITNESS_V0_SCRIPTHASH);
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_WITNESS_V0_SCRIPTHASH);
BOOST_CHECK_EQUAL(solutions.size(), 1U);
BOOST_CHECK(solutions[0] == ToByteVector(scriptHash));
// TX_NONSTANDARD
s.clear();
s << OP_9 << OP_ADD << OP_11 << OP_EQUAL;
- BOOST_CHECK(!Solver(s, whichType, solutions));
- BOOST_CHECK_EQUAL(whichType, TX_NONSTANDARD);
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
}
BOOST_AUTO_TEST_CASE(script_standard_Solver_failure)
@@ -127,53 +117,52 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_failure)
pubkey = key.GetPubKey();
CScript s;
- txnouttype whichType;
std::vector<std::vector<unsigned char> > solutions;
// TX_PUBKEY with incorrectly sized pubkey
s.clear();
s << std::vector<unsigned char>(30, 0x01) << OP_CHECKSIG;
- BOOST_CHECK(!Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_PUBKEYHASH with incorrectly sized key hash
s.clear();
s << OP_DUP << OP_HASH160 << ToByteVector(pubkey) << OP_EQUALVERIFY << OP_CHECKSIG;
- BOOST_CHECK(!Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_SCRIPTHASH with incorrectly sized script hash
s.clear();
s << OP_HASH160 << std::vector<unsigned char>(21, 0x01) << OP_EQUAL;
- BOOST_CHECK(!Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_MULTISIG 0/2
s.clear();
s << OP_0 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG;
- BOOST_CHECK(!Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_MULTISIG 2/1
s.clear();
s << OP_2 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG;
- BOOST_CHECK(!Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_MULTISIG n = 2 with 1 pubkey
s.clear();
s << OP_1 << ToByteVector(pubkey) << OP_2 << OP_CHECKMULTISIG;
- BOOST_CHECK(!Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_MULTISIG n = 1 with 0 pubkeys
s.clear();
s << OP_1 << OP_1 << OP_CHECKMULTISIG;
- BOOST_CHECK(!Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_NULL_DATA with other opcodes
s.clear();
s << OP_RETURN << std::vector<unsigned char>({75}) << OP_ADD;
- BOOST_CHECK(!Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_WITNESS with incorrect program size
s.clear();
s << OP_0 << std::vector<unsigned char>(19, 0x01);
- BOOST_CHECK(!Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
}
BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp
index 6a0aa864d9..26cf74830d 100644
--- a/src/test/streams_tests.cpp
+++ b/src/test/streams_tests.cpp
@@ -68,6 +68,86 @@ BOOST_AUTO_TEST_CASE(streams_vector_writer)
vch.clear();
}
+BOOST_AUTO_TEST_CASE(streams_vector_reader)
+{
+ std::vector<unsigned char> vch = {1, 255, 3, 4, 5, 6};
+
+ VectorReader reader(SER_NETWORK, INIT_PROTO_VERSION, vch, 0);
+ BOOST_CHECK_EQUAL(reader.size(), 6);
+ BOOST_CHECK(!reader.empty());
+
+ // Read a single byte as an unsigned char.
+ unsigned char a;
+ reader >> a;
+ BOOST_CHECK_EQUAL(a, 1);
+ BOOST_CHECK_EQUAL(reader.size(), 5);
+ BOOST_CHECK(!reader.empty());
+
+ // Read a single byte as a signed char.
+ signed char b;
+ reader >> b;
+ BOOST_CHECK_EQUAL(b, -1);
+ BOOST_CHECK_EQUAL(reader.size(), 4);
+ BOOST_CHECK(!reader.empty());
+
+ // Read a 4 bytes as an unsigned int.
+ unsigned int c;
+ reader >> c;
+ BOOST_CHECK_EQUAL(c, 100992003); // 3,4,5,6 in little-endian base-256
+ BOOST_CHECK_EQUAL(reader.size(), 0);
+ BOOST_CHECK(reader.empty());
+
+ // Reading after end of byte vector throws an error.
+ signed int d;
+ BOOST_CHECK_THROW(reader >> d, std::ios_base::failure);
+
+ // Read a 4 bytes as a signed int from the beginning of the buffer.
+ reader.seek(-6);
+ reader >> d;
+ BOOST_CHECK_EQUAL(d, 67370753); // 1,255,3,4 in little-endian base-256
+ BOOST_CHECK_EQUAL(reader.size(), 2);
+ BOOST_CHECK(!reader.empty());
+
+ // Reading after end of byte vector throws an error even if the reader is
+ // not totally empty.
+ BOOST_CHECK_THROW(reader >> d, std::ios_base::failure);
+}
+
+BOOST_AUTO_TEST_CASE(bitstream_reader_writer)
+{
+ CDataStream data(SER_NETWORK, INIT_PROTO_VERSION);
+
+ BitStreamWriter<CDataStream> bit_writer(data);
+ bit_writer.Write(0, 1);
+ bit_writer.Write(2, 2);
+ bit_writer.Write(6, 3);
+ bit_writer.Write(11, 4);
+ bit_writer.Write(1, 5);
+ bit_writer.Write(32, 6);
+ bit_writer.Write(7, 7);
+ bit_writer.Write(30497, 16);
+ bit_writer.Flush();
+
+ CDataStream data_copy(data);
+ uint32_t serialized_int1;
+ data >> serialized_int1;
+ BOOST_CHECK_EQUAL(serialized_int1, (uint32_t)0x7700C35A); // NOTE: Serialized as LE
+ uint16_t serialized_int2;
+ data >> serialized_int2;
+ BOOST_CHECK_EQUAL(serialized_int2, (uint16_t)0x1072); // NOTE: Serialized as LE
+
+ BitStreamReader<CDataStream> bit_reader(data_copy);
+ BOOST_CHECK_EQUAL(bit_reader.Read(1), 0);
+ BOOST_CHECK_EQUAL(bit_reader.Read(2), 2);
+ BOOST_CHECK_EQUAL(bit_reader.Read(3), 6);
+ BOOST_CHECK_EQUAL(bit_reader.Read(4), 11);
+ BOOST_CHECK_EQUAL(bit_reader.Read(5), 1);
+ BOOST_CHECK_EQUAL(bit_reader.Read(6), 32);
+ BOOST_CHECK_EQUAL(bit_reader.Read(7), 7);
+ BOOST_CHECK_EQUAL(bit_reader.Read(16), 30497);
+ BOOST_CHECK_THROW(bit_reader.Read(8), std::ios_base::failure);
+}
+
BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
{
std::vector<char> in;
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 9c3285fb0c..a89bf785f1 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -8,15 +8,17 @@
#include <consensus/consensus.h>
#include <consensus/validation.h>
#include <crypto/sha256.h>
-#include <validation.h>
#include <miner.h>
#include <net_processing.h>
#include <pow.h>
-#include <ui_interface.h>
-#include <streams.h>
-#include <rpc/server.h>
#include <rpc/register.h>
+#include <rpc/server.h>
#include <script/sigcache.h>
+#include <streams.h>
+#include <ui_interface.h>
+#include <validation.h>
+
+const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
void CConnmanTest::AddNode(CNode& node)
{
diff --git a/src/test/test_bitcoin_fuzzy.cpp b/src/test/test_bitcoin_fuzzy.cpp
index 4d835db7be..11b7c66ccd 100644
--- a/src/test/test_bitcoin_fuzzy.cpp
+++ b/src/test/test_bitcoin_fuzzy.cpp
@@ -6,20 +6,20 @@
#include <config/bitcoin-config.h>
#endif
-#include <consensus/merkle.h>
-#include <primitives/block.h>
-#include <script/script.h>
#include <addrman.h>
+#include <blockencodings.h>
#include <chain.h>
#include <coins.h>
#include <compressor.h>
+#include <consensus/merkle.h>
#include <net.h>
+#include <primitives/block.h>
#include <protocol.h>
+#include <pubkey.h>
+#include <script/script.h>
#include <streams.h>
#include <undo.h>
#include <version.h>
-#include <pubkey.h>
-#include <blockencodings.h>
#include <stdint.h>
#include <unistd.h>
@@ -28,6 +28,8 @@
#include <memory>
#include <vector>
+const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
+
enum TEST_ID {
CBLOCK_DESERIALIZE=0,
CTRANSACTION_DESERIALIZE,
diff --git a/src/test/txindex_tests.cpp b/src/test/txindex_tests.cpp
index be7ee2428b..2a160b9988 100644
--- a/src/test/txindex_tests.cpp
+++ b/src/test/txindex_tests.cpp
@@ -61,6 +61,8 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
BOOST_ERROR("Read incorrect tx");
}
}
+
+ txindex.Stop(); // Stop thread before calling destructor
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/txmempool.h b/src/txmempool.h
index 587d931d95..f8915cec31 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -28,6 +28,7 @@
#include <boost/signals2/signal.hpp>
class CBlockIndex;
+extern CCriticalSection cs_main;
/** Fake height value used in Coin to signify they are only in the memory pool (since 0.8) */
static const uint32_t MEMPOOL_HEIGHT = 0x7FFFFFFF;
@@ -543,7 +544,7 @@ public:
void addUnchecked(const uint256& hash, const CTxMemPoolEntry& entry, setEntries& setAncestors, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs);
void removeRecursive(const CTransaction &tx, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN);
- void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags);
+ void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void removeConflicts(const CTransaction &tx) EXCLUSIVE_LOCKS_REQUIRED(cs);
void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight);
diff --git a/src/undo.h b/src/undo.h
index a1398b7624..4a78238944 100644
--- a/src/undo.h
+++ b/src/undo.h
@@ -6,6 +6,7 @@
#ifndef BITCOIN_UNDO_H
#define BITCOIN_UNDO_H
+#include <coins.h>
#include <compressor.h>
#include <consensus/consensus.h>
#include <primitives/transaction.h>
diff --git a/src/util.cpp b/src/util.cpp
index 95bc427bb2..1aab85264f 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -86,8 +86,6 @@ const char * const BITCOIN_PID_FILENAME = "bitcoind.pid";
ArgsManager gArgs;
-CTranslationInterface translationInterface;
-
/** 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
diff --git a/src/util.h b/src/util.h
index 23b2a787e4..e93489c1ed 100644
--- a/src/util.h
+++ b/src/util.h
@@ -19,8 +19,8 @@
#include <logging.h>
#include <sync.h>
#include <tinyformat.h>
-#include <utiltime.h>
#include <utilmemory.h>
+#include <utiltime.h>
#include <atomic>
#include <exception>
@@ -31,33 +31,24 @@
#include <unordered_set>
#include <vector>
-#include <boost/signals2/signal.hpp>
#include <boost/thread/condition_variable.hpp> // for boost::thread_interrupted
// Application startup time (used for uptime calculation)
int64_t GetStartupTime();
-/** Signals for translation. */
-class CTranslationInterface
-{
-public:
- /** Translate a message to the native language of the user. */
- boost::signals2::signal<std::string (const char* psz)> Translate;
-};
-
-extern CTranslationInterface translationInterface;
-
extern const char * const BITCOIN_CONF_FILENAME;
extern const char * const BITCOIN_PID_FILENAME;
+/** Translate a message to the native language of the user. */
+const extern std::function<std::string(const char*)> G_TRANSLATION_FUN;
+
/**
- * 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.
+ * Translation function.
+ * If no translation function is set, simply return the input.
*/
inline std::string _(const char* psz)
{
- boost::optional<std::string> rv = translationInterface.Translate(psz);
- return rv ? (*rv) : psz;
+ return G_TRANSLATION_FUN ? (G_TRANSLATION_FUN)(psz) : psz;
}
void SetupEnvironment();
diff --git a/src/validation.cpp b/src/validation.cpp
index fceb135854..3e51221a5e 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -170,7 +170,7 @@ public:
// Block (dis)connection on a given view:
DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view);
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
- CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false);
+ CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
// Block disconnection on our pcoinsTip:
bool DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool);
@@ -189,8 +189,8 @@ public:
void UnloadBlockIndex();
private:
- bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace);
- bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool);
+ bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
CBlockIndex* AddToBlockIndex(const CBlockHeader& block) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Create a new block index entry for a given block hash */
@@ -202,7 +202,7 @@ private:
*/
void CheckBlockIndex(const Consensus::Params& consensusParams);
- void InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state);
+ void InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
CBlockIndex* FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const CDiskBlockPos& pos, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -457,7 +457,7 @@ std::string FormatStateMessage(const CValidationState &state)
state.GetRejectCode());
}
-static bool IsCurrentForFeeEstimation()
+static bool IsCurrentForFeeEstimation() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(cs_main);
if (IsInitialBlockDownload())
@@ -482,7 +482,7 @@ static bool IsCurrentForFeeEstimation()
* and instead just erase from the mempool as needed.
*/
-static void UpdateMempoolForReorg(DisconnectedBlockTransactions &disconnectpool, bool fAddToMempool)
+static void UpdateMempoolForReorg(DisconnectedBlockTransactions &disconnectpool, bool fAddToMempool) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(cs_main);
std::vector<uint256> vHashUpdate;
@@ -524,7 +524,7 @@ static void UpdateMempoolForReorg(DisconnectedBlockTransactions &disconnectpool,
// Used to avoid mempool polluting consensus critical paths if CCoinsViewMempool
// were somehow broken and returning the wrong scriptPubKeys
static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& view, const CTxMemPool& pool,
- unsigned int flags, bool cacheSigStore, PrecomputedTransactionData& txdata) {
+ unsigned int flags, bool cacheSigStore, PrecomputedTransactionData& txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
AssertLockHeld(cs_main);
// pool.cs should be locked already, but go ahead and re-take the lock here
@@ -559,7 +559,7 @@ static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, CValidationSt
static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool& pool, CValidationState& state, const CTransactionRef& ptx,
bool* pfMissingInputs, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
- bool bypass_limits, const CAmount& nAbsurdFee, std::vector<COutPoint>& coins_to_uncache, bool test_accept)
+ bool bypass_limits, const CAmount& nAbsurdFee, std::vector<COutPoint>& coins_to_uncache, bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
const CTransaction& tx = *ptx;
const uint256 hash = tx.GetHash();
@@ -977,7 +977,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
/** (try to) add transaction to memory pool with a specified acceptance time **/
static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx,
bool* pfMissingInputs, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
- bool bypass_limits, const CAmount nAbsurdFee, bool test_accept)
+ bool bypass_limits, const CAmount nAbsurdFee, bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
std::vector<COutPoint> coins_to_uncache;
bool res = AcceptToMemoryPoolWorker(chainparams, pool, state, tx, pfMissingInputs, nAcceptTime, plTxnReplaced, bypass_limits, nAbsurdFee, coins_to_uncache, test_accept);
@@ -1216,7 +1216,7 @@ static void AlertNotify(const std::string& strMessage)
t.detach(); // thread runs free
}
-static void CheckForkWarningConditions()
+static void CheckForkWarningConditions() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(cs_main);
// Before we get past initial download, we cannot reliably alert about forks
@@ -1257,7 +1257,7 @@ static void CheckForkWarningConditions()
}
}
-static void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip)
+static void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(cs_main);
// If we are on a fork that is sufficiently large, set a warning flag
@@ -1290,7 +1290,7 @@ static void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip)
CheckForkWarningConditions();
}
-void static InvalidChainFound(CBlockIndex* pindexNew)
+void static InvalidChainFound(CBlockIndex* pindexNew) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
if (!pindexBestInvalid || pindexNew->nChainWork > pindexBestInvalid->nChainWork)
pindexBestInvalid = pindexNew;
@@ -1377,7 +1377,7 @@ void InitScriptExecutionCache() {
*
* Non-static (and re-declared) in src/test/txvalidationcache_tests.cpp
*/
-bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks)
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
if (!tx.IsCoinBase())
{
@@ -1743,7 +1743,7 @@ 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) {
+static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& consensusparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
AssertLockHeld(cs_main);
unsigned int flags = SCRIPT_VERIFY_NONE;
@@ -2863,6 +2863,7 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c
}
return true;
}
+
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex) {
return g_chainstate.InvalidateBlock(state, chainparams, pindex);
}
diff --git a/src/validation.h b/src/validation.h
index 4965ff152a..c4c9b8b5ba 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -302,7 +302,7 @@ void PruneBlockFilesManual(int nManualPruneHeight);
* plTxnReplaced will be appended to with all transactions replaced from mempool **/
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx,
bool* pfMissingInputs, std::list<CTransactionRef>* plTxnReplaced,
- bool bypass_limits, const CAmount nAbsurdFee, bool test_accept=false);
+ bool bypass_limits, const CAmount nAbsurdFee, bool test_accept=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Convert CValidationState to a human-readable message for logging */
std::string FormatStateMessage(const CValidationState &state);
@@ -329,12 +329,12 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight);
*
* See consensus/consensus.h for flag definitions.
*/
-bool CheckFinalTx(const CTransaction &tx, int flags = -1);
+bool CheckFinalTx(const CTransaction &tx, int flags = -1) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Test whether the LockPoints height and time are still valid on the current chain
*/
-bool TestLockPointValidity(const LockPoints* lp);
+bool TestLockPointValidity(const LockPoints* lp) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Check if transaction will be BIP 68 final in the next block to be created.
@@ -347,7 +347,7 @@ bool TestLockPointValidity(const LockPoints* lp);
*
* See consensus/consensus.h for flag definitions.
*/
-bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp = nullptr, bool useExistingLockPoints = false);
+bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp = nullptr, bool useExistingLockPoints = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Closure representing one script verification
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index 248e774a8d..e25eca2368 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -7,7 +7,6 @@
#include <primitives/block.h>
#include <scheduler.h>
-#include <sync.h>
#include <txmempool.h>
#include <util.h>
#include <validation.h>
diff --git a/src/validationinterface.h b/src/validationinterface.h
index 6e96755ea3..f0374e8e78 100644
--- a/src/validationinterface.h
+++ b/src/validationinterface.h
@@ -7,10 +7,12 @@
#define BITCOIN_VALIDATIONINTERFACE_H
#include <primitives/transaction.h> // CTransaction(Ref)
+#include <sync.h>
#include <functional>
#include <memory>
+extern CCriticalSection cs_main;
class CBlock;
class CBlockIndex;
struct CBlockLocator;
@@ -51,7 +53,7 @@ void CallFunctionInValidationInterfaceQueue(std::function<void ()> func);
* });
* promise.get_future().wait();
*/
-void SyncWithValidationInterfaceQueue();
+void SyncWithValidationInterfaceQueue() LOCKS_EXCLUDED(cs_main);
/**
* Implement this to subscribe to events generated in validation
diff --git a/src/wallet/coinselection.cpp b/src/wallet/coinselection.cpp
index 3734ba66b6..fdeb89553b 100644
--- a/src/wallet/coinselection.cpp
+++ b/src/wallet/coinselection.cpp
@@ -3,9 +3,12 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <wallet/coinselection.h>
+
#include <util.h>
#include <utilmoneystr.h>
+#include <boost/optional.hpp>
+
// Descending order comparator
struct {
bool operator()(const OutputGroup& a, const OutputGroup& b) const
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index d5d4021305..2b8a0f6467 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -18,7 +18,7 @@
//! Check whether transaction has descendant in wallet or mempool, or has been
//! mined, or conflicts with a mined transaction. Return a feebumper::Result.
-static feebumper::Result PreconditionChecks(const CWallet* wallet, const CWalletTx& wtx, std::vector<std::string>& errors) EXCLUSIVE_LOCKS_REQUIRED(wallet->cs_wallet)
+static feebumper::Result PreconditionChecks(const CWallet* wallet, const CWalletTx& wtx, std::vector<std::string>& errors) EXCLUSIVE_LOCKS_REQUIRED(cs_main, wallet->cs_wallet)
{
if (wallet->HasWalletSpend(wtx.GetHash())) {
errors.push_back("Transaction has descendants in the wallet");
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index b108d6df53..a7ec481646 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -89,7 +89,7 @@ void EnsureWalletIsUnlocked(CWallet * const pwallet)
}
}
-static void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
+static void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
int confirms = wtx.GetDepthInMainChain();
entry.pushKV("confirmations", confirms);
@@ -165,7 +165,7 @@ static UniValue getnewaddress(const JSONRPCRequest& request)
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
}
- LOCK2(cs_main, pwallet->cs_wallet);
+ LOCK(pwallet->cs_wallet);
// Parse the label first so we don't generate a key if there's an error
std::string label;
@@ -276,7 +276,7 @@ static UniValue getrawchangeaddress(const JSONRPCRequest& request)
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
}
- LOCK2(cs_main, pwallet->cs_wallet);
+ LOCK(pwallet->cs_wallet);
if (!pwallet->IsLocked()) {
pwallet->TopUpKeyPool();
@@ -331,7 +331,7 @@ static UniValue setlabel(const JSONRPCRequest& request)
+ HelpExampleRpc("setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"tabby\"")
);
- LOCK2(cs_main, pwallet->cs_wallet);
+ LOCK(pwallet->cs_wallet);
CTxDestination dest = DecodeDestination(request.params[0].get_str());
if (!IsValidDestination(dest)) {
@@ -1526,7 +1526,7 @@ struct tallyitem
}
};
-static UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool by_label)
+static UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
// Minimum confirmations
int nMinDepth = 1;
@@ -1793,7 +1793,7 @@ static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
* @param ret The UniValue into which the result is stored.
* @param filter The "is mine" filter bool.
*/
-static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, const std::string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
+static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, const std::string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
CAmount nFee;
std::string strSentAccount;
@@ -1851,7 +1851,7 @@ static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, const
{
if (wtx.GetDepthInMainChain() < 1)
entry.pushKV("category", "orphan");
- else if (wtx.GetBlocksToMaturity() > 0)
+ else if (wtx.IsImmatureCoinBase())
entry.pushKV("category", "immature");
else
entry.pushKV("category", "generate");
@@ -2147,7 +2147,7 @@ static UniValue listaccounts(const JSONRPCRequest& request)
std::list<COutputEntry> listReceived;
std::list<COutputEntry> listSent;
int nDepth = wtx.GetDepthInMainChain();
- if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0)
+ if (wtx.IsImmatureCoinBase() || nDepth < 0)
continue;
wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly);
mapAccountBalances[strSentAccount] -= nFee;
@@ -4029,9 +4029,8 @@ public:
void ProcessSubScript(const CScript& subscript, UniValue& obj, bool include_addresses = false) const
{
// Always present: script type and redeemscript
- txnouttype which_type;
std::vector<std::vector<unsigned char>> solutions_data;
- Solver(subscript, which_type, solutions_data);
+ txnouttype which_type = Solver(subscript, solutions_data);
obj.pushKV("script", GetTxnOutputType(which_type));
obj.pushKV("hex", HexStr(subscript.begin(), subscript.end()));
@@ -4599,7 +4598,7 @@ UniValue walletprocesspsbt(const JSONRPCRequest& request)
" \"ALL|ANYONECANPAY\"\n"
" \"NONE|ANYONECANPAY\"\n"
" \"SINGLE|ANYONECANPAY\"\n"
- "4. bip32derivs (boolean, optiona, default=false) If true, includes the BIP 32 derivation paths for public keys if we know them\n"
+ "4. bip32derivs (boolean, optional, default=false) If true, includes the BIP 32 derivation paths for public keys if we know them\n"
"\nResult:\n"
"{\n"
@@ -4701,7 +4700,7 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
" \"ECONOMICAL\"\n"
" \"CONSERVATIVE\"\n"
" }\n"
- "5. bip32derivs (boolean, optiona, default=false) If true, includes the BIP 32 derivation paths for public keys if we know them\n"
+ "5. bip32derivs (boolean, optional, default=false) If true, includes the BIP 32 derivation paths for public keys if we know them\n"
"\nResult:\n"
"{\n"
" \"psbt\": \"value\", (string) The resulting raw transaction (base64-encoded string)\n"
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 5a7fdf9a85..d0857bcb72 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1894,7 +1894,7 @@ CAmount CWalletTx::GetDebit(const isminefilter& filter) const
CAmount CWalletTx::GetCredit(const isminefilter& filter) const
{
// Must wait until coinbase is safely deep enough in the chain before valuing it
- if (IsCoinBase() && GetBlocksToMaturity() > 0)
+ if (IsImmatureCoinBase())
return 0;
CAmount credit = 0;
@@ -1926,8 +1926,7 @@ CAmount CWalletTx::GetCredit(const isminefilter& filter) const
CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const
{
- if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
- {
+ if (IsImmatureCoinBase() && IsInMainChain()) {
if (fUseCache && fImmatureCreditCached)
return nImmatureCreditCached;
nImmatureCreditCached = pwallet->GetCredit(*tx, ISMINE_SPENDABLE);
@@ -1944,7 +1943,7 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache, const isminefilter& filter
return 0;
// Must wait until coinbase is safely deep enough in the chain before valuing it
- if (IsCoinBase() && GetBlocksToMaturity() > 0)
+ if (IsImmatureCoinBase())
return 0;
CAmount* cache = nullptr;
@@ -1985,8 +1984,7 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache, const isminefilter& filter
CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool fUseCache) const
{
- if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
- {
+ if (IsImmatureCoinBase() && IsInMainChain()) {
if (fUseCache && fImmatureWatchCreditCached)
return nImmatureWatchCreditCached;
nImmatureWatchCreditCached = pwallet->GetCredit(*tx, ISMINE_WATCH_ONLY);
@@ -2199,7 +2197,7 @@ CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth, cons
for (const auto& entry : mapWallet) {
const CWalletTx& wtx = entry.second;
const int depth = wtx.GetDepthInMainChain();
- if (depth < 0 || !CheckFinalTx(*wtx.tx) || wtx.GetBlocksToMaturity() > 0) {
+ if (depth < 0 || !CheckFinalTx(*wtx.tx) || wtx.IsImmatureCoinBase()) {
continue;
}
@@ -2259,7 +2257,7 @@ void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const
if (!CheckFinalTx(*pcoin->tx))
continue;
- if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
+ if (pcoin->IsImmatureCoinBase())
continue;
int nDepth = pcoin->GetDepthInMainChain();
@@ -3528,7 +3526,7 @@ std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
if (!pcoin->IsTrusted())
continue;
- if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
+ if (pcoin->IsImmatureCoinBase())
continue;
int nDepth = pcoin->GetDepthInMainChain();
@@ -4406,6 +4404,11 @@ int CMerkleTx::GetBlocksToMaturity() const
return std::max(0, (COINBASE_MATURITY+1) - chain_depth);
}
+bool CMerkleTx::IsImmatureCoinBase() const
+{
+ // note GetBlocksToMaturity is 0 for non-coinbase tx
+ return GetBlocksToMaturity() > 0;
+}
bool CWalletTx::AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state)
{
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 57b22c0e49..51ac3df71e 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -264,15 +264,22 @@ public:
* 0 : in memory pool, waiting to be included in a block
* >=1 : this many blocks deep in the main chain
*/
- int GetDepthInMainChain() const;
- bool IsInMainChain() const { return GetDepthInMainChain() > 0; }
- int GetBlocksToMaturity() const;
+ int GetDepthInMainChain() const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool IsInMainChain() const EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return GetDepthInMainChain() > 0; }
+
+ /**
+ * @return number of blocks to maturity for this transaction:
+ * 0 : is not a coinbase transaction, or is a mature coinbase transaction
+ * >0 : is a coinbase transaction which matures in this many blocks
+ */
+ int GetBlocksToMaturity() const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool hashUnset() const { return (hashBlock.IsNull() || hashBlock == ABANDON_HASH); }
bool isAbandoned() const { return (hashBlock == ABANDON_HASH); }
void setAbandoned() { hashBlock = ABANDON_HASH; }
const uint256& GetHash() const { return tx->GetHash(); }
bool IsCoinBase() const { return tx->IsCoinBase(); }
+ bool IsImmatureCoinBase() const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
};
//Get the marginal bytes of spending the specified output
@@ -454,10 +461,10 @@ public:
//! filter decides which addresses will count towards the debit
CAmount GetDebit(const isminefilter& filter) const;
- CAmount GetCredit(const isminefilter& filter) const;
- CAmount GetImmatureCredit(bool fUseCache=true) const;
- CAmount GetAvailableCredit(bool fUseCache=true, const isminefilter& filter=ISMINE_SPENDABLE) const;
- CAmount GetImmatureWatchOnlyCredit(const bool fUseCache=true) const;
+ CAmount GetCredit(const isminefilter& filter) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ CAmount GetImmatureCredit(bool fUseCache=true) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ CAmount GetAvailableCredit(bool fUseCache=true, const isminefilter& filter=ISMINE_SPENDABLE) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ CAmount GetImmatureWatchOnlyCredit(const bool fUseCache=true) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
CAmount GetChange() const;
// Get the marginal bytes if spending the specified output from this transaction
@@ -478,15 +485,15 @@ public:
bool IsEquivalentTo(const CWalletTx& tx) const;
bool InMempool() const;
- bool IsTrusted() const;
+ bool IsTrusted() const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
int64_t GetTxTime() const;
// RelayWalletTransaction may only be called if fBroadcastTransactions!
- bool RelayWalletTransaction(CConnman* connman);
+ bool RelayWalletTransaction(CConnman* connman) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Pass this transaction to the mempool. Fails if absolute fee exceeds absurd fee. */
- bool AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state);
+ bool AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
std::set<uint256> GetConflicts() const;
};
@@ -840,7 +847,7 @@ public:
/**
* populate vCoins with vector of available COutputs.
*/
- void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlySafe=true, const CCoinControl *coinControl = nullptr, const CAmount& nMinimumAmount = 1, const CAmount& nMaximumAmount = MAX_MONEY, const CAmount& nMinimumSumAmount = MAX_MONEY, const uint64_t nMaximumCount = 0, const int nMinDepth = 0, const int nMaxDepth = 9999999) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlySafe=true, const CCoinControl *coinControl = nullptr, const CAmount& nMinimumAmount = 1, const CAmount& nMaximumAmount = MAX_MONEY, const CAmount& nMinimumSumAmount = MAX_MONEY, const uint64_t nMaximumCount = 0, const int nMinDepth = 0, const int nMaxDepth = 9999999) const EXCLUSIVE_LOCKS_REQUIRED(cs_main, cs_wallet);
/**
* Return list of available coins and locked coins grouped by non-change output address.
@@ -861,7 +868,7 @@ public:
bool SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<OutputGroup> groups,
std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CoinSelectionParams& coin_selection_params, bool& bnb_used) const;
- bool IsSpent(const uint256& hash, unsigned int n) const;
+ bool IsSpent(const uint256& hash, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
std::vector<OutputGroup> GroupOutputs(const std::vector<COutput>& outputs, bool single_coin) const;
bool IsLockedCoin(uint256 hash, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
@@ -947,9 +954,9 @@ public:
CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, const WalletRescanReserver& reserver, bool fUpdate = false);
void TransactionRemovedFromMempool(const CTransactionRef &ptx) override;
void ReacceptWalletTransactions();
- void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override;
+ void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override EXCLUSIVE_LOCKS_REQUIRED(cs_main);
// ResendWalletTransactionsBefore may only be called if fBroadcastTransactions!
- std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman);
+ std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
CAmount GetBalance(const isminefilter& filter=ISMINE_SPENDABLE, const int min_depth=0) const;
CAmount GetUnconfirmedBalance() const;
CAmount GetImmatureBalance() const;
@@ -1034,7 +1041,7 @@ public:
const std::map<CKeyID, int64_t>& GetAllReserveKeys() const { return m_pool_key_to_index; }
std::set<std::set<CTxDestination>> GetAddressGroupings() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
- std::map<CTxDestination, CAmount> GetAddressBalances();
+ std::map<CTxDestination, CAmount> GetAddressBalances() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
std::set<CTxDestination> GetLabelAddresses(const std::string& label) const;
void DeleteLabel(const std::string& label);
@@ -1173,7 +1180,7 @@ public:
* Obviously holding cs_main/cs_wallet when going into this call may cause
* deadlock
*/
- void BlockUntilSyncedToCurrentChain() LOCKS_EXCLUDED(cs_wallet);
+ void BlockUntilSyncedToCurrentChain() LOCKS_EXCLUDED(cs_main, cs_wallet);
/**
* Explicitly make the wallet learn the related scripts for outputs to the
diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py
index 6105da810c..7e84ba43b5 100755
--- a/test/functional/feature_rbf.py
+++ b/test/functional/feature_rbf.py
@@ -429,6 +429,9 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx1a_hex = txToHex(tx1a)
tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True)
+ # This transaction isn't shown as replaceable
+ assert_equal(self.nodes[0].getmempoolentry(tx1a_txid)['bip125-replaceable'], False)
+
# Shouldn't be able to double-spend
tx1b = CTransaction()
tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]
@@ -469,7 +472,10 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx3a.vout = [CTxOut(int(0.9*COIN), CScript([b'c'])), CTxOut(int(0.9*COIN), CScript([b'd']))]
tx3a_hex = txToHex(tx3a)
- self.nodes[0].sendrawtransaction(tx3a_hex, True)
+ tx3a_txid = self.nodes[0].sendrawtransaction(tx3a_hex, True)
+
+ # This transaction is shown as replaceable
+ assert_equal(self.nodes[0].getmempoolentry(tx3a_txid)['bip125-replaceable'], True)
tx3b = CTransaction()
tx3b.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0)]
diff --git a/test/functional/p2p_invalid_tx.py b/test/functional/p2p_invalid_tx.py
index 0aa5e21103..12bc62131f 100755
--- a/test/functional/p2p_invalid_tx.py
+++ b/test/functional/p2p_invalid_tx.py
@@ -136,11 +136,16 @@ class InvalidTxRequestTest(BitcoinTestFramework):
# restart node with sending BIP61 messages disabled, check that it disconnects without sending the reject message
self.log.info('Test a transaction that is rejected, with BIP61 disabled')
- self.restart_node(0, ['-enablebip61=0','-persistmempool=0'])
+ self.restart_node(0, ['-enablebip61=0', '-persistmempool=0'])
self.reconnect_p2p(num_connections=1)
- node.p2p.send_txs_and_test([tx1], node, success=False, expect_disconnect=True)
+ with node.assert_debug_log(expected_msgs=[
+ "{} from peer=0 was not accepted: mandatory-script-verify-flag-failed (Invalid OP_IF construction) (code 16)".format(tx1.hash),
+ "disconnecting peer=0",
+ ]):
+ node.p2p.send_txs_and_test([tx1], node, success=False, expect_disconnect=True)
# send_txs_and_test will have waited for disconnect, so we can safely check that no reject has been received
assert_equal(node.p2p.reject_code_received, None)
+
if __name__ == '__main__':
InvalidTxRequestTest().main()
diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py
index 7276f6b450..0a3907cba4 100755
--- a/test/functional/test_framework/messages.py
+++ b/test/functional/test_framework/messages.py
@@ -904,28 +904,17 @@ class msg_version():
def deserialize(self, f):
self.nVersion = struct.unpack("<i", f.read(4))[0]
- if self.nVersion == 10300:
- self.nVersion = 300
self.nServices = struct.unpack("<Q", f.read(8))[0]
self.nTime = struct.unpack("<q", f.read(8))[0]
self.addrTo = CAddress()
self.addrTo.deserialize(f, False)
- if self.nVersion >= 106:
- self.addrFrom = CAddress()
- self.addrFrom.deserialize(f, False)
- self.nNonce = struct.unpack("<Q", f.read(8))[0]
- self.strSubVer = deser_string(f)
- else:
- self.addrFrom = None
- self.nNonce = None
- self.strSubVer = None
- self.nStartingHeight = None
+ self.addrFrom = CAddress()
+ self.addrFrom.deserialize(f, False)
+ self.nNonce = struct.unpack("<Q", f.read(8))[0]
+ self.strSubVer = deser_string(f)
- if self.nVersion >= 209:
- self.nStartingHeight = struct.unpack("<i", f.read(4))[0]
- else:
- self.nStartingHeight = None
+ self.nStartingHeight = struct.unpack("<i", f.read(4))[0]
if self.nVersion >= 70001:
# Relay field is optional for version 70001 onwards
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index 0d00cc2082..a831fdcd5d 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -4,6 +4,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Class for bitcoind node under test"""
+import contextlib
import decimal
import errno
from enum import Enum
@@ -229,6 +230,23 @@ class TestNode():
def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT):
wait_until(self.is_node_stopped, timeout=timeout)
+ @contextlib.contextmanager
+ def assert_debug_log(self, expected_msgs):
+ debug_log = os.path.join(self.datadir, 'regtest', 'debug.log')
+ with open(debug_log, encoding='utf-8') as dl:
+ dl.seek(0, 2)
+ prev_size = dl.tell()
+ try:
+ yield
+ finally:
+ with open(debug_log, encoding='utf-8') as dl:
+ dl.seek(prev_size)
+ log = dl.read()
+ print_log = " - " + "\n - ".join(log.splitlines())
+ for expected_msg in expected_msgs:
+ if re.search(re.escape(expected_msg), log, flags=re.MULTILINE) is None:
+ self._raise_assertion_error('Expected message "{}" does not partially match log:\n\n{}\n\n'.format(expected_msg, print_log))
+
def assert_start_raises_init_error(self, extra_args=None, expected_msg=None, match=ErrorMatch.FULL_TEXT, *args, **kwargs):
"""Attempt to start the node and expect it to raise an error.
diff --git a/test/lint/check-rpc-mappings.py b/test/lint/check-rpc-mappings.py
index 33e49bac13..137cc82b5d 100755
--- a/test/lint/check-rpc-mappings.py
+++ b/test/lint/check-rpc-mappings.py
@@ -90,6 +90,10 @@ def process_mapping(fname):
return cmds
def main():
+ if len(sys.argv) != 2:
+ print('Usage: {} ROOT-DIR'.format(sys.argv[0]), file=sys.stderr)
+ sys.exit(1)
+
root = sys.argv[1]
# Get all commands from dispatch tables