aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml24
-rw-r--r--.travis.yml41
-rw-r--r--.travis/README.md8
-rwxr-xr-x.travis/test_04_install.sh37
-rw-r--r--build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj30
-rw-r--r--ci/README.md25
-rwxr-xr-xci/extended_lint/04_install.sh (renamed from .travis/extended_lint_04_install.sh)0
-rwxr-xr-xci/extended_lint/06_script.sh (renamed from .travis/extended_lint_06_script.sh)0
-rwxr-xr-xci/lint/04_install.sh (renamed from .travis/lint_04_install.sh)6
-rwxr-xr-xci/lint/05_before_script.sh (renamed from .travis/lint_05_before_script.sh)0
-rwxr-xr-xci/lint/06_script.sh (renamed from .travis/lint_06_script.sh)0
-rw-r--r--ci/retry/README.md123
-rwxr-xr-xci/retry/retry163
-rwxr-xr-xci/test/00_setup_env.sh33
-rwxr-xr-xci/test/03_before_install.sh (renamed from .travis/test_03_before_install.sh)1
-rwxr-xr-xci/test/04_install.sh49
-rwxr-xr-xci/test/05_before_script.sh (renamed from .travis/test_05_before_script.sh)0
-rwxr-xr-xci/test/06_script_a.sh (renamed from .travis/test_06_script_a.sh)12
-rwxr-xr-xci/test/06_script_b.sh (renamed from .travis/test_06_script_b.sh)4
-rwxr-xr-xci/test_run_all.sh16
-rw-r--r--contrib/debian/copyright12
-rw-r--r--doc/release-notes-16060.md15
-rw-r--r--doc/release-notes-16383.md8
-rw-r--r--src/Makefile.qt.include12
-rw-r--r--src/chainparams.cpp49
-rw-r--r--src/chainparamsbase.cpp1
-rw-r--r--src/consensus/params.h8
-rw-r--r--src/init.cpp58
-rw-r--r--src/interfaces/node.cpp2
-rw-r--r--src/net_processing.cpp9
-rw-r--r--src/node/coin.cpp3
-rw-r--r--src/node/transaction.cpp2
-rw-r--r--src/qt/bitcoin.qrc10
-rw-r--r--src/qt/bitcoingui.cpp34
-rw-r--r--src/qt/res/icons/about.pngbin3717 -> 0 bytes
-rw-r--r--src/qt/res/icons/about_qt.pngbin2240 -> 0 bytes
-rw-r--r--src/qt/res/icons/configure.pngbin2865 -> 0 bytes
-rw-r--r--src/qt/res/icons/debugwindow.pngbin1327 -> 0 bytes
-rw-r--r--src/qt/res/icons/filesave.pngbin2359 -> 0 bytes
-rw-r--r--src/qt/res/icons/info.pngbin2028 -> 0 bytes
-rw-r--r--src/qt/res/icons/key.pngbin1759 -> 0 bytes
-rw-r--r--src/qt/res/icons/open.pngbin1694 -> 0 bytes
-rw-r--r--src/qt/res/icons/quit.pngbin1091 -> 0 bytes
-rw-r--r--src/qt/res/icons/verify.pngbin2034 -> 0 bytes
-rw-r--r--src/qt/res/src/verify.svg14
-rw-r--r--src/rest.cpp4
-rw-r--r--src/rpc/blockchain.cpp160
-rw-r--r--src/rpc/mining.cpp5
-rw-r--r--src/rpc/rawtransaction.cpp6
-rw-r--r--src/test/miner_tests.cpp6
-rw-r--r--src/test/setup_common.cpp13
-rw-r--r--src/test/txvalidationcache_tests.cpp22
-rw-r--r--src/txdb.cpp2
-rw-r--r--src/txdb.h5
-rw-r--r--src/txmempool.h2
-rw-r--r--src/validation.cpp136
-rw-r--r--src/validation.h106
-rw-r--r--src/versionbits.cpp1
-rw-r--r--src/versionbits.h28
-rw-r--r--src/versionbitsinfo.cpp8
-rw-r--r--src/wallet/rpcwallet.cpp69
-rwxr-xr-xtest/functional/feature_bip68_sequence.py14
-rwxr-xr-xtest/functional/feature_cltv.py17
-rwxr-xr-xtest/functional/feature_csv_activation.py97
-rwxr-xr-xtest/functional/feature_dbcrash.py2
-rwxr-xr-xtest/functional/feature_dersig.py17
-rwxr-xr-xtest/functional/feature_nulldummy.py2
-rwxr-xr-xtest/functional/feature_segwit.py6
-rwxr-xr-xtest/functional/p2p_compactblocks.py4
-rwxr-xr-xtest/functional/p2p_segwit.py82
-rwxr-xr-xtest/functional/rpc_blockchain.py26
-rw-r--r--test/functional/test_framework/address.py9
-rw-r--r--test/functional/test_framework/util.py6
-rwxr-xr-xtest/functional/test_runner.py25
-rwxr-xr-xtest/functional/wallet_import_rescan.py77
-rw-r--r--test/functional/wallet_watchonly.py107
-rw-r--r--test/lint/lint-python-dead-code-whitelist45
-rwxr-xr-xtest/lint/lint-python-dead-code.sh4
78 files changed, 1275 insertions, 647 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index ce17a223b1..1e6e6937da 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -27,3 +27,27 @@ task:
- gmake check ${MAKEJOBS} VERBOSE=1
functional_test_script:
- ./test/functional/test_runner.py --jobs 9 --ci --extended --exclude feature_dbcrash --combinedlogslen=1000 --quiet --failfast
+task:
+ name: "x86_64 Linux [GOAL: install] [bionic] [Using ./ci/ system]"
+ container:
+ image: ubuntu:18.04
+ cpu: 8
+ memory: 8G
+ timeout_in: 60m
+ env:
+ MAKEJOBS: "-j9"
+ RUN_CI_ON_HOST: "1"
+ CCACHE_SIZE: "200M"
+ CCACHE_DIR: "/tmp/ccache_dir"
+ ccache_cache:
+ folder: "/tmp/ccache_dir"
+ depends_built_cache:
+ folder: "/tmp/cirrus-ci-build/depends/built"
+ depends_sdk_cache:
+ folder: "/tmp/cirrus-ci-build/depends/sdk-sources"
+ install_script:
+ - apt-get update
+ - apt-get -y install git bash ccache
+ - ccache --max-size=${CCACHE_SIZE}
+ ci_script:
+ - ./ci/test_run_all.sh
diff --git a/.travis.yml b/.travis.yml
index d49c116a5e..4d83042994 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -17,7 +17,7 @@
# Bitcoin Core GitHub member via the Travis web interface [0].
#
# Travis CI uploads the cache after the script phase of the build [1].
-# However, the build is terminated without saving the chache if it takes over
+# However, the build is terminated without saving the cache if it takes over
# 50 minutes [2]. Thus, if we spent too much time in early build stages, fail
# with an error and save the cache.
#
@@ -40,38 +40,25 @@ stages:
- extended-lint
env:
global:
- - MAKEJOBS=-j3
- - RUN_UNIT_TESTS=true
- - RUN_FUNCTIONAL_TESTS=true
- - RUN_FUZZ_TESTS=false
- - DOCKER_NAME_TAG=ubuntu:18.04
- - BOOST_TEST_RANDOM=1$TRAVIS_BUILD_ID
- - CCACHE_SIZE=100M
- - CCACHE_TEMPDIR=/tmp/.ccache-temp
- - CCACHE_COMPRESS=1
- - CCACHE_DIR=$HOME/.ccache
- - BASE_OUTDIR=$TRAVIS_BUILD_DIR/out
- - SDK_URL=https://bitcoincore.org/depends-sources/sdks
- - WINEDEBUG=fixme-all
- - DOCKER_PACKAGES="build-essential libtool autotools-dev automake pkg-config bsdmainutils curl git ca-certificates ccache"
+ - CI_RETRY_EXE="travis_retry"
- CACHE_ERR_MSG="Error! Initial build successful, but not enough time remains to run later build stages and tests. Please manually re-run this job by using the travis restart button or asking a bitcoin maintainer to restart. The next run should not time out because the build cache has been saved."
before_install:
- - set -o errexit; source .travis/test_03_before_install.sh
+ - set -o errexit; source ./ci/test/00_setup_env.sh
+ - set -o errexit; source ./ci/test/03_before_install.sh
install:
- - set -o errexit; source .travis/test_04_install.sh
+ - set -o errexit; source ./ci/test/04_install.sh
before_script:
- - set -o errexit; source .travis/test_05_before_script.sh
+ - set -o errexit; source ./ci/test/05_before_script.sh
script:
- export CONTINUE=1
- if [ $SECONDS -gt 1200 ]; then export CONTINUE=0; fi # Likely the depends build took very long
- if [ $TRAVIS_REPO_SLUG = "bitcoin/bitcoin" ]; then export CONTINUE=1; fi # Whitelisted repo (90 minutes build time)
- - if [ $CONTINUE = "1" ]; then set -o errexit; source .travis/test_06_script_a.sh; else set +o errexit; echo "$CACHE_ERR_MSG"; false; fi
+ - if [ $CONTINUE = "1" ]; then set -o errexit; source ./ci/test/06_script_a.sh; else set +o errexit; echo "$CACHE_ERR_MSG"; false; fi
- if [ $SECONDS -gt 2000 ]; then export CONTINUE=0; fi # Likely the build took very long; The tests take about 1000s, so we should abort if we have less than 50*60-1000=2000s left
- if [ $TRAVIS_REPO_SLUG = "bitcoin/bitcoin" ]; then export CONTINUE=1; fi # Whitelisted repo (90 minutes build time)
- - if [ $CONTINUE = "1" ]; then set -o errexit; source .travis/test_06_script_b.sh; else set +o errexit; echo "$CACHE_ERR_MSG"; false; fi
+ - if [ $CONTINUE = "1" ]; then set -o errexit; source ./ci/test/06_script_b.sh; else set +o errexit; echo "$CACHE_ERR_MSG"; false; fi
after_script:
- echo $TRAVIS_COMMIT_RANGE
- - echo $TRAVIS_COMMIT_LOG
jobs:
include:
@@ -82,11 +69,11 @@ jobs:
language: python
python: '3.5' # Oldest supported version according to doc/dependencies.md
install:
- - set -o errexit; source .travis/lint_04_install.sh
+ - set -o errexit; source ./ci/lint/04_install.sh
before_script:
- - set -o errexit; source .travis/lint_05_before_script.sh
+ - set -o errexit; source ./ci/lint/05_before_script.sh
script:
- - set -o errexit; source .travis/lint_06_script.sh
+ - set -o errexit; source ./ci/lint/06_script.sh
- stage: extended-lint
name: 'extended lint [runtime >= 60 seconds]'
@@ -95,11 +82,11 @@ jobs:
language: python
python: '3.5'
install:
- - set -o errexit; source .travis/extended_lint_04_install.sh
+ - set -o errexit; source ./ci/extended_lint/04_install.sh
before_script:
- - set -o errexit; source .travis/lint_05_before_script.sh
+ - set -o errexit; source ./ci/lint/05_before_script.sh
script:
- - set -o errexit; source .travis/extended_lint_06_script.sh
+ - set -o errexit; source ./ci/extended_lint/06_script.sh
- stage: test
name: 'ARM [GOAL: install] [no unit or functional tests]'
diff --git a/.travis/README.md b/.travis/README.md
deleted file mode 100644
index 21d1b9cc03..0000000000
--- a/.travis/README.md
+++ /dev/null
@@ -1,8 +0,0 @@
-## travis build scripts
-
-The `.travis` directory contains scripts for each build step in each build stage.
-Currently the travis build defines two stages `lint` and `test`. Each stage has
-it's own [lifecycle](https://docs.travis-ci.com/user/customizing-the-build/#the-build-lifecycle).
-Every script in here is named and numbered according to which stage and lifecycle
-step it belongs to.
-
diff --git a/.travis/test_04_install.sh b/.travis/test_04_install.sh
deleted file mode 100755
index 319f2c5b21..0000000000
--- a/.travis/test_04_install.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/env bash
-#
-# Copyright (c) 2018 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-export LC_ALL=C.UTF-8
-
-free -m -h
-echo "Number of CPUs (nproc): $(nproc)"
-
-travis_retry docker pull "$DOCKER_NAME_TAG"
-
-export DIR_FUZZ_IN=${TRAVIS_BUILD_DIR}/qa-assets
-git clone https://github.com/bitcoin-core/qa-assets ${DIR_FUZZ_IN}
-export DIR_FUZZ_IN=${DIR_FUZZ_IN}/fuzz_seed_corpus/
-
-mkdir -p "${TRAVIS_BUILD_DIR}/sanitizer-output/"
-export ASAN_OPTIONS=""
-export LSAN_OPTIONS="suppressions=${TRAVIS_BUILD_DIR}/test/sanitizer_suppressions/lsan"
-export TSAN_OPTIONS="suppressions=${TRAVIS_BUILD_DIR}/test/sanitizer_suppressions/tsan:log_path=${TRAVIS_BUILD_DIR}/sanitizer-output/tsan"
-export UBSAN_OPTIONS="suppressions=${TRAVIS_BUILD_DIR}/test/sanitizer_suppressions/ubsan:print_stacktrace=1:halt_on_error=1"
-env | grep -E '^(BITCOIN_CONFIG|CCACHE_|WINEDEBUG|LC_ALL|BOOST_TEST_RANDOM|CONFIG_SHELL|(ASAN|LSAN|TSAN|UBSAN)_OPTIONS)' | tee /tmp/env
-if [[ $HOST = *-mingw32 ]]; then
- DOCKER_ADMIN="--cap-add SYS_ADMIN"
-elif [[ $BITCOIN_CONFIG = *--with-sanitizers=*address* ]]; then # If ran with (ASan + LSan), Docker needs access to ptrace (https://github.com/google/sanitizers/issues/764)
- DOCKER_ADMIN="--cap-add SYS_PTRACE"
-fi
-DOCKER_ID=$(docker run $DOCKER_ADMIN -idt --mount type=bind,src=$TRAVIS_BUILD_DIR,dst=$TRAVIS_BUILD_DIR --mount type=bind,src=$CCACHE_DIR,dst=$CCACHE_DIR -w $TRAVIS_BUILD_DIR --env-file /tmp/env $DOCKER_NAME_TAG)
-
-DOCKER_EXEC () {
- docker exec $DOCKER_ID bash -c "cd $PWD && $*"
-}
-
-travis_retry DOCKER_EXEC apt-get update
-travis_retry DOCKER_EXEC apt-get install --no-install-recommends --no-upgrade -qq $PACKAGES $DOCKER_PACKAGES
-
diff --git a/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj b/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj
index 73ba90aa88..f21ba7a82b 100644
--- a/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj
+++ b/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj
@@ -406,9 +406,6 @@
<None Include="..\..\src\qtes\src\tx_inout.svg">
<DeploymentContent>true</DeploymentContent>
</None>
- <None Include="..\..\src\qtes\src\verify.svg">
- <DeploymentContent>true</DeploymentContent>
- </None>
<None Include="GeneratedFiles\bitcoin.moc" />
<None Include="GeneratedFiles\bitcoinamountfield.moc" />
<None Include="GeneratedFiles\intro.moc" />
@@ -416,12 +413,6 @@
<None Include="GeneratedFilespcconsole.moc" />
</ItemGroup>
<ItemGroup>
- <Image Include="..\..\src\qtes\icons\about.png">
- <DeploymentContent>true</DeploymentContent>
- </Image>
- <Image Include="..\..\src\qtes\icons\about_qt.png">
- <DeploymentContent>true</DeploymentContent>
- </Image>
<Image Include="..\..\src\qtes\icons\add.png">
<DeploymentContent>true</DeploymentContent>
</Image>
@@ -455,9 +446,6 @@
<Image Include="..\..\src\qtes\icons\clock5.png">
<DeploymentContent>true</DeploymentContent>
</Image>
- <Image Include="..\..\src\qtes\icons\configure.png">
- <DeploymentContent>true</DeploymentContent>
- </Image>
<Image Include="..\..\src\qtes\icons\connect0.png">
<DeploymentContent>true</DeploymentContent>
</Image>
@@ -473,9 +461,6 @@
<Image Include="..\..\src\qtes\icons\connect4.png">
<DeploymentContent>true</DeploymentContent>
</Image>
- <Image Include="..\..\src\qtes\icons\debugwindow.png">
- <DeploymentContent>true</DeploymentContent>
- </Image>
<Image Include="..\..\src\qtes\icons\edit.png">
<DeploymentContent>true</DeploymentContent>
</Image>
@@ -497,9 +482,6 @@
<Image Include="..\..\src\qtes\icons\eye_plus.png">
<DeploymentContent>true</DeploymentContent>
</Image>
- <Image Include="..\..\src\qtes\icons\filesave.png">
- <DeploymentContent>true</DeploymentContent>
- </Image>
<Image Include="..\..\src\qtes\icons\fontbigger.png">
<DeploymentContent>true</DeploymentContent>
</Image>
@@ -518,9 +500,6 @@
<Image Include="..\..\src\qtes\icons\info.png">
<DeploymentContent>true</DeploymentContent>
</Image>
- <Image Include="..\..\src\qtes\icons\key.png">
- <DeploymentContent>true</DeploymentContent>
- </Image>
<Image Include="..\..\src\qtes\icons\lock_closed.png">
<DeploymentContent>true</DeploymentContent>
</Image>
@@ -530,15 +509,9 @@
<Image Include="..\..\src\qtes\icons\network_disabled.png">
<DeploymentContent>true</DeploymentContent>
</Image>
- <Image Include="..\..\src\qtes\icons\open.png">
- <DeploymentContent>true</DeploymentContent>
- </Image>
<Image Include="..\..\src\qtes\icons\overview.png">
<DeploymentContent>true</DeploymentContent>
</Image>
- <Image Include="..\..\src\qtes\icons\quit.png">
- <DeploymentContent>true</DeploymentContent>
- </Image>
<Image Include="..\..\src\qtes\iconseceive.png">
<DeploymentContent>true</DeploymentContent>
</Image>
@@ -575,9 +548,6 @@
<Image Include="..\..\src\qtes\icons\tx_output.png">
<DeploymentContent>true</DeploymentContent>
</Image>
- <Image Include="..\..\src\qtes\icons\verify.png">
- <DeploymentContent>true</DeploymentContent>
- </Image>
<Image Include="..\..\src\qtes\icons\warning.png">
<DeploymentContent>true</DeploymentContent>
</Image>
diff --git a/ci/README.md b/ci/README.md
new file mode 100644
index 0000000000..754cbc7c95
--- /dev/null
+++ b/ci/README.md
@@ -0,0 +1,25 @@
+## ci scripts
+
+This directory contains scripts for each build step in each build stage.
+
+Currently three stages `lint`, `extended_lint` and `test` are defined. Each stage has its own lifecycle, similar to the
+[Travis CI lifecycle](https://docs.travis-ci.com/user/job-lifecycle#the-job-lifecycle). Every script in here is named
+and numbered according to which stage and lifecycle step it belongs to.
+
+### Running a stage locally
+
+To allow for a wide range of tested environments, but also ensure reproducibility to some extent, the test stage
+requires `docker` to be installed. To install all requirements on Ubuntu, run
+
+```
+sudo apt install docker.io ccache bash git
+```
+
+To run the test stage,
+
+```
+./ci/test_run_all.sh
+```
+
+Be aware that the tests will be build and run in-place, so please run at your own risk.
+If the repository is not a fresh git clone, you might have to clean files from previous builds or test runs first.
diff --git a/.travis/extended_lint_04_install.sh b/ci/extended_lint/04_install.sh
index 123d874a84..123d874a84 100755
--- a/.travis/extended_lint_04_install.sh
+++ b/ci/extended_lint/04_install.sh
diff --git a/.travis/extended_lint_06_script.sh b/ci/extended_lint/06_script.sh
index e8228c9c4d..e8228c9c4d 100755
--- a/.travis/extended_lint_06_script.sh
+++ b/ci/extended_lint/06_script.sh
diff --git a/.travis/lint_04_install.sh b/ci/lint/04_install.sh
index 62174620f2..20bff368a5 100755
--- a/.travis/lint_04_install.sh
+++ b/ci/lint/04_install.sh
@@ -6,9 +6,9 @@
export LC_ALL=C
-travis_retry pip install codespell==1.15.0
-travis_retry pip install flake8==3.5.0
-travis_retry pip install vulture==0.29
+travis_retry pip3 install codespell==1.15.0
+travis_retry pip3 install flake8==3.5.0
+travis_retry pip3 install vulture==0.29
SHELLCHECK_VERSION=v0.6.0
curl -s "https://storage.googleapis.com/shellcheck/shellcheck-${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" | tar --xz -xf - --directory /tmp/
diff --git a/.travis/lint_05_before_script.sh b/ci/lint/05_before_script.sh
index 28bcbb47f7..28bcbb47f7 100755
--- a/.travis/lint_05_before_script.sh
+++ b/ci/lint/05_before_script.sh
diff --git a/.travis/lint_06_script.sh b/ci/lint/06_script.sh
index c7dea599dc..c7dea599dc 100755
--- a/.travis/lint_06_script.sh
+++ b/ci/lint/06_script.sh
diff --git a/ci/retry/README.md b/ci/retry/README.md
new file mode 100644
index 0000000000..983a498070
--- /dev/null
+++ b/ci/retry/README.md
@@ -0,0 +1,123 @@
+retry - The command line retry tool
+------------------------------------------
+
+Retry any shell command with exponential backoff or constant delay.
+
+### Instructions
+
+Install:
+
+retry is a shell script, so drop it somewhere and make sure it's added to your $PATH. Or you can use the following one-liner:
+
+```sh
+sudo sh -c "curl https://raw.githubusercontent.com/kadwanev/retry/master/retry -o /usr/local/bin/retry && chmod +x /usr/local/bin/retry"
+```
+
+If you're on OS X, retry is also on Homebrew:
+
+```
+brew pull 27283
+brew install retry
+```
+Not popular enough for homebrew-core. Please star this project to help.
+
+### Usage
+
+Help:
+
+`retry -?`
+
+ Usage: retry [options] -- execute command
+ -h, -?, --help
+ -v, --verbose Verbose output
+ -t, --tries=# Set max retries: Default 10
+ -s, --sleep=secs Constant sleep amount (seconds)
+ -m, --min=secs Exponenetial Backoff: minimum sleep amount (seconds): Default 0.3
+ -x, --max=secs Exponenetial Backoff: maximum sleep amount (seconds): Default 60
+ -f, --fail="script +cmds" Fail Script: run in case of final failure
+
+### Examples
+
+No problem:
+
+`retry echo u work good`
+
+ u work good
+
+Test functionality:
+
+`retry 'echo "y u no work"; false'`
+
+ y u no work
+ Before retry #1: sleeping 0.3 seconds
+ y u no work
+ Before retry #2: sleeping 0.6 seconds
+ y u no work
+ Before retry #3: sleeping 1.2 seconds
+ y u no work
+ Before retry #4: sleeping 2.4 seconds
+ y u no work
+ Before retry #5: sleeping 4.8 seconds
+ y u no work
+ Before retry #6: sleeping 9.6 seconds
+ y u no work
+ Before retry #7: sleeping 19.2 seconds
+ y u no work
+ Before retry #8: sleeping 38.4 seconds
+ y u no work
+ Before retry #9: sleeping 60.0 seconds
+ y u no work
+ Before retry #10: sleeping 60.0 seconds
+ y u no work
+ etc..
+
+Limit retries:
+
+`retry -t 4 'echo "y u no work"; false'`
+
+ y u no work
+ Before retry #1: sleeping 0.3 seconds
+ y u no work
+ Before retry #2: sleeping 0.6 seconds
+ y u no work
+ Before retry #3: sleeping 1.2 seconds
+ y u no work
+ Before retry #4: sleeping 2.4 seconds
+ y u no work
+ Retries exhausted
+
+Bad command:
+
+`retry poop`
+
+ bash: poop: command not found
+
+Fail command:
+
+`retry -t 3 -f 'echo "oh poopsickles"' 'echo "y u no work"; false'`
+
+ y u no work
+ Before retry #1: sleeping 0.3 seconds
+ y u no work
+ Before retry #2: sleeping 0.6 seconds
+ y u no work
+ Before retry #3: sleeping 1.2 seconds
+ y u no work
+ Retries exhausted, running fail script
+ oh poopsickles
+
+Last attempt passed:
+
+`retry -t 3 -- 'if [ $RETRY_ATTEMPT -eq 3 ]; then echo Passed at attempt $RETRY_ATTEMPT; true; else echo Failed at attempt $RETRY_ATTEMPT; false; fi;'`
+
+ Failed at attempt 0
+ Before retry #1: sleeping 0.3 seconds
+ Failed at attempt 1
+ Before retry #2: sleeping 0.6 seconds
+ Failed at attempt 2
+ Before retry #3: sleeping 1.2 seconds
+ Passed at attempt 3
+
+### License
+
+Apache 2.0 - go nuts
diff --git a/ci/retry/retry b/ci/retry/retry
new file mode 100755
index 0000000000..0e5f6e9701
--- /dev/null
+++ b/ci/retry/retry
@@ -0,0 +1,163 @@
+#!/usr/bin/env bash
+
+GETOPT_BIN=$IN_GETOPT_BIN
+GETOPT_BIN=${GETOPT_BIN:-getopt}
+
+__sleep_amount() {
+ if [ -n "$constant_sleep" ]; then
+ sleep_time=$constant_sleep
+ else
+ #TODO: check for awk
+ #TODO: check if user would rather use one of the other possible dependencies: python, ruby, bc, dc
+ sleep_time=`awk "BEGIN {t = $min_sleep * $(( (1<<($attempts -1)) )); print (t > $max_sleep ? $max_sleep : t)}"`
+ fi
+}
+
+__log_out() {
+ echo "$1" 1>&2
+}
+
+# Paramters: max_tries min_sleep max_sleep constant_sleep fail_script EXECUTION_COMMAND
+retry()
+{
+ local max_tries="$1"; shift
+ local min_sleep="$1"; shift
+ local max_sleep="$1"; shift
+ local constant_sleep="$1"; shift
+ local fail_script="$1"; shift
+ if [ -n "$VERBOSE" ]; then
+ __log_out "Retry Parameters: max_tries=$max_tries min_sleep=$min_sleep max_sleep=$max_sleep constant_sleep=$constant_sleep"
+ if [ -n "$fail_script" ]; then __log_out "Fail script: $fail_script"; fi
+ __log_out ""
+ __log_out "Execution Command: $*"
+ __log_out ""
+ fi
+
+ local attempts=0
+ local return_code=1
+
+
+ while [[ $return_code -ne 0 && $attempts -le $max_tries ]]; do
+ if [ $attempts -gt 0 ]; then
+ __sleep_amount
+ __log_out "Before retry #$attempts: sleeping $sleep_time seconds"
+ sleep $sleep_time
+ fi
+
+ P="$1"
+ for param in "${@:2}"; do P="$P '$param'"; done
+ #TODO: replace single quotes in each arg with '"'"' ?
+ export RETRY_ATTEMPT=$attempts
+ bash -c "$P"
+ return_code=$?
+ #__log_out "Process returned $return_code on attempt $attempts"
+ if [ $return_code -eq 127 ]; then
+ # command not found
+ exit $return_code
+ elif [ $return_code -ne 0 ]; then
+ attempts=$[$attempts +1]
+ fi
+ done
+
+ if [ $attempts -gt $max_tries ]; then
+ if [ -n "$fail_script" ]; then
+ __log_out "Retries exhausted, running fail script"
+ eval $fail_script
+ else
+ __log_out "Retries exhausted"
+ fi
+ fi
+
+ exit $return_code
+}
+
+# If we're being sourced, don't worry about such things
+if [ "$BASH_SOURCE" == "$0" ]; then
+ # Prints the help text
+ help()
+ {
+ local retry=$(basename $0)
+ cat <<EOF
+Usage: $retry [options] -- execute command
+ -h, -?, --help
+ -v, --verbose Verbose output
+ -t, --tries=# Set max retries: Default 10
+ -s, --sleep=secs Constant sleep amount (seconds)
+ -m, --min=secs Exponenetial Backoff: minimum sleep amount (seconds): Default 0.3
+ -x, --max=secs Exponenetial Backoff: maximum sleep amount (seconds): Default 60
+ -f, --fail="script +cmds" Fail Script: run in case of final failure
+EOF
+ }
+
+ # show help for no arguments if stdin is a terminal
+ if { [ -z "$1" ] && [ -t 0 ] ; } || [ "$1" == '-h' ] || [ "$1" == '-?' ] || [ "$1" == '--help' ]
+ then
+ help
+ exit 0
+ fi
+
+ $GETOPT_BIN --test > /dev/null
+ if [[ $? -ne 4 ]]; then
+ echo "I’m sorry, 'getopt --test' failed in this environment. Please load GNU getopt."
+ exit 1
+ fi
+
+ OPTIONS=vt:s:m:x:f:
+ LONGOPTIONS=verbose,tries:,sleep:,min:,max:,fail:
+
+ PARSED=$($GETOPT_BIN --options="$OPTIONS" --longoptions="$LONGOPTIONS" --name "$0" -- "$@")
+ if [[ $? -ne 0 ]]; then
+ # e.g. $? == 1
+ # then getopt has complained about wrong arguments to stdout
+ exit 2
+ fi
+ # read getopt’s output this way to handle the quoting right:
+ eval set -- "$PARSED"
+
+ max_tries=10
+ min_sleep=0.3
+ max_sleep=60.0
+ constant_sleep=
+ fail_script=
+
+ # now enjoy the options in order and nicely split until we see --
+ while true; do
+ case "$1" in
+ -v|--verbose)
+ VERBOSE=true
+ shift
+ ;;
+ -t|--tries)
+ max_tries="$2"
+ shift 2
+ ;;
+ -s|--sleep)
+ constant_sleep="$2"
+ shift 2
+ ;;
+ -m|--min)
+ min_sleep="$2"
+ shift 2
+ ;;
+ -x|--max)
+ max_sleep="$2"
+ shift 2
+ ;;
+ -f|--fail)
+ fail_script="$2"
+ shift 2
+ ;;
+ --)
+ shift
+ break
+ ;;
+ *)
+ echo "Programming error"
+ exit 3
+ ;;
+ esac
+ done
+
+ retry "$max_tries" "$min_sleep" "$max_sleep" "$constant_sleep" "$fail_script" "$@"
+
+fi
diff --git a/ci/test/00_setup_env.sh b/ci/test/00_setup_env.sh
new file mode 100755
index 0000000000..fae48ba176
--- /dev/null
+++ b/ci/test/00_setup_env.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) 2019 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+export LC_ALL=C.UTF-8
+
+echo "Setting default values in env"
+
+BASE_ROOT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../../ >/dev/null 2>&1 && pwd )
+export BASE_ROOT_DIR
+
+export MAKEJOBS=${MAKEJOBS:--j3}
+export HOST=${HOST:-x86_64-unknown-linux-gnu}
+export RUN_UNIT_TESTS=${RUN_UNIT_TESTS:-true}
+export RUN_FUNCTIONAL_TESTS=${RUN_FUNCTIONAL_TESTS:-true}
+export RUN_FUZZ_TESTS=${RUN_FUZZ_TESTS:-false}
+export DOCKER_NAME_TAG=${DOCKER_NAME_TAG:-ubuntu:18.04}
+export BOOST_TEST_RANDOM=${BOOST_TEST_RANDOM:-1$TRAVIS_BUILD_ID}
+export CCACHE_SIZE=${CCACHE_SIZE:-100M}
+export CCACHE_TEMPDIR=${CCACHE_TEMPDIR:-/tmp/.ccache-temp}
+export CCACHE_COMPRESS=${CCACHE_COMPRESS:-1}
+export CCACHE_DIR=${CCACHE_DIR:-$HOME/.ccache}
+export BASE_BUILD_DIR=${BASE_BUILD_DIR:-${TRAVIS_BUILD_DIR:-$BASE_ROOT_DIR}}
+export BASE_OUTDIR=${BASE_OUTDIR:-$BASE_BUILD_DIR/out/$HOST}
+export SDK_URL=${SDK_URL:-https://bitcoincore.org/depends-sources/sdks}
+export WINEDEBUG=${WINEDEBUG:-fixme-all}
+export DOCKER_PACKAGES=${DOCKER_PACKAGES:-build-essential libtool autotools-dev automake pkg-config bsdmainutils curl ca-certificates ccache python3}
+export GOAL=${GOAL:-install}
+export DIR_QA_ASSETS=${DIR_QA_ASSETS:-${BASE_BUILD_DIR}/qa-assets}
+export PATH=${BASE_ROOT_DIR}/ci/retry:$PATH
+export CI_RETRY_EXE=${CI_RETRY_EXE:retry}
diff --git a/.travis/test_03_before_install.sh b/ci/test/03_before_install.sh
index 3c9fcf3f98..5086114ba1 100755
--- a/.travis/test_03_before_install.sh
+++ b/ci/test/03_before_install.sh
@@ -6,7 +6,6 @@
export LC_ALL=C.UTF-8
-PATH=$(echo $PATH | tr ':' "\n" | sed '/\/opt\/python/d' | tr "\n" ":" | sed "s|::|:|g")
# Add llvm-symbolizer directory to PATH. Needed to get symbolized stack traces from the sanitizers.
PATH=$PATH:/usr/lib/llvm-6.0/bin/
export PATH
diff --git a/ci/test/04_install.sh b/ci/test/04_install.sh
new file mode 100755
index 0000000000..3535746e83
--- /dev/null
+++ b/ci/test/04_install.sh
@@ -0,0 +1,49 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) 2018 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+export LC_ALL=C.UTF-8
+
+ccache echo "Creating ccache dir if it didn't already exist"
+
+if [ ! -d ${DIR_QA_ASSETS} ]; then
+ git clone https://github.com/bitcoin-core/qa-assets ${DIR_QA_ASSETS}
+fi
+export DIR_FUZZ_IN=${DIR_QA_ASSETS}/fuzz_seed_corpus/
+
+mkdir -p "${BASE_BUILD_DIR}/sanitizer-output/"
+export ASAN_OPTIONS=""
+export LSAN_OPTIONS="suppressions=${BASE_BUILD_DIR}/test/sanitizer_suppressions/lsan"
+export TSAN_OPTIONS="suppressions=${BASE_BUILD_DIR}/test/sanitizer_suppressions/tsan:log_path=${BASE_BUILD_DIR}/sanitizer-output/tsan"
+export UBSAN_OPTIONS="suppressions=${BASE_BUILD_DIR}/test/sanitizer_suppressions/ubsan:print_stacktrace=1:halt_on_error=1"
+env | grep -E '^(BITCOIN_CONFIG|CCACHE_|WINEDEBUG|LC_ALL|BOOST_TEST_RANDOM|CONFIG_SHELL|(ASAN|LSAN|TSAN|UBSAN)_OPTIONS)' | tee /tmp/env
+if [[ $HOST = *-mingw32 ]]; then
+ DOCKER_ADMIN="--cap-add SYS_ADMIN"
+elif [[ $BITCOIN_CONFIG = *--with-sanitizers=*address* ]]; then # If ran with (ASan + LSan), Docker needs access to ptrace (https://github.com/google/sanitizers/issues/764)
+ DOCKER_ADMIN="--cap-add SYS_PTRACE"
+fi
+
+if [ -z "$RUN_CI_ON_HOST" ]; then
+ echo "Creating $DOCKER_NAME_TAG container to run in"
+ ${CI_RETRY_EXE} docker pull "$DOCKER_NAME_TAG"
+
+ DOCKER_ID=$(docker run $DOCKER_ADMIN -idt --mount type=bind,src=$BASE_BUILD_DIR,dst=$BASE_BUILD_DIR --mount type=bind,src=$CCACHE_DIR,dst=$CCACHE_DIR -w $BASE_BUILD_DIR --env-file /tmp/env $DOCKER_NAME_TAG)
+
+ DOCKER_EXEC () {
+ docker exec $DOCKER_ID bash -c "cd $PWD && $*"
+ }
+else
+ echo "Running on host system without docker wrapper"
+ DOCKER_EXEC () {
+ bash -c "cd $PWD && $*"
+ }
+fi
+
+DOCKER_EXEC free -m -h
+DOCKER_EXEC echo "Number of CPUs \(nproc\): $(nproc)"
+
+${CI_RETRY_EXE} DOCKER_EXEC apt-get update
+${CI_RETRY_EXE} DOCKER_EXEC apt-get install --no-install-recommends --no-upgrade -qq $PACKAGES $DOCKER_PACKAGES
+
diff --git a/.travis/test_05_before_script.sh b/ci/test/05_before_script.sh
index 516d3fc042..516d3fc042 100755
--- a/.travis/test_05_before_script.sh
+++ b/ci/test/05_before_script.sh
diff --git a/.travis/test_06_script_a.sh b/ci/test/06_script_a.sh
index 8cc593f936..eb6ade7919 100755
--- a/.travis/test_06_script_a.sh
+++ b/ci/test/06_script_a.sh
@@ -6,11 +6,7 @@
export LC_ALL=C.UTF-8
-TRAVIS_COMMIT_LOG=$(git log --format=fuller -1)
-export TRAVIS_COMMIT_LOG
-
-OUTDIR=$BASE_OUTDIR/$TRAVIS_PULL_REQUEST/$TRAVIS_JOB_NUMBER-$HOST
-BITCOIN_CONFIG_ALL="--disable-dependency-tracking --prefix=$TRAVIS_BUILD_DIR/depends/$HOST --bindir=$OUTDIR/bin --libdir=$OUTDIR/lib"
+BITCOIN_CONFIG_ALL="--disable-dependency-tracking --prefix=$BASE_BUILD_DIR/depends/$HOST --bindir=$BASE_OUTDIR/bin --libdir=$BASE_OUTDIR/lib"
if [ -z "$NO_DEPENDS" ]; then
DOCKER_EXEC ccache --max-size=$CCACHE_SIZE
fi
@@ -23,7 +19,7 @@ else
fi
END_FOLD
-mkdir build
+mkdir -p build
cd build || (echo "could not enter build directory"; exit 1)
BEGIN_FOLD configure
@@ -41,10 +37,10 @@ DOCKER_EXEC ./configure --cache-file=../config.cache $BITCOIN_CONFIG_ALL $BITCOI
END_FOLD
set -o errtrace
-trap 'DOCKER_EXEC "cat ${TRAVIS_BUILD_DIR}/sanitizer-output/* 2> /dev/null"' ERR
+trap 'DOCKER_EXEC "cat ${BASE_BUILD_DIR}/sanitizer-output/* 2> /dev/null"' ERR
BEGIN_FOLD build
DOCKER_EXEC make $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && DOCKER_EXEC make $GOAL V=1 ; false )
END_FOLD
-cd ${TRAVIS_BUILD_DIR} || (echo "could not enter travis build dir $TRAVIS_BUILD_DIR"; exit 1)
+cd ${BASE_BUILD_DIR} || (echo "could not enter travis build dir $BASE_BUILD_DIR"; exit 1)
diff --git a/.travis/test_06_script_b.sh b/ci/test/06_script_b.sh
index e40055a6ee..fafb6e0493 100755
--- a/.travis/test_06_script_b.sh
+++ b/ci/test/06_script_b.sh
@@ -10,7 +10,7 @@ cd "build/bitcoin-$HOST" || (echo "could not enter distdir build/bitcoin-$HOST";
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
+ DOCKER_EXEC LD_LIBRARY_PATH=$BASE_BUILD_DIR/depends/$HOST/lib make $MAKEJOBS check VERBOSE=1
END_FOLD
fi
@@ -26,4 +26,4 @@ if [ "$RUN_FUZZ_TESTS" = "true" ]; then
END_FOLD
fi
-cd ${TRAVIS_BUILD_DIR} || (echo "could not enter travis build dir $TRAVIS_BUILD_DIR"; exit 1)
+cd ${BASE_BUILD_DIR} || (echo "could not enter travis build dir $BASE_BUILD_DIR"; exit 1)
diff --git a/ci/test_run_all.sh b/ci/test_run_all.sh
new file mode 100755
index 0000000000..a39f1f9f09
--- /dev/null
+++ b/ci/test_run_all.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) 2019 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+export LC_ALL=C.UTF-8
+
+echo "Setting default values in env"
+
+set -o errexit; source ./ci/test/00_setup_env.sh
+set -o errexit; source ./ci/test/03_before_install.sh
+set -o errexit; source ./ci/test/04_install.sh
+set -o errexit; source ./ci/test/05_before_script.sh
+set -o errexit; source ./ci/test/06_script_a.sh
+set -o errexit; source ./ci/test/06_script_b.sh
diff --git a/contrib/debian/copyright b/contrib/debian/copyright
index 8fb9df9e6c..0eccbacb96 100644
--- a/contrib/debian/copyright
+++ b/contrib/debian/copyright
@@ -26,21 +26,14 @@ License: GNU-All-permissive-License
Files: src/qt/res/icons/add.png
src/qt/res/icons/address-book.png
src/qt/res/icons/chevron.png
- src/qt/res/icons/configure.png
- src/qt/res/icons/debugwindow.png
src/qt/res/icons/edit.png
src/qt/res/icons/editcopy.png
src/qt/res/icons/editpaste.png
src/qt/res/icons/export.png
src/qt/res/icons/eye.png
- src/qt/res/icons/filesave.png
src/qt/res/icons/history.png
- src/qt/res/icons/info.png
- src/qt/res/icons/key.png
src/qt/res/icons/lock_*.png
- src/qt/res/icons/open.png
src/qt/res/icons/overview.png
- src/qt/res/icons/quit.png
src/qt/res/icons/receive.png
src/qt/res/icons/remove.png
src/qt/res/icons/send.png
@@ -76,16 +69,13 @@ License: Expat
Files: src/qt/res/icons/clock*.png
src/qt/res/icons/eye_*.png
src/qt/res/icons/tx_in*.png
- src/qt/res/icons/verify.png
src/qt/res/src/clock_*.svg
src/qt/res/src/tx_*.svg
- src/qt/res/src/verify.svg
Copyright: Stephen Hutchings, Jonas Schnelli
License: Expat
Comment: Modifications of Stephen Hutchings' Typicons
-Files: src/qt/res/icons/about.png
- src/qt/res/icons/bitcoin.*
+Files: src/qt/res/icons/bitcoin.*
share/pixmaps/bitcoin*
src/qt/res/src/bitcoin.svg
Copyright: Bitboy, Jonas Schnelli
diff --git a/doc/release-notes-16060.md b/doc/release-notes-16060.md
new file mode 100644
index 0000000000..7e150d10e7
--- /dev/null
+++ b/doc/release-notes-16060.md
@@ -0,0 +1,15 @@
+Low-level RPC changes
+----------------------
+
+- Soft fork reporting in the `getblockchaininfo` return object has been
+ updated. For full details, see the RPC help text. In summary:
+ - The `bip9_softforks` sub-object is no longer returned
+ - The `softforks` sub-object now returns an object keyed by soft fork name,
+ rather than an array
+ - Each softfork object in the `softforks` object contains a `type` value which
+ is either `buried` (for soft fork deployments where the activation height is
+ hard-coded into the client implementation), or `bip9` (for soft fork deployments
+ where activation is controlled by BIP 9 signaling).
+
+- `getblocktemplate` no longer returns a `rules` array containing `CSV`
+ and `segwit` (the BIP 9 deployments that are currently in active state).
diff --git a/doc/release-notes-16383.md b/doc/release-notes-16383.md
new file mode 100644
index 0000000000..8015715167
--- /dev/null
+++ b/doc/release-notes-16383.md
@@ -0,0 +1,8 @@
+RPC changes
+-----------
+
+RPCs which have an `include_watchonly` argument or `includeWatching`
+option now default to `true` for watch-only wallets. Affected RPCs
+are: `getbalance`, `listreceivedbyaddress`, `listreceivedbylabel`,
+`listtransactions`, `listsinceblock`, `gettransaction`,
+`walletcreatefundedpsbt`, and `fundrawtransaction`.
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index 3ae8498a87..6d8faf3883 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -250,8 +250,6 @@ BITCOIN_QT_H = \
RES_ICONS = \
qt/res/icons/add.png \
qt/res/icons/address-book.png \
- qt/res/icons/about.png \
- qt/res/icons/about_qt.png \
qt/res/icons/bitcoin.ico \
qt/res/icons/bitcoin_testnet.ico \
qt/res/icons/bitcoin.png \
@@ -261,13 +259,11 @@ RES_ICONS = \
qt/res/icons/clock3.png \
qt/res/icons/clock4.png \
qt/res/icons/clock5.png \
- qt/res/icons/configure.png \
qt/res/icons/connect0.png \
qt/res/icons/connect1.png \
qt/res/icons/connect2.png \
qt/res/icons/connect3.png \
qt/res/icons/connect4.png \
- qt/res/icons/debugwindow.png \
qt/res/icons/edit.png \
qt/res/icons/editcopy.png \
qt/res/icons/editpaste.png \
@@ -275,21 +271,16 @@ RES_ICONS = \
qt/res/icons/eye.png \
qt/res/icons/eye_minus.png \
qt/res/icons/eye_plus.png \
- qt/res/icons/filesave.png \
qt/res/icons/fontbigger.png \
qt/res/icons/fontsmaller.png \
qt/res/icons/hd_disabled.png \
qt/res/icons/hd_enabled.png \
qt/res/icons/history.png \
- qt/res/icons/info.png \
- qt/res/icons/key.png \
qt/res/icons/lock_closed.png \
qt/res/icons/lock_open.png \
qt/res/icons/network_disabled.png \
- qt/res/icons/open.png \
qt/res/icons/overview.png \
qt/res/icons/proxy.png \
- qt/res/icons/quit.png \
qt/res/icons/receive.png \
qt/res/icons/remove.png \
qt/res/icons/send.png \
@@ -302,8 +293,7 @@ RES_ICONS = \
qt/res/icons/tx_input.png \
qt/res/icons/tx_output.png \
qt/res/icons/tx_mined.png \
- qt/res/icons/warning.png \
- qt/res/icons/verify.png
+ qt/res/icons/warning.png
BITCOIN_QT_BASE_CPP = \
qt/bantablemodel.cpp \
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index c24234aeb7..ad766471dc 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -69,6 +69,8 @@ public:
consensus.BIP34Hash = uint256S("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8");
consensus.BIP65Height = 388381; // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0
consensus.BIP66Height = 363725; // 00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931
+ consensus.CSVHeight = 419328; // 000000000000000004a1b34462cb8aeebd5799177f7a29cf28f2d1961716b5b5
+ consensus.SegwitHeight = 481824; // 0000000000000000001c8018d9cb3b742ef25114f27563e3fc4a1902167f9893
consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 10 * 60;
@@ -80,16 +82,6 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008
- // Deployment of BIP68, BIP112, and BIP113.
- consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0;
- consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1462060800; // May 1st, 2016
- consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800; // May 1st, 2017
-
- // Deployment of SegWit (BIP141, BIP143, and BIP147)
- consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1;
- consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1479168000; // November 15th, 2016.
- consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1510704000; // November 15th, 2017.
-
// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000051dc8b82f450202ecb3d471");
@@ -183,6 +175,8 @@ public:
consensus.BIP34Hash = uint256S("0x0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8");
consensus.BIP65Height = 581885; // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6
consensus.BIP66Height = 330776; // 000000002104c8c45e99a8853285a3b592602a3ccde2b832481da85e9e4ba182
+ consensus.CSVHeight = 770112; // 00000000025e930139bac5c6c31a403776da130831ab85be56578f3fa75369bb
+ consensus.SegwitHeight = 834624; // 00000000002b980fcd729daaa248fd9316a5200e9b367f4ff2c42453e84201ca
consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 10 * 60;
@@ -194,16 +188,6 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008
- // Deployment of BIP68, BIP112, and BIP113.
- consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0;
- consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1456790400; // March 1st, 2016
- consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800; // May 1st, 2017
-
- // Deployment of SegWit (BIP141, BIP143, and BIP147)
- consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1;
- consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1462060800; // May 1st 2016
- consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1493596800; // May 1st 2017
-
// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000007dbe94253893cbd463");
@@ -275,6 +259,8 @@ public:
consensus.BIP34Hash = uint256();
consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in functional tests)
consensus.BIP66Height = 1251; // BIP66 activated on regtest (Used in functional tests)
+ consensus.CSVHeight = 432; // CSV activated on regtest (Used in rpc activation tests)
+ consensus.SegwitHeight = 0; // SEGWIT is always activated on regtest unless overridden
consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 10 * 60;
@@ -285,12 +271,6 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
- consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0;
- consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 0;
- consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
- consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1;
- consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
- consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00");
@@ -307,7 +287,7 @@ public:
m_assumed_blockchain_size = 0;
m_assumed_chain_state_size = 0;
- UpdateVersionBitsParametersFromArgs(args);
+ UpdateActivationParametersFromArgs(args);
genesis = CreateGenesisBlock(1296688602, 2, 0x207fffff, 1, 50 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
@@ -350,11 +330,22 @@ public:
consensus.vDeployments[d].nStartTime = nStartTime;
consensus.vDeployments[d].nTimeout = nTimeout;
}
- void UpdateVersionBitsParametersFromArgs(const ArgsManager& args);
+ void UpdateActivationParametersFromArgs(const ArgsManager& args);
};
-void CRegTestParams::UpdateVersionBitsParametersFromArgs(const ArgsManager& args)
+void CRegTestParams::UpdateActivationParametersFromArgs(const ArgsManager& args)
{
+ if (gArgs.IsArgSet("-segwitheight")) {
+ int64_t height = gArgs.GetArg("-segwitheight", consensus.SegwitHeight);
+ if (height < -1 || height >= std::numeric_limits<int>::max()) {
+ throw std::runtime_error(strprintf("Activation height %ld for segwit is out of valid range. Use -1 to disable segwit.", height));
+ } else if (height == -1) {
+ LogPrintf("Segwit disabled for testing\n");
+ height = std::numeric_limits<int>::max();
+ }
+ consensus.SegwitHeight = static_cast<int>(height);
+ }
+
if (!args.IsArgSet("-vbparams")) return;
for (const std::string& strDeployment : args.GetArgs("-vbparams")) {
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index deb8e0fb57..9b98dff3ca 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -19,6 +19,7 @@ void SetupChainParamsBaseOptions()
{
gArgs.AddArg("-regtest", "Enter regression test mode, which uses a special chain in which blocks can be solved instantly. "
"This is intended for regression testing tools and app development.", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
+ gArgs.AddArg("-segwitheight=<n>", "Set the activation height of segwit. -1 to disable. (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-testnet", "Use the test chain", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS);
gArgs.AddArg("-vbparams=deployment:start:end", "Use given start/end times for specified version bits deployment (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS);
}
diff --git a/src/consensus/params.h b/src/consensus/params.h
index 6c3a201f4f..8263b0fef4 100644
--- a/src/consensus/params.h
+++ b/src/consensus/params.h
@@ -16,8 +16,6 @@ namespace Consensus {
enum DeploymentPos
{
DEPLOYMENT_TESTDUMMY,
- DEPLOYMENT_CSV, // Deployment of BIP68, BIP112, and BIP113.
- DEPLOYMENT_SEGWIT, // Deployment of BIP141, BIP143, and BIP147.
// NOTE: Also add new deployments to VersionBitsDeploymentInfo in versionbits.cpp
MAX_VERSION_BITS_DEPLOYMENTS
};
@@ -58,6 +56,12 @@ struct Params {
int BIP65Height;
/** Block height at which BIP66 becomes active */
int BIP66Height;
+ /** Block height at which CSV (BIP68, BIP112 and BIP113) becomes active */
+ int CSVHeight;
+ /** Block height at which Segwit (BIP141, BIP143 and BIP147) becomes active.
+ * Note that segwit v0 script rules are enforced on all blocks except the
+ * BIP 16 exception blocks. */
+ int SegwitHeight;
/**
* Minimum blocks including miner confirmation of the total of 2016 blocks in a retargeting period,
* (nPowTargetTimespan / nPowTargetSpacing) which is also used for BIP9 deployments.
diff --git a/src/init.cpp b/src/init.cpp
index 6dde6edaee..dce601a554 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -15,7 +15,6 @@
#include <blockfilter.h>
#include <chain.h>
#include <chainparams.h>
-#include <coins.h>
#include <compat/sanity.h>
#include <consensus/validation.h>
#include <fs.h>
@@ -150,7 +149,6 @@ NODISCARD static bool CreatePidFile()
// shutdown thing.
//
-static std::unique_ptr<CCoinsViewErrorCatcher> pcoinscatcher;
static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle;
static boost::thread_group threadGroup;
@@ -235,8 +233,14 @@ void Shutdown(InitInterfaces& interfaces)
}
// FlushStateToDisk generates a ChainStateFlushed callback, which we should avoid missing
- if (pcoinsTip != nullptr) {
- ::ChainstateActive().ForceFlushStateToDisk();
+ //
+ // g_chainstate is referenced here directly (instead of ::ChainstateActive()) because it
+ // may not have been initialized yet.
+ {
+ LOCK(cs_main);
+ if (g_chainstate && g_chainstate->CanFlushToDisk()) {
+ g_chainstate->ForceFlushStateToDisk();
+ }
}
// After there are no more peers/RPC left to give us new data which may generate
@@ -251,12 +255,10 @@ void Shutdown(InitInterfaces& interfaces)
{
LOCK(cs_main);
- if (pcoinsTip != nullptr) {
- ::ChainstateActive().ForceFlushStateToDisk();
+ if (g_chainstate && g_chainstate->CanFlushToDisk()) {
+ g_chainstate->ForceFlushStateToDisk();
+ g_chainstate->ResetCoinsViews();
}
- pcoinsTip.reset();
- pcoinscatcher.reset();
- pcoinsdbview.reset();
pblocktree.reset();
}
for (const auto& client : interfaces.chain_clients) {
@@ -1462,10 +1464,10 @@ bool AppInitMain(InitInterfaces& interfaces)
bool is_coinsview_empty;
try {
LOCK(cs_main);
+ // This statement makes ::ChainstateActive() usable.
+ g_chainstate = MakeUnique<CChainState>();
UnloadBlockIndex();
- pcoinsTip.reset();
- pcoinsdbview.reset();
- pcoinscatcher.reset();
+
// new CBlockTreeDB tries to delete the existing file, which
// fails if it's still open from the previous loop. Close it first:
pblocktree.reset();
@@ -1516,9 +1518,12 @@ bool AppInitMain(InitInterfaces& interfaces)
// At this point we're either in reindex or we've loaded a useful
// block tree into BlockIndex()!
- pcoinsdbview.reset(new CCoinsViewDB(nCoinDBCache, false, fReset || fReindexChainState));
- pcoinscatcher.reset(new CCoinsViewErrorCatcher(pcoinsdbview.get()));
- pcoinscatcher->AddReadErrCallback([]() {
+ ::ChainstateActive().InitCoinsDB(
+ /* cache_size_bytes */ nCoinDBCache,
+ /* in_memory */ false,
+ /* should_wipe */ fReset || fReindexChainState);
+
+ ::ChainstateActive().CoinsErrorCatcher().AddReadErrCallback([]() {
uiInterface.ThreadSafeMessageBox(
_("Error reading from database, shutting down.").translated,
"", CClientUIInterface::MSG_ERROR);
@@ -1526,23 +1531,25 @@ bool AppInitMain(InitInterfaces& interfaces)
// If necessary, upgrade from older database format.
// This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
- if (!pcoinsdbview->Upgrade()) {
+ if (!::ChainstateActive().CoinsDB().Upgrade()) {
strLoadError = _("Error upgrading chainstate database").translated;
break;
}
// ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
- if (!ReplayBlocks(chainparams, pcoinsdbview.get())) {
+ if (!ReplayBlocks(chainparams, &::ChainstateActive().CoinsDB())) {
strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.").translated;
break;
}
// The on-disk coinsdb is now in a good state, create the cache
- pcoinsTip.reset(new CCoinsViewCache(pcoinscatcher.get()));
+ ::ChainstateActive().InitCoinsCache();
+ assert(::ChainstateActive().CanFlushToDisk());
- is_coinsview_empty = fReset || fReindexChainState || pcoinsTip->GetBestBlock().IsNull();
+ is_coinsview_empty = fReset || fReindexChainState ||
+ ::ChainstateActive().CoinsTip().GetBestBlock().IsNull();
if (!is_coinsview_empty) {
- // LoadChainTip sets ::ChainActive() based on pcoinsTip's best block
+ // LoadChainTip sets ::ChainActive() based on CoinsTip()'s best block
if (!LoadChainTip(chainparams)) {
strLoadError = _("Error initializing block database").translated;
break;
@@ -1584,7 +1591,7 @@ bool AppInitMain(InitInterfaces& interfaces)
break;
}
- if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview.get(), gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL),
+ if (!CVerifyDB().VerifyDB(chainparams, &::ChainstateActive().CoinsDB(), gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL),
gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) {
strLoadError = _("Corrupted block database detected").translated;
break;
@@ -1666,12 +1673,9 @@ bool AppInitMain(InitInterfaces& interfaces)
}
}
- if (chainparams.GetConsensus().vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout != 0) {
- // Only advertise witness capabilities if they have a reasonable start time.
- // This allows us to have the code merged without a defined softfork, by setting its
- // end time to 0.
- // Note that setting NODE_WITNESS is never required: the only downside from not
- // doing so is that after activation, no upgraded nodes will fetch from you.
+ if (chainparams.GetConsensus().SegwitHeight != std::numeric_limits<int>::max()) {
+ // Advertise witness capabilities.
+ // The option to not set NODE_WITNESS is only used in the tests and should be removed.
nLocalServices = ServiceFlags(nLocalServices | NODE_WITNESS);
}
diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp
index bcd226edd9..fc49817502 100644
--- a/src/interfaces/node.cpp
+++ b/src/interfaces/node.cpp
@@ -232,7 +232,7 @@ public:
bool getUnspentOutput(const COutPoint& output, Coin& coin) override
{
LOCK(::cs_main);
- return ::pcoinsTip->GetCoin(output, coin);
+ return ::ChainstateActive().CoinsTip().GetCoin(output, coin);
}
std::string getWalletDir() override
{
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 3db460d444..520dfcbb66 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -1291,11 +1291,12 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
LOCK(g_cs_orphans);
if (mapOrphanTransactions.count(inv.hash)) return true;
}
+ const CCoinsViewCache& coins_cache = ::ChainstateActive().CoinsTip();
return recentRejects->contains(inv.hash) ||
mempool.exists(inv.hash) ||
- pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 0)) || // Best effort: only try output 0 and 1
- pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 1));
+ coins_cache.HaveCoinInCache(COutPoint(inv.hash, 0)) || // Best effort: only try output 0 and 1
+ coins_cache.HaveCoinInCache(COutPoint(inv.hash, 1));
}
case MSG_BLOCK:
case MSG_WITNESS_BLOCK:
@@ -1844,7 +1845,7 @@ void static ProcessOrphanTx(CConnman* connman, std::set<uint256>& orphan_work_se
EraseOrphanTx(orphanHash);
done = true;
}
- mempool.check(pcoinsTip.get());
+ mempool.check(&::ChainstateActive().CoinsTip());
}
}
@@ -2497,7 +2498,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (!AlreadyHave(inv) &&
AcceptToMemoryPool(mempool, state, ptx, &fMissingInputs, &lRemovedTxn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
- mempool.check(pcoinsTip.get());
+ mempool.check(&::ChainstateActive().CoinsTip());
RelayTransaction(tx.GetHash(), *connman);
for (unsigned int i = 0; i < tx.vout.size(); i++) {
auto it_by_prev = mapOrphanTransactionsByPrev.find(COutPoint(inv.hash, i));
diff --git a/src/node/coin.cpp b/src/node/coin.cpp
index bb98e63f3a..ad8d1d3af4 100644
--- a/src/node/coin.cpp
+++ b/src/node/coin.cpp
@@ -10,8 +10,7 @@
void FindCoins(std::map<COutPoint, Coin>& coins)
{
LOCK2(cs_main, ::mempool.cs);
- assert(pcoinsTip);
- CCoinsViewCache& chain_view = *::pcoinsTip;
+ CCoinsViewCache& chain_view = ::ChainstateActive().CoinsTip();
CCoinsViewMemPool mempool_view(&chain_view, ::mempool);
for (auto& coin : coins) {
if (!mempool_view.GetCoin(coin.first, coin.second)) {
diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp
index a28136a8e8..7e8291ddc8 100644
--- a/src/node/transaction.cpp
+++ b/src/node/transaction.cpp
@@ -28,7 +28,7 @@ TransactionError BroadcastTransaction(const CTransactionRef tx, std::string& err
LOCK(cs_main);
// If the transaction is already confirmed in the chain, don't do anything
// and return early.
- CCoinsViewCache &view = *pcoinsTip;
+ CCoinsViewCache &view = ::ChainstateActive().CoinsTip();
for (size_t o = 0; o < tx->vout.size(); o++) {
const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o));
// IsSpent doesnt mean the coin is spent, it means the output doesnt' exist.
diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc
index fddc2a5685..037b23e4b2 100644
--- a/src/qt/bitcoin.qrc
+++ b/src/qt/bitcoin.qrc
@@ -2,7 +2,6 @@
<qresource prefix="/icons">
<file alias="bitcoin">res/icons/bitcoin.png</file>
<file alias="address-book">res/icons/address-book.png</file>
- <file alias="quit">res/icons/quit.png</file>
<file alias="send">res/icons/send.png</file>
<file alias="connect_0">res/icons/connect0.png</file>
<file alias="connect_1">res/icons/connect1.png</file>
@@ -20,7 +19,6 @@
<file alias="eye">res/icons/eye.png</file>
<file alias="eye_minus">res/icons/eye_minus.png</file>
<file alias="eye_plus">res/icons/eye_plus.png</file>
- <file alias="options">res/icons/configure.png</file>
<file alias="receiving_addresses">res/icons/receive.png</file>
<file alias="editpaste">res/icons/editpaste.png</file>
<file alias="editcopy">res/icons/editcopy.png</file>
@@ -37,14 +35,6 @@
<file alias="tx_inout">res/icons/tx_inout.png</file>
<file alias="lock_closed">res/icons/lock_closed.png</file>
<file alias="lock_open">res/icons/lock_open.png</file>
- <file alias="key">res/icons/key.png</file>
- <file alias="filesave">res/icons/filesave.png</file>
- <file alias="debugwindow">res/icons/debugwindow.png</file>
- <file alias="open">res/icons/open.png</file>
- <file alias="info">res/icons/info.png</file>
- <file alias="about">res/icons/about.png</file>
- <file alias="about_qt">res/icons/about_qt.png</file>
- <file alias="verify">res/icons/verify.png</file>
<file alias="warning">res/icons/warning.png</file>
<file alias="fontbigger">res/icons/fontbigger.png</file>
<file alias="fontsmaller">res/icons/fontsmaller.png</file>
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 3533227483..bc9af9793e 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -248,7 +248,7 @@ void BitcoinGUI::createActions()
sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2));
tabGroup->addAction(sendCoinsAction);
- sendCoinsMenuAction = new QAction(platformStyle->TextColorIcon(":/icons/send"), sendCoinsAction->text(), this);
+ sendCoinsMenuAction = new QAction(sendCoinsAction->text(), this);
sendCoinsMenuAction->setStatusTip(sendCoinsAction->statusTip());
sendCoinsMenuAction->setToolTip(sendCoinsMenuAction->statusTip());
@@ -259,7 +259,7 @@ void BitcoinGUI::createActions()
receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3));
tabGroup->addAction(receiveCoinsAction);
- receiveCoinsMenuAction = new QAction(platformStyle->TextColorIcon(":/icons/receiving_addresses"), receiveCoinsAction->text(), this);
+ receiveCoinsMenuAction = new QAction(receiveCoinsAction->text(), this);
receiveCoinsMenuAction->setStatusTip(receiveCoinsAction->statusTip());
receiveCoinsMenuAction->setToolTip(receiveCoinsMenuAction->statusTip());
@@ -287,48 +287,48 @@ void BitcoinGUI::createActions()
connect(historyAction, &QAction::triggered, this, &BitcoinGUI::gotoHistoryPage);
#endif // ENABLE_WALLET
- quitAction = new QAction(platformStyle->TextColorIcon(":/icons/quit"), tr("E&xit"), this);
+ quitAction = new QAction(tr("E&xit"), this);
quitAction->setStatusTip(tr("Quit application"));
quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
quitAction->setMenuRole(QAction::QuitRole);
- aboutAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&About %1").arg(PACKAGE_NAME), this);
+ aboutAction = new QAction(tr("&About %1").arg(PACKAGE_NAME), this);
aboutAction->setStatusTip(tr("Show information about %1").arg(PACKAGE_NAME));
aboutAction->setMenuRole(QAction::AboutRole);
aboutAction->setEnabled(false);
- aboutQtAction = new QAction(platformStyle->TextColorIcon(":/icons/about_qt"), tr("About &Qt"), this);
+ aboutQtAction = new QAction(tr("About &Qt"), this);
aboutQtAction->setStatusTip(tr("Show information about Qt"));
aboutQtAction->setMenuRole(QAction::AboutQtRole);
- optionsAction = new QAction(platformStyle->TextColorIcon(":/icons/options"), tr("&Options..."), this);
+ optionsAction = new QAction(tr("&Options..."), this);
optionsAction->setStatusTip(tr("Modify configuration options for %1").arg(PACKAGE_NAME));
optionsAction->setMenuRole(QAction::PreferencesRole);
optionsAction->setEnabled(false);
- toggleHideAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&Show / Hide"), this);
+ toggleHideAction = new QAction(tr("&Show / Hide"), this);
toggleHideAction->setStatusTip(tr("Show or hide the main Window"));
- encryptWalletAction = new QAction(platformStyle->TextColorIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this);
+ encryptWalletAction = new QAction(tr("&Encrypt Wallet..."), this);
encryptWalletAction->setStatusTip(tr("Encrypt the private keys that belong to your wallet"));
encryptWalletAction->setCheckable(true);
- backupWalletAction = new QAction(platformStyle->TextColorIcon(":/icons/filesave"), tr("&Backup Wallet..."), this);
+ backupWalletAction = new QAction(tr("&Backup Wallet..."), this);
backupWalletAction->setStatusTip(tr("Backup wallet to another location"));
- changePassphraseAction = new QAction(platformStyle->TextColorIcon(":/icons/key"), tr("&Change Passphrase..."), this);
+ changePassphraseAction = new QAction(tr("&Change Passphrase..."), this);
changePassphraseAction->setStatusTip(tr("Change the passphrase used for wallet encryption"));
- signMessageAction = new QAction(platformStyle->TextColorIcon(":/icons/edit"), tr("Sign &message..."), this);
+ signMessageAction = new QAction(tr("Sign &message..."), this);
signMessageAction->setStatusTip(tr("Sign messages with your Bitcoin addresses to prove you own them"));
- verifyMessageAction = new QAction(platformStyle->TextColorIcon(":/icons/verify"), tr("&Verify message..."), this);
+ verifyMessageAction = new QAction(tr("&Verify message..."), this);
verifyMessageAction->setStatusTip(tr("Verify messages to ensure they were signed with specified Bitcoin addresses"));
- openRPCConsoleAction = new QAction(platformStyle->TextColorIcon(":/icons/debugwindow"), tr("&Debug window"), this);
+ openRPCConsoleAction = new QAction(tr("&Debug window"), this);
openRPCConsoleAction->setStatusTip(tr("Open debugging and diagnostic console"));
// initially disable the debug window menu item
openRPCConsoleAction->setEnabled(false);
openRPCConsoleAction->setObjectName("openRPCConsoleAction");
- usedSendingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Sending addresses"), this);
+ usedSendingAddressesAction = new QAction(tr("&Sending addresses"), this);
usedSendingAddressesAction->setStatusTip(tr("Show the list of used sending addresses and labels"));
- usedReceivingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Receiving addresses"), this);
+ usedReceivingAddressesAction = new QAction(tr("&Receiving addresses"), this);
usedReceivingAddressesAction->setStatusTip(tr("Show the list of used receiving addresses and labels"));
- openAction = new QAction(platformStyle->TextColorIcon(":/icons/open"), tr("Open &URI..."), this);
+ openAction = new QAction(tr("Open &URI..."), this);
openAction->setStatusTip(tr("Open a bitcoin: URI or payment request"));
m_open_wallet_action = new QAction(tr("Open Wallet"), this);
@@ -339,7 +339,7 @@ void BitcoinGUI::createActions()
m_close_wallet_action = new QAction(tr("Close Wallet..."), this);
m_close_wallet_action->setStatusTip(tr("Close wallet"));
- showHelpMessageAction = new QAction(platformStyle->TextColorIcon(":/icons/info"), tr("&Command-line options"), this);
+ showHelpMessageAction = new QAction(tr("&Command-line options"), this);
showHelpMessageAction->setMenuRole(QAction::NoRole);
showHelpMessageAction->setStatusTip(tr("Show the %1 help message to get a list with possible Bitcoin command-line options").arg(PACKAGE_NAME));
diff --git a/src/qt/res/icons/about.png b/src/qt/res/icons/about.png
deleted file mode 100644
index 4143be8bac..0000000000
--- a/src/qt/res/icons/about.png
+++ /dev/null
Binary files differ
diff --git a/src/qt/res/icons/about_qt.png b/src/qt/res/icons/about_qt.png
deleted file mode 100644
index c40abfd3a6..0000000000
--- a/src/qt/res/icons/about_qt.png
+++ /dev/null
Binary files differ
diff --git a/src/qt/res/icons/configure.png b/src/qt/res/icons/configure.png
deleted file mode 100644
index 5333c83d5e..0000000000
--- a/src/qt/res/icons/configure.png
+++ /dev/null
Binary files differ
diff --git a/src/qt/res/icons/debugwindow.png b/src/qt/res/icons/debugwindow.png
deleted file mode 100644
index 290fe60864..0000000000
--- a/src/qt/res/icons/debugwindow.png
+++ /dev/null
Binary files differ
diff --git a/src/qt/res/icons/filesave.png b/src/qt/res/icons/filesave.png
deleted file mode 100644
index 779cca1d52..0000000000
--- a/src/qt/res/icons/filesave.png
+++ /dev/null
Binary files differ
diff --git a/src/qt/res/icons/info.png b/src/qt/res/icons/info.png
deleted file mode 100644
index 692b50c2a9..0000000000
--- a/src/qt/res/icons/info.png
+++ /dev/null
Binary files differ
diff --git a/src/qt/res/icons/key.png b/src/qt/res/icons/key.png
deleted file mode 100644
index f301c4f38c..0000000000
--- a/src/qt/res/icons/key.png
+++ /dev/null
Binary files differ
diff --git a/src/qt/res/icons/open.png b/src/qt/res/icons/open.png
deleted file mode 100644
index 4d958f0e18..0000000000
--- a/src/qt/res/icons/open.png
+++ /dev/null
Binary files differ
diff --git a/src/qt/res/icons/quit.png b/src/qt/res/icons/quit.png
deleted file mode 100644
index 55e34de4b8..0000000000
--- a/src/qt/res/icons/quit.png
+++ /dev/null
Binary files differ
diff --git a/src/qt/res/icons/verify.png b/src/qt/res/icons/verify.png
deleted file mode 100644
index 8e2cb2cc14..0000000000
--- a/src/qt/res/icons/verify.png
+++ /dev/null
Binary files differ
diff --git a/src/qt/res/src/verify.svg b/src/qt/res/src/verify.svg
deleted file mode 100644
index 1ff11b7f5e..0000000000
--- a/src/qt/res/src/verify.svg
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
- viewBox="0 0 841.9 595.3" enable-background="new 0 0 841.9 595.3" xml:space="preserve">
-<path d="M654.1,317.5c-14.9-9.9-37.2-2.5-44.6,12.4l-62,111.6l-34.7-34.7c-12.4-12.4-34.7-12.4-47.1,0c-12.4,12.4-12.4,34.7,0,47.1
- l67,67c7.4,7.4,14.9,9.9,22.3,9.9h5c9.9-2.5,19.8-7.4,24.8-17.4l81.9-148.8C676.4,347.2,671.5,327.4,654.1,317.5z"/>
-<path d="M326.7,471.3H177.9V362.1l94.3-94.3c-5-14.9-7.4-29.8-7.4-44.6c0-81.9,67-148.8,148.8-148.8s148.8,67,148.8,148.8
- s-67,148.8-148.8,148.8h-37.2v49.6h-49.6L326.7,471.3L326.7,471.3z M227.5,421.7h49.6v-49.6h49.6v-49.6h86.8
- c54.6,0,99.2-44.6,99.2-99.2S468.1,124,413.5,124s-99.2,44.6-99.2,99.2c0,14.9,2.5,27.3,9.9,39.7l7.4,14.9L230,379.5v42.2H227.5z
- M413.5,198.4c14.9,0,24.8,9.9,24.8,24.8c0,14.9-9.9,24.8-24.8,24.8c-14.9,0-24.8-9.9-24.8-24.8
- C388.7,208.3,401.1,198.4,413.5,198.4 M413.5,173.6c-27.3,0-49.6,22.3-49.6,49.6c0,27.3,22.3,49.6,49.6,49.6
- c27.3,0,49.6-22.3,49.6-49.6C463.1,195.9,443.3,173.6,413.5,173.6z"/>
-</svg>
diff --git a/src/rest.cpp b/src/rest.cpp
index eba7aae50f..2c4d475542 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -503,12 +503,12 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
if (fCheckMemPool) {
// use db+mempool as cache backend in case user likes to query mempool
LOCK2(cs_main, mempool.cs);
- CCoinsViewCache& viewChain = *pcoinsTip;
+ CCoinsViewCache& viewChain = ::ChainstateActive().CoinsTip();
CCoinsViewMemPool viewMempool(&viewChain, mempool);
process_utxos(viewMempool, mempool);
} else {
LOCK(cs_main); // no need to lock mempool!
- process_utxos(*pcoinsTip, CTxMemPool());
+ process_utxos(::ChainstateActive().CoinsTip(), CTxMemPool());
}
for (size_t i = 0; i < hits.size(); ++i) {
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index b7dcd59c6d..bfb6ab6a21 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -1062,7 +1062,9 @@ static UniValue gettxoutsetinfo(const JSONRPCRequest& request)
CCoinsStats stats;
::ChainstateActive().ForceFlushStateToDisk();
- if (GetUTXOStats(pcoinsdbview.get(), stats)) {
+
+ CCoinsView* coins_view = WITH_LOCK(cs_main, return &ChainstateActive().CoinsDB());
+ if (GetUTXOStats(coins_view, stats)) {
ret.pushKV("height", (int64_t)stats.nHeight);
ret.pushKV("bestblock", stats.hashBlock.GetHex());
ret.pushKV("transactions", (int64_t)stats.nTransactions);
@@ -1126,19 +1128,21 @@ UniValue gettxout(const JSONRPCRequest& request)
fMempool = request.params[2].get_bool();
Coin coin;
+ CCoinsViewCache* coins_view = &::ChainstateActive().CoinsTip();
+
if (fMempool) {
LOCK(mempool.cs);
- CCoinsViewMemPool view(pcoinsTip.get(), mempool);
+ CCoinsViewMemPool view(coins_view, mempool);
if (!view.GetCoin(out, coin) || mempool.isSpent(out)) {
return NullUniValue;
}
} else {
- if (!pcoinsTip->GetCoin(out, coin)) {
+ if (!coins_view->GetCoin(out, coin)) {
return NullUniValue;
}
}
- const CBlockIndex* pindex = LookupBlockIndex(pcoinsTip->GetBestBlock());
+ const CBlockIndex* pindex = LookupBlockIndex(coins_view->GetBestBlock());
ret.pushKV("bestblock", pindex->GetBlockHash().GetHex());
if (coin.nHeight == MEMPOOL_HEIGHT) {
ret.pushKV("confirmations", 0);
@@ -1180,57 +1184,53 @@ static UniValue verifychain(const JSONRPCRequest& request)
if (!request.params[1].isNull())
nCheckDepth = request.params[1].get_int();
- return CVerifyDB().VerifyDB(Params(), pcoinsTip.get(), nCheckLevel, nCheckDepth);
+ return CVerifyDB().VerifyDB(
+ Params(), &::ChainstateActive().CoinsTip(), nCheckLevel, nCheckDepth);
}
-/** Implementation of IsSuperMajority with better feedback */
-static UniValue SoftForkMajorityDesc(int version, const CBlockIndex* pindex, const Consensus::Params& consensusParams)
+static void BuriedForkDescPushBack(UniValue& softforks, const std::string &name, int height) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
- UniValue rv(UniValue::VOBJ);
- bool activated = false;
- switch(version)
- {
- case 2:
- activated = pindex->nHeight >= consensusParams.BIP34Height;
- break;
- case 3:
- activated = pindex->nHeight >= consensusParams.BIP66Height;
- break;
- case 4:
- activated = pindex->nHeight >= consensusParams.BIP65Height;
- break;
- }
- rv.pushKV("status", activated);
- return rv;
-}
+ // For buried deployments.
+ // A buried deployment is one where the height of the activation has been hardcoded into
+ // the client implementation long after the consensus change has activated. See BIP 90.
+ // Buried deployments with activation height value of
+ // std::numeric_limits<int>::max() are disabled and thus hidden.
+ if (height == std::numeric_limits<int>::max()) return;
-static UniValue SoftForkDesc(const std::string &name, int version, const CBlockIndex* pindex, const Consensus::Params& consensusParams)
-{
UniValue rv(UniValue::VOBJ);
- rv.pushKV("id", name);
- rv.pushKV("version", version);
- rv.pushKV("reject", SoftForkMajorityDesc(version, pindex, consensusParams));
- return rv;
+ rv.pushKV("type", "buried");
+ // getblockchaininfo reports the softfork as active from when the chain height is
+ // one below the activation height
+ rv.pushKV("active", ::ChainActive().Tip()->nHeight + 1 >= height);
+ rv.pushKV("height", height);
+ softforks.pushKV(name, rv);
}
-static UniValue BIP9SoftForkDesc(const Consensus::Params& consensusParams, Consensus::DeploymentPos id)
+static void BIP9SoftForkDescPushBack(UniValue& softforks, const std::string &name, const Consensus::Params& consensusParams, Consensus::DeploymentPos id) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
- UniValue rv(UniValue::VOBJ);
+ // For BIP9 deployments.
+ // Deployments (e.g. testdummy) with timeout value before Jan 1, 2009 are hidden.
+ // A timeout value of 0 guarantees a softfork will never be activated.
+ // This is used when merging logic to implement a proposed softfork without a specified deployment schedule.
+ if (consensusParams.vDeployments[id].nTimeout <= 1230768000) return;
+
+ UniValue bip9(UniValue::VOBJ);
const ThresholdState thresholdState = VersionBitsTipState(consensusParams, id);
switch (thresholdState) {
- case ThresholdState::DEFINED: rv.pushKV("status", "defined"); break;
- case ThresholdState::STARTED: rv.pushKV("status", "started"); break;
- case ThresholdState::LOCKED_IN: rv.pushKV("status", "locked_in"); break;
- case ThresholdState::ACTIVE: rv.pushKV("status", "active"); break;
- case ThresholdState::FAILED: rv.pushKV("status", "failed"); break;
+ case ThresholdState::DEFINED: bip9.pushKV("status", "defined"); break;
+ case ThresholdState::STARTED: bip9.pushKV("status", "started"); break;
+ case ThresholdState::LOCKED_IN: bip9.pushKV("status", "locked_in"); break;
+ case ThresholdState::ACTIVE: bip9.pushKV("status", "active"); break;
+ case ThresholdState::FAILED: bip9.pushKV("status", "failed"); break;
}
if (ThresholdState::STARTED == thresholdState)
{
- rv.pushKV("bit", consensusParams.vDeployments[id].bit);
+ bip9.pushKV("bit", consensusParams.vDeployments[id].bit);
}
- rv.pushKV("startTime", consensusParams.vDeployments[id].nStartTime);
- rv.pushKV("timeout", consensusParams.vDeployments[id].nTimeout);
- rv.pushKV("since", VersionBitsTipStateSinceHeight(consensusParams, id));
+ bip9.pushKV("startTime", consensusParams.vDeployments[id].nStartTime);
+ bip9.pushKV("timeout", consensusParams.vDeployments[id].nTimeout);
+ int64_t since_height = VersionBitsTipStateSinceHeight(consensusParams, id);
+ bip9.pushKV("since", since_height);
if (ThresholdState::STARTED == thresholdState)
{
UniValue statsUV(UniValue::VOBJ);
@@ -1240,18 +1240,18 @@ static UniValue BIP9SoftForkDesc(const Consensus::Params& consensusParams, Conse
statsUV.pushKV("elapsed", statsStruct.elapsed);
statsUV.pushKV("count", statsStruct.count);
statsUV.pushKV("possible", statsStruct.possible);
- rv.pushKV("statistics", statsUV);
+ bip9.pushKV("statistics", statsUV);
}
- return rv;
-}
-static void BIP9SoftForkDescPushBack(UniValue& bip9_softforks, const Consensus::Params& consensusParams, Consensus::DeploymentPos id)
-{
- // Deployments with timeout value of 0 are hidden.
- // A timeout value of 0 guarantees a softfork will never be activated.
- // This is used when softfork codes are merged without specifying the deployment schedule.
- if (consensusParams.vDeployments[id].nTimeout > 0)
- bip9_softforks.pushKV(VersionBitsDeploymentInfo[id].name, BIP9SoftForkDesc(consensusParams, id));
+ UniValue rv(UniValue::VOBJ);
+ rv.pushKV("type", "bip9");
+ rv.pushKV("bip9", bip9);
+ if (ThresholdState::ACTIVE == thresholdState) {
+ rv.pushKV("height", since_height);
+ }
+ rv.pushKV("active", ThresholdState::ACTIVE == thresholdState);
+
+ softforks.pushKV(name, rv);
}
UniValue getblockchaininfo(const JSONRPCRequest& request)
@@ -1275,29 +1275,25 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
" \"pruneheight\": xxxxxx, (numeric) lowest-height complete block stored (only present if pruning is enabled)\n"
" \"automatic_pruning\": xx, (boolean) whether automatic pruning is enabled (only present if pruning is enabled)\n"
" \"prune_target_size\": xxxxxx, (numeric) the target size used by pruning (only present if automatic pruning is enabled)\n"
- " \"softforks\": [ (array) status of softforks in progress\n"
- " {\n"
- " \"id\": \"xxxx\", (string) name of softfork\n"
- " \"version\": xx, (numeric) block version\n"
- " \"reject\": { (object) progress toward rejecting pre-softfork blocks\n"
- " \"status\": xx, (boolean) true if threshold reached\n"
- " },\n"
- " }, ...\n"
- " ],\n"
- " \"bip9_softforks\": { (object) status of BIP9 softforks in progress\n"
+ " \"softforks\": { (object) status of softforks\n"
" \"xxxx\" : { (string) name of the softfork\n"
- " \"status\": \"xxxx\", (string) one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\"\n"
- " \"bit\": xx, (numeric) the bit (0-28) in the block version field used to signal this softfork (only for \"started\" status)\n"
- " \"startTime\": xx, (numeric) the minimum median time past of a block at which the bit gains its meaning\n"
- " \"timeout\": xx, (numeric) the median time past of a block at which the deployment is considered failed if not yet locked in\n"
- " \"since\": xx, (numeric) height of the first block to which the status applies\n"
- " \"statistics\": { (object) numeric statistics about BIP9 signalling for a softfork (only for \"started\" status)\n"
- " \"period\": xx, (numeric) the length in blocks of the BIP9 signalling period \n"
- " \"threshold\": xx, (numeric) the number of blocks with the version bit set required to activate the feature \n"
- " \"elapsed\": xx, (numeric) the number of blocks elapsed since the beginning of the current period \n"
- " \"count\": xx, (numeric) the number of blocks with the version bit set in the current period \n"
- " \"possible\": xx (boolean) returns false if there are not enough blocks left in this period to pass activation threshold \n"
- " }\n"
+ " \"type\": \"xxxx\", (string) one of \"buried\", \"bip9\"\n"
+ " \"bip9\": { (object) status of bip9 softforks (only for \"bip9\" type)\n"
+ " \"status\": \"xxxx\", (string) one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\"\n"
+ " \"bit\": xx, (numeric) the bit (0-28) in the block version field used to signal this softfork (only for \"started\" status)\n"
+ " \"startTime\": xx, (numeric) the minimum median time past of a block at which the bit gains its meaning\n"
+ " \"timeout\": xx, (numeric) the median time past of a block at which the deployment is considered failed if not yet locked in\n"
+ " \"since\": xx, (numeric) height of the first block to which the status applies\n"
+ " \"statistics\": { (object) numeric statistics about BIP9 signalling for a softfork\n"
+ " \"period\": xx, (numeric) the length in blocks of the BIP9 signalling period \n"
+ " \"threshold\": xx, (numeric) the number of blocks with the version bit set required to activate the feature \n"
+ " \"elapsed\": xx, (numeric) the number of blocks elapsed since the beginning of the current period \n"
+ " \"count\": xx, (numeric) the number of blocks with the version bit set in the current period \n"
+ " \"possible\": xx (boolean) returns false if there are not enough blocks left in this period to pass activation threshold \n"
+ " }\n"
+ " },\n"
+ " \"height\": \"xxxxxx\", (numeric) height of the first block which the rules are or will be enforced (only for \"buried\" type, or \"bip9\" type with \"active\" status)\n"
+ " \"active\": xx, (boolean) true if the rules are enforced for the mempool and the next block\n"
" }\n"
" }\n"
" \"warnings\" : \"...\", (string) any network and blockchain warnings.\n"
@@ -1342,16 +1338,14 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
}
const Consensus::Params& consensusParams = Params().GetConsensus();
- UniValue softforks(UniValue::VARR);
- UniValue bip9_softforks(UniValue::VOBJ);
- softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams));
- softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams));
- softforks.push_back(SoftForkDesc("bip65", 4, tip, consensusParams));
- for (int pos = Consensus::DEPLOYMENT_CSV; pos != Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++pos) {
- BIP9SoftForkDescPushBack(bip9_softforks, consensusParams, static_cast<Consensus::DeploymentPos>(pos));
- }
+ UniValue softforks(UniValue::VOBJ);
+ BuriedForkDescPushBack(softforks, "bip34", consensusParams.BIP34Height);
+ BuriedForkDescPushBack(softforks, "bip66", consensusParams.BIP66Height);
+ BuriedForkDescPushBack(softforks, "bip65", consensusParams.BIP65Height);
+ BuriedForkDescPushBack(softforks, "csv", consensusParams.CSVHeight);
+ BuriedForkDescPushBack(softforks, "segwit", consensusParams.SegwitHeight);
+ BIP9SoftForkDescPushBack(softforks, "testdummy", consensusParams, Consensus::DEPLOYMENT_TESTDUMMY);
obj.pushKV("softforks", softforks);
- obj.pushKV("bip9_softforks", bip9_softforks);
obj.pushKV("warnings", GetWarnings("statusbar"));
return obj;
@@ -2203,7 +2197,7 @@ UniValue scantxoutset(const JSONRPCRequest& request)
{
LOCK(cs_main);
::ChainstateActive().ForceFlushStateToDisk();
- pcursor = std::unique_ptr<CCoinsViewCursor>(pcoinsdbview->Cursor());
+ pcursor = std::unique_ptr<CCoinsViewCursor>(::ChainstateActive().CoinsDB().Cursor());
assert(pcursor);
}
bool res = FindScriptPubKey(g_scan_progress, g_should_abort_scan, count, pcursor.get(), needles, coins);
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 92a0e33769..07c2958635 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -482,9 +482,8 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
// TODO: Maybe recheck connections/IBD and (if something wrong) send an expires-immediately template to stop miners?
}
- const struct VBDeploymentInfo& segwit_info = VersionBitsDeploymentInfo[Consensus::DEPLOYMENT_SEGWIT];
// GBT must be called with 'segwit' set in the rules
- if (setClientRules.count(segwit_info.name) != 1) {
+ if (setClientRules.count("segwit") != 1) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "getblocktemplate must be called with the segwit rule set (call with {\"rules\": [\"segwit\"]})");
}
@@ -521,7 +520,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
pblock->nNonce = 0;
// NOTE: If at some point we support pre-segwit miners post-segwit-activation, this needs to take segwit support into consideration
- const bool fPreSegWit = (ThresholdState::ACTIVE != VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT, versionbitscache));
+ const bool fPreSegWit = (pindexPrev->nHeight + 1 < consensusParams.SegwitHeight);
UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal");
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 966c159f0f..ffbad45714 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -259,7 +259,7 @@ static UniValue gettxoutproof(const JSONRPCRequest& request)
// Loop through txids and try to find which block they're in. Exit loop once a block is found.
for (const auto& tx : setTxids) {
- const Coin& coin = AccessByTxid(*pcoinsTip, tx);
+ const Coin& coin = AccessByTxid(::ChainstateActive().CoinsTip(), tx);
if (!coin.IsSpent()) {
pblockindex = ::ChainActive()[coin.nHeight];
break;
@@ -636,7 +636,7 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request)
{
LOCK(cs_main);
LOCK(mempool.cs);
- CCoinsViewCache &viewChain = *pcoinsTip;
+ CCoinsViewCache &viewChain = ::ChainstateActive().CoinsTip();
CCoinsViewMemPool viewMempool(&viewChain, mempool);
view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
@@ -1505,7 +1505,7 @@ UniValue utxoupdatepsbt(const JSONRPCRequest& request)
CCoinsViewCache view(&viewDummy);
{
LOCK2(cs_main, mempool.cs);
- CCoinsViewCache &viewChain = *pcoinsTip;
+ CCoinsViewCache &viewChain = ::ChainstateActive().CoinsTip();
CCoinsViewMemPool viewMempool(&viewChain, mempool);
view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 05d7f76983..c9661b730d 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -372,7 +372,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
CBlockIndex* prev = ::ChainActive().Tip();
CBlockIndex* next = new CBlockIndex();
next->phashBlock = new uint256(InsecureRand256());
- pcoinsTip->SetBestBlock(next->GetBlockHash());
+ ::ChainstateActive().CoinsTip().SetBestBlock(next->GetBlockHash());
next->pprev = prev;
next->nHeight = prev->nHeight + 1;
next->BuildSkip();
@@ -384,7 +384,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
CBlockIndex* prev = ::ChainActive().Tip();
CBlockIndex* next = new CBlockIndex();
next->phashBlock = new uint256(InsecureRand256());
- pcoinsTip->SetBestBlock(next->GetBlockHash());
+ ::ChainstateActive().CoinsTip().SetBestBlock(next->GetBlockHash());
next->pprev = prev;
next->nHeight = prev->nHeight + 1;
next->BuildSkip();
@@ -414,7 +414,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
while (::ChainActive().Tip()->nHeight > nHeight) {
CBlockIndex* del = ::ChainActive().Tip();
::ChainActive().SetTip(del->pprev);
- pcoinsTip->SetBestBlock(del->pprev->GetBlockHash());
+ ::ChainstateActive().CoinsTip().SetBestBlock(del->pprev->GetBlockHash());
delete del->phashBlock;
delete del;
}
diff --git a/src/test/setup_common.cpp b/src/test/setup_common.cpp
index de877fd167..bbdf1ef830 100644
--- a/src/test/setup_common.cpp
+++ b/src/test/setup_common.cpp
@@ -85,8 +85,12 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
mempool.setSanityCheck(1.0);
pblocktree.reset(new CBlockTreeDB(1 << 20, true));
- pcoinsdbview.reset(new CCoinsViewDB(1 << 23, true));
- pcoinsTip.reset(new CCoinsViewCache(pcoinsdbview.get()));
+ g_chainstate = MakeUnique<CChainState>();
+ ::ChainstateActive().InitCoinsDB(
+ /* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false);
+ assert(!::ChainstateActive().CanFlushToDisk());
+ ::ChainstateActive().InitCoinsCache();
+ assert(::ChainstateActive().CanFlushToDisk());
if (!LoadGenesisBlock(chainparams)) {
throw std::runtime_error("LoadGenesisBlock failed.");
}
@@ -113,8 +117,7 @@ TestingSetup::~TestingSetup()
g_connman.reset();
g_banman.reset();
UnloadBlockIndex();
- pcoinsTip.reset();
- pcoinsdbview.reset();
+ g_chainstate.reset();
pblocktree.reset();
}
@@ -122,7 +125,7 @@ TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST)
{
// CreateAndProcessBlock() does not support building SegWit blocks, so don't activate in these tests.
// TODO: fix the code to support SegWit blocks.
- gArgs.ForceSetArg("-vbparams", strprintf("segwit:0:%d", (int64_t)Consensus::BIP9Deployment::NO_TIMEOUT));
+ gArgs.ForceSetArg("-segwitheight", "432");
SelectParams(CBaseChainParams::REGTEST);
// Generate a 100-block chain:
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index f99a3748c9..e69ebcc2c3 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -97,7 +97,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
BOOST_CHECK_EQUAL(mempool.size(), 0U);
}
-// Run CheckInputs (using pcoinsTip) on the given transaction, for all script
+// Run CheckInputs (using CoinsTip()) on the given transaction, for all script
// flags. Test that CheckInputs passes for all flags that don't overlap with
// the failing_flags argument, but otherwise fails.
// CHECKLOCKTIMEVERIFY and CHECKSEQUENCEVERIFY (and future NOP codes that may
@@ -125,7 +125,7 @@ static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t fail
// WITNESS requires P2SH
test_flags |= SCRIPT_VERIFY_P2SH;
}
- bool ret = CheckInputs(tx, state, pcoinsTip.get(), true, test_flags, true, add_to_cache, txdata, nullptr);
+ bool ret = CheckInputs(tx, state, &::ChainstateActive().CoinsTip(), true, test_flags, true, add_to_cache, txdata, nullptr);
// CheckInputs should succeed iff test_flags doesn't intersect with
// failing_flags
bool expected_return_value = !(test_flags & failing_flags);
@@ -135,13 +135,13 @@ static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t fail
if (ret && add_to_cache) {
// Check that we get a cache hit if the tx was valid
std::vector<CScriptCheck> scriptchecks;
- BOOST_CHECK(CheckInputs(tx, state, pcoinsTip.get(), true, test_flags, true, add_to_cache, txdata, &scriptchecks));
+ BOOST_CHECK(CheckInputs(tx, state, &::ChainstateActive().CoinsTip(), true, test_flags, true, add_to_cache, txdata, &scriptchecks));
BOOST_CHECK(scriptchecks.empty());
} else {
// Check that we get script executions to check, if the transaction
// was invalid, or we didn't add to cache.
std::vector<CScriptCheck> scriptchecks;
- BOOST_CHECK(CheckInputs(tx, state, pcoinsTip.get(), true, test_flags, true, add_to_cache, txdata, &scriptchecks));
+ BOOST_CHECK(CheckInputs(tx, state, &::ChainstateActive().CoinsTip(), true, test_flags, true, add_to_cache, txdata, &scriptchecks));
BOOST_CHECK_EQUAL(scriptchecks.size(), tx.vin.size());
}
}
@@ -204,13 +204,13 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
CValidationState state;
PrecomputedTransactionData ptd_spend_tx(spend_tx);
- BOOST_CHECK(!CheckInputs(CTransaction(spend_tx), state, pcoinsTip.get(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr));
+ BOOST_CHECK(!CheckInputs(CTransaction(spend_tx), state, &::ChainstateActive().CoinsTip(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr));
// If we call again asking for scriptchecks (as happens in
// ConnectBlock), we should add a script check object for this -- we're
// not caching invalidity (if that changes, delete this test case).
std::vector<CScriptCheck> scriptchecks;
- BOOST_CHECK(CheckInputs(CTransaction(spend_tx), state, pcoinsTip.get(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, &scriptchecks));
+ BOOST_CHECK(CheckInputs(CTransaction(spend_tx), state, &::ChainstateActive().CoinsTip(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, &scriptchecks));
BOOST_CHECK_EQUAL(scriptchecks.size(), 1U);
// Test that CheckInputs returns true iff DERSIG-enforcing flags are
@@ -227,7 +227,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
block = CreateAndProcessBlock({spend_tx}, p2pk_scriptPubKey);
LOCK(cs_main);
BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() == block.GetHash());
- BOOST_CHECK(pcoinsTip->GetBestBlock() == block.GetHash());
+ BOOST_CHECK(::ChainstateActive().CoinsTip().GetBestBlock() == block.GetHash());
// Test P2SH: construct a transaction that is valid without P2SH, and
// then test validity with P2SH.
@@ -272,7 +272,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
CValidationState state;
PrecomputedTransactionData txdata(invalid_with_cltv_tx);
- BOOST_CHECK(CheckInputs(CTransaction(invalid_with_cltv_tx), state, pcoinsTip.get(), true, SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr));
+ BOOST_CHECK(CheckInputs(CTransaction(invalid_with_cltv_tx), state, ::ChainstateActive().CoinsTip(), true, SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr));
}
// TEST CHECKSEQUENCEVERIFY
@@ -300,7 +300,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
CValidationState state;
PrecomputedTransactionData txdata(invalid_with_csv_tx);
- BOOST_CHECK(CheckInputs(CTransaction(invalid_with_csv_tx), state, pcoinsTip.get(), true, SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr));
+ BOOST_CHECK(CheckInputs(CTransaction(invalid_with_csv_tx), state, &::ChainstateActive().CoinsTip(), true, SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr));
}
// TODO: add tests for remaining script flags
@@ -362,12 +362,12 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
CValidationState state;
PrecomputedTransactionData txdata(tx);
// This transaction is now invalid under segwit, because of the second input.
- BOOST_CHECK(!CheckInputs(CTransaction(tx), state, pcoinsTip.get(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, nullptr));
+ BOOST_CHECK(!CheckInputs(CTransaction(tx), state, &::ChainstateActive().CoinsTip(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, nullptr));
std::vector<CScriptCheck> scriptchecks;
// Make sure this transaction was not cached (ie because the first
// input was valid)
- BOOST_CHECK(CheckInputs(CTransaction(tx), state, pcoinsTip.get(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, &scriptchecks));
+ BOOST_CHECK(CheckInputs(CTransaction(tx), state, &::ChainstateActive().CoinsTip(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, &scriptchecks));
// Should get 2 script checks back -- caching is on a whole-transaction basis.
BOOST_CHECK_EQUAL(scriptchecks.size(), 2U);
}
diff --git a/src/txdb.cpp b/src/txdb.cpp
index df9851396e..18be07e6db 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -52,7 +52,7 @@ struct CoinEntry {
}
-CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe, true)
+CCoinsViewDB::CCoinsViewDB(fs::path ldb_path, size_t nCacheSize, bool fMemory, bool fWipe) : db(ldb_path, nCacheSize, fMemory, fWipe, true)
{
}
diff --git a/src/txdb.h b/src/txdb.h
index c4ece11503..140ce2c7ff 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -48,7 +48,10 @@ class CCoinsViewDB final : public CCoinsView
protected:
CDBWrapper db;
public:
- explicit CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
+ /**
+ * @param[in] ldb_path Location in the filesystem where leveldb data will be stored.
+ */
+ explicit CCoinsViewDB(fs::path ldb_path, size_t nCacheSize, bool fMemory, bool fWipe);
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
bool HaveCoin(const COutPoint &outpoint) const override;
diff --git a/src/txmempool.h b/src/txmempool.h
index 7169e80da2..6e5ba445d3 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -497,7 +497,7 @@ public:
*
* 1. Locking both `cs_main` and `mempool.cs` will give a view of mempool
* that is consistent with current chain tip (`::ChainActive()` and
- * `pcoinsTip`) and is fully populated. Fully populated means that if the
+ * `CoinsTip()`) and is fully populated. Fully populated means that if the
* current active chain is missing transactions that were present in a
* previously active chain, all the missing transactions will have been
* re-added to the mempool and should be present if they meet size and
diff --git a/src/validation.cpp b/src/validation.cpp
index b4677df62f..74f68a3047 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -82,11 +82,17 @@ namespace {
BlockManager g_blockman;
} // anon namespace
-static CChainState g_chainstate(g_blockman);
+std::unique_ptr<CChainState> g_chainstate;
-CChainState& ChainstateActive() { return g_chainstate; }
+CChainState& ChainstateActive() {
+ assert(g_chainstate);
+ return *g_chainstate;
+}
-CChain& ChainActive() { return g_chainstate.m_chain; }
+CChain& ChainActive() {
+ assert(g_chainstate);
+ return g_chainstate->m_chain;
+}
/**
* Mutex to guard access to validation specific variables, such as reading
@@ -173,8 +179,6 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc
return chain.Genesis();
}
-std::unique_ptr<CCoinsViewDB> pcoinsdbview;
-std::unique_ptr<CCoinsViewCache> pcoinsTip;
std::unique_ptr<CBlockTreeDB> pblocktree;
// See definition for documentation
@@ -260,8 +264,8 @@ bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flag
lockPair.second = lp->time;
}
else {
- // pcoinsTip contains the UTXO set for ::ChainActive().Tip()
- CCoinsViewMemPool viewMemPool(pcoinsTip.get(), pool);
+ // CoinsTip() contains the UTXO set for ::ChainActive().Tip()
+ CCoinsViewMemPool viewMemPool(&::ChainstateActive().CoinsTip(), pool);
std::vector<int> prevheights;
prevheights.resize(tx.vin.size());
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
@@ -310,7 +314,8 @@ bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flag
// Returns the script flags which should be checked for a given block
static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& chainparams);
-static void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
+static void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age)
+ EXCLUSIVE_LOCKS_REQUIRED(pool.cs, ::cs_main)
{
int expired = pool.Expire(GetTime() - age);
if (expired != 0) {
@@ -320,7 +325,7 @@ static void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age)
std::vector<COutPoint> vNoSpendsRemaining;
pool.TrimToSize(limit, &vNoSpendsRemaining);
for (const COutPoint& removed : vNoSpendsRemaining)
- pcoinsTip->Uncache(removed);
+ ::ChainstateActive().CoinsTip().Uncache(removed);
}
static bool IsCurrentForFeeEstimation() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
@@ -382,7 +387,7 @@ static void UpdateMempoolForReorg(DisconnectedBlockTransactions& disconnectpool,
mempool.UpdateTransactionsFromBlock(vHashUpdate);
// We also need to remove any now-immature transactions
- mempool.removeForReorg(pcoinsTip.get(), ::ChainActive().Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS);
+ mempool.removeForReorg(&::ChainstateActive().CoinsTip(), ::ChainActive().Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS);
// Re-limit mempool size, in case we added any transactions
LimitMempoolSize(mempool, gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
}
@@ -414,7 +419,7 @@ static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, CValidationSt
assert(txFrom->vout.size() > txin.prevout.n);
assert(txFrom->vout[txin.prevout.n] == coin.out);
} else {
- const Coin& coinFromDisk = pcoinsTip->AccessCoin(txin.prevout);
+ const Coin& coinFromDisk = ::ChainstateActive().CoinsTip().AccessCoin(txin.prevout);
assert(!coinFromDisk.IsSpent());
assert(coinFromDisk.out == coin.out);
}
@@ -514,23 +519,24 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
CCoinsViewCache view(&dummy);
LockPoints lp;
- CCoinsViewMemPool viewMemPool(pcoinsTip.get(), pool);
+ CCoinsViewCache& coins_cache = ::ChainstateActive().CoinsTip();
+ CCoinsViewMemPool viewMemPool(&coins_cache, pool);
view.SetBackend(viewMemPool);
// do all inputs exist?
for (const CTxIn& txin : tx.vin) {
- if (!pcoinsTip->HaveCoinInCache(txin.prevout)) {
+ if (!coins_cache.HaveCoinInCache(txin.prevout)) {
coins_to_uncache.push_back(txin.prevout);
}
// Note: this call may add txin.prevout to the coins cache
- // (pcoinsTip.cacheCoins) by way of FetchCoin(). It should be removed
+ // (CoinsTip().cacheCoins) by way of FetchCoin(). It should be removed
// later (via coins_to_uncache) if this tx turns out to be invalid.
if (!view.HaveCoin(txin.prevout)) {
// Are inputs missing because we already have the tx?
for (size_t out = 0; out < tx.vout.size(); out++) {
// Optimistically just do efficient check of cache for outputs
- if (pcoinsTip->HaveCoinInCache(COutPoint(hash, out))) {
+ if (coins_cache.HaveCoinInCache(COutPoint(hash, out))) {
return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, REJECT_DUPLICATE, "txn-already-known");
}
}
@@ -860,7 +866,7 @@ static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPo
// (`CCoinsViewCache::cacheCoins`).
for (const COutPoint& hashTx : coins_to_uncache)
- pcoinsTip->Uncache(hashTx);
+ ::ChainstateActive().CoinsTip().Uncache(hashTx);
}
// After we've (potentially) uncached entries, ensure our coins cache is still within its size limits
CValidationState stateDummy;
@@ -1040,6 +1046,40 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
return nSubsidy;
}
+CoinsViews::CoinsViews(
+ std::string ldb_name,
+ size_t cache_size_bytes,
+ bool in_memory,
+ bool should_wipe) : m_dbview(
+ GetDataDir() / ldb_name, cache_size_bytes, in_memory, should_wipe),
+ m_catcherview(&m_dbview) {}
+
+void CoinsViews::InitCache()
+{
+ m_cacheview = MakeUnique<CCoinsViewCache>(&m_catcherview);
+}
+
+// NOTE: for now m_blockman is set to a global, but this will be changed
+// in a future commit.
+CChainState::CChainState() : m_blockman(g_blockman) {}
+
+
+void CChainState::InitCoinsDB(
+ size_t cache_size_bytes,
+ bool in_memory,
+ bool should_wipe,
+ std::string leveldb_name)
+{
+ m_coins_views = MakeUnique<CoinsViews>(
+ leveldb_name, cache_size_bytes, in_memory, should_wipe);
+}
+
+void CChainState::InitCoinsCache()
+{
+ assert(m_coins_views != nullptr);
+ m_coins_views->InitCache();
+}
+
// Note that though this is marked const, we may end up modifying `m_cached_finished_ibd`, which
// is a performance-related implementation detail. This function must be marked
// `const` so that `CValidationInterface` clients (which are given a `const CChainState*`)
@@ -1608,7 +1648,7 @@ static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS] GUARDED_BY(cs_
// environment. See test/functional/p2p-segwit.py.
static bool IsScriptWitnessEnabled(const Consensus::Params& params)
{
- return params.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout != 0;
+ return params.SegwitHeight != std::numeric_limits<int>::max();
}
static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& consensusparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
@@ -1644,12 +1684,13 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consens
flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
}
- // Start enforcing BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY) using versionbits logic.
- if (VersionBitsState(pindex->pprev, consensusparams, Consensus::DEPLOYMENT_CSV, versionbitscache) == ThresholdState::ACTIVE) {
+ // Start enforcing BIP112 (CHECKSEQUENCEVERIFY)
+ if (pindex->nHeight >= consensusparams.CSVHeight) {
flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY;
}
- if (IsNullDummyEnabled(pindex->pprev, consensusparams)) {
+ // Start enforcing BIP147 NULLDUMMY (activated simultaneously with segwit)
+ if (IsWitnessEnabled(pindex->pprev, consensusparams)) {
flags |= SCRIPT_VERIFY_NULLDUMMY;
}
@@ -1834,9 +1875,9 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
}
}
- // Start enforcing BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY) using versionbits logic.
+ // Start enforcing BIP68 (sequence locks)
int nLockTimeFlags = 0;
- if (VersionBitsState(pindex->pprev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV, versionbitscache) == ThresholdState::ACTIVE) {
+ if (pindex->nHeight >= chainparams.GetConsensus().CSVHeight) {
nLockTimeFlags |= LOCKTIME_VERIFY_SEQUENCE;
}
@@ -1981,6 +2022,7 @@ bool CChainState::FlushStateToDisk(
{
int64_t nMempoolUsage = mempool.DynamicMemoryUsage();
LOCK(cs_main);
+ assert(this->CanFlushToDisk());
static int64_t nLastWrite = 0;
static int64_t nLastFlush = 0;
std::set<int> setFilesToPrune;
@@ -2014,7 +2056,7 @@ bool CChainState::FlushStateToDisk(
nLastFlush = nNow;
}
int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
- int64_t cacheSize = pcoinsTip->DynamicMemoryUsage();
+ int64_t cacheSize = CoinsTip().DynamicMemoryUsage();
int64_t nTotalSpace = nCoinCacheUsage + std::max<int64_t>(nMempoolSizeMax - nMempoolUsage, 0);
// The cache is large and we're within 10% and 10 MiB of the limit, but we have time now (not in the middle of a block processing).
bool fCacheLarge = mode == FlushStateMode::PERIODIC && cacheSize > std::max((9 * nTotalSpace) / 10, nTotalSpace - MAX_BLOCK_COINSDB_USAGE * 1024 * 1024);
@@ -2058,17 +2100,17 @@ bool CChainState::FlushStateToDisk(
nLastWrite = nNow;
}
// Flush best chain related state. This can only be done if the blocks / block index write was also done.
- if (fDoFullFlush && !pcoinsTip->GetBestBlock().IsNull()) {
+ if (fDoFullFlush && !CoinsTip().GetBestBlock().IsNull()) {
// Typical Coin structures on disk are around 48 bytes in size.
// Pushing a new one to the database can cause it to be written
// twice (once in the log, and once in the tables). This is already
// an overestimation, as most will delete an existing entry or
// overwrite one. Still, use a conservative safety factor of 2.
- if (!CheckDiskSpace(GetDataDir(), 48 * 2 * 2 * pcoinsTip->GetCacheSize())) {
+ if (!CheckDiskSpace(GetDataDir(), 48 * 2 * 2 * CoinsTip().GetCacheSize())) {
return AbortNode(state, "Disk space is too low!", _("Error: Disk space is too low!").translated, CClientUIInterface::MSG_NOPREFIX);
}
// Flush the chainstate (which may refer to block index entries).
- if (!pcoinsTip->Flush())
+ if (!CoinsTip().Flush())
return AbortNode(state, "Failed to write to coin database");
nLastFlush = nNow;
full_flush_completed = true;
@@ -2120,7 +2162,9 @@ static void AppendWarning(std::string& res, const std::string& warn)
}
/** Check warning conditions and do some notifications on new chain tip set. */
-void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainParams) {
+void static UpdateTip(const CBlockIndex* pindexNew, const CChainParams& chainParams)
+ EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
+{
// New best block
mempool.AddTransactionsUpdated(1);
@@ -2162,7 +2206,7 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar
pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, pindexNew->nVersion,
log(pindexNew->nChainWork.getdouble())/log(2.0), (unsigned long)pindexNew->nChainTx,
FormatISO8601DateTime(pindexNew->GetBlockTime()),
- GuessVerificationProgress(chainParams.TxData(), pindexNew), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize());
+ GuessVerificationProgress(chainParams.TxData(), pindexNew), ::ChainstateActive().CoinsTip().DynamicMemoryUsage() * (1.0 / (1<<20)), ::ChainstateActive().CoinsTip().GetCacheSize());
if (!warningMessages.empty())
LogPrintf(" warning='%s'", warningMessages); /* Continued */
LogPrintf("\n");
@@ -2191,7 +2235,7 @@ bool CChainState::DisconnectTip(CValidationState& state, const CChainParams& cha
// Apply the block atomically to the chain state.
int64_t nStart = GetTimeMicros();
{
- CCoinsViewCache view(pcoinsTip.get());
+ CCoinsViewCache view(&CoinsTip());
assert(view.GetBestBlock() == pindexDelete->GetBlockHash());
if (DisconnectBlock(block, pindexDelete, view) != DISCONNECT_OK)
return error("DisconnectTip(): DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString());
@@ -2319,7 +2363,7 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp
int64_t nTime3;
LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * MILLI, nTimeReadFromDisk * MICRO);
{
- CCoinsViewCache view(pcoinsTip.get());
+ CCoinsViewCache view(&CoinsTip());
bool rv = ConnectBlock(blockConnecting, state, pindexNew, view, chainparams);
GetMainSignals().BlockChecked(blockConnecting, state);
if (!rv) {
@@ -2506,7 +2550,7 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar
// any disconnected transactions back to the mempool.
UpdateMempoolForReorg(disconnectpool, true);
}
- mempool.check(pcoinsTip.get());
+ mempool.check(&CoinsTip());
// Callbacks/notifications for a new best chain.
if (fInvalidFound)
@@ -3045,14 +3089,8 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params)
{
- LOCK(cs_main);
- return (VersionBitsState(pindexPrev, params, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == ThresholdState::ACTIVE);
-}
-
-bool IsNullDummyEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params)
-{
- LOCK(cs_main);
- return (VersionBitsState(pindexPrev, params, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == ThresholdState::ACTIVE);
+ int height = pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1;
+ return (height >= params.SegwitHeight);
}
// Compute at which vout of the block's coinbase transaction the witness
@@ -3087,7 +3125,7 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
std::vector<unsigned char> commitment;
int commitpos = GetWitnessCommitmentIndex(block);
std::vector<unsigned char> ret(32, 0x00);
- if (consensusParams.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout != 0) {
+ if (consensusParams.SegwitHeight != std::numeric_limits<int>::max()) {
if (commitpos == -1) {
uint256 witnessroot = BlockWitnessMerkleRoot(block, nullptr);
CHash256().Write(witnessroot.begin(), 32).Write(ret.data(), 32).Finalize(witnessroot.begin());
@@ -3185,9 +3223,9 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
{
const int nHeight = pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1;
- // Start enforcing BIP113 (Median Time Past) using versionbits logic.
+ // Start enforcing BIP113 (Median Time Past).
int nLockTimeFlags = 0;
- if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_CSV, versionbitscache) == ThresholdState::ACTIVE) {
+ if (nHeight >= consensusParams.CSVHeight) {
assert(pindexPrev != nullptr);
nLockTimeFlags |= LOCKTIME_MEDIAN_TIME_PAST;
}
@@ -3222,7 +3260,7 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
// {0xaa, 0x21, 0xa9, 0xed}, and the following 32 bytes are SHA256^2(witness root, witness reserved value). In case there are
// multiple, the last one is used.
bool fHaveWitness = false;
- if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == ThresholdState::ACTIVE) {
+ if (nHeight >= consensusParams.SegwitHeight) {
int commitpos = GetWitnessCommitmentIndex(block);
if (commitpos != -1) {
bool malleated = false;
@@ -3508,7 +3546,7 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
{
AssertLockHeld(cs_main);
assert(pindexPrev && pindexPrev == ::ChainActive().Tip());
- CCoinsViewCache viewNew(pcoinsTip.get());
+ CCoinsViewCache viewNew(&::ChainstateActive().CoinsTip());
uint256 block_hash(block.GetHash());
CBlockIndex indexDummy(block);
indexDummy.pprev = pindexPrev;
@@ -3861,12 +3899,14 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams) EXCLUSIVE_LOCKS_RE
bool LoadChainTip(const CChainParams& chainparams)
{
AssertLockHeld(cs_main);
- assert(!pcoinsTip->GetBestBlock().IsNull()); // Never called when the coins view is empty
+ const CCoinsViewCache& coins_cache = ::ChainstateActive().CoinsTip();
+ assert(!coins_cache.GetBestBlock().IsNull()); // Never called when the coins view is empty
- if (::ChainActive().Tip() && ::ChainActive().Tip()->GetBlockHash() == pcoinsTip->GetBestBlock()) return true;
+ if (::ChainActive().Tip() &&
+ ::ChainActive().Tip()->GetBlockHash() == coins_cache.GetBestBlock()) return true;
// Load pointer to end of best chain
- CBlockIndex* pindex = LookupBlockIndex(pcoinsTip->GetBestBlock());
+ CBlockIndex* pindex = LookupBlockIndex(coins_cache.GetBestBlock());
if (!pindex) {
return false;
}
@@ -3943,7 +3983,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
}
}
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
- if (nCheckLevel >= 3 && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) {
+ if (nCheckLevel >= 3 && (coins.DynamicMemoryUsage() + ::ChainstateActive().CoinsTip().DynamicMemoryUsage()) <= nCoinCacheUsage) {
assert(coins.GetBestBlock() == pindex->GetBlockHash());
DisconnectResult res = ::ChainstateActive().DisconnectBlock(block, pindex, coins);
if (res == DISCONNECT_FAILED) {
diff --git a/src/validation.h b/src/validation.h
index d747fdbf27..7cf3311f22 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -19,6 +19,7 @@
#include <script/script_error.h>
#include <sync.h>
#include <txmempool.h> // For CTxMemPool::cs
+#include <txdb.h>
#include <versionbits.h>
#include <algorithm>
@@ -37,7 +38,6 @@ class CBlockIndex;
class CBlockTreeDB;
class CBlockUndo;
class CChainParams;
-class CCoinsViewDB;
class CInv;
class CConnman;
class CScriptCheck;
@@ -383,12 +383,10 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
/** Check a block is completely valid from start to finish (only works on top of our current best block) */
bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-/** Check whether witness commitments are required for block. */
+/** Check whether witness commitments are required for a block, and whether to enforce NULLDUMMY (BIP 147) rules.
+ * Note that transaction witness validation rules are always enforced when P2SH is enforced. */
bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params);
-/** Check whether NULLDUMMY (BIP 147) has activated. */
-bool IsNullDummyEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params);
-
/** When there are blocks in the active chain with missing data, rewind the chainstate and remove them from the block index */
bool RewindBlockIndex(const CChainParams& params) LOCKS_EXCLUDED(cs_main);
@@ -506,6 +504,41 @@ public:
};
/**
+ * A convenience class for constructing the CCoinsView* hierarchy used
+ * to facilitate access to the UTXO set.
+ *
+ * This class consists of an arrangement of layered CCoinsView objects,
+ * preferring to store and retrieve coins in memory via `m_cacheview` but
+ * ultimately falling back on cache misses to the canonical store of UTXOs on
+ * disk, `m_dbview`.
+ */
+class CoinsViews {
+
+public:
+ //! The lowest level of the CoinsViews cache hierarchy sits in a leveldb database on disk.
+ //! All unspent coins reside in this store.
+ CCoinsViewDB m_dbview GUARDED_BY(cs_main);
+
+ //! This view wraps access to the leveldb instance and handles read errors gracefully.
+ CCoinsViewErrorCatcher m_catcherview GUARDED_BY(cs_main);
+
+ //! This is the top layer of the cache hierarchy - it keeps as many coins in memory as
+ //! can fit per the dbcache setting.
+ std::unique_ptr<CCoinsViewCache> m_cacheview GUARDED_BY(cs_main);
+
+ //! This constructor initializes CCoinsViewDB and CCoinsViewErrorCatcher instances, but it
+ //! *does not* create a CCoinsViewCache instance by default. This is done separately because the
+ //! presence of the cache has implications on whether or not we're allowed to flush the cache's
+ //! state to disk, which should not be done until the health of the database is verified.
+ //!
+ //! All arguments forwarded onto CCoinsViewDB.
+ CoinsViews(std::string ldb_name, size_t cache_size_bytes, bool in_memory, bool should_wipe);
+
+ //! Initialize the CCoinsViewCache member.
+ void InitCache() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+};
+
+/**
* CChainState stores and provides an API to update our local knowledge of the
* current best chain.
*
@@ -553,12 +586,39 @@ private:
//! easily as opposed to referencing a global.
BlockManager& m_blockman;
+ //! Manages the UTXO set, which is a reflection of the contents of `m_chain`.
+ std::unique_ptr<CoinsViews> m_coins_views;
+
public:
- CChainState(BlockManager& blockman) : m_blockman(blockman) { }
+ CChainState(BlockManager& blockman) : m_blockman(blockman) {}
+ CChainState();
+
+ /**
+ * Initialize the CoinsViews UTXO set database management data structures. The in-memory
+ * cache is initialized separately.
+ *
+ * All parameters forwarded to CoinsViews.
+ */
+ void InitCoinsDB(
+ size_t cache_size_bytes,
+ bool in_memory,
+ bool should_wipe,
+ std::string leveldb_name = "chainstate");
+
+ //! Initialize the in-memory coins cache (to be done after the health of the on-disk database
+ //! is verified).
+ void InitCoinsCache() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+
+ //! @returns whether or not the CoinsViews object has been fully initialized and we can
+ //! safely flush this object to disk.
+ bool CanFlushToDisk() EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
+ return m_coins_views && m_coins_views->m_cacheview;
+ }
//! The current chain of blockheaders we consult and build on.
//! @see CChain, CBlockIndex.
CChain m_chain;
+
/**
* The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and
* as good as our current tip or better. Entries may be failed, though, and pruning nodes may be
@@ -566,6 +626,29 @@ public:
*/
std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
+ //! @returns A reference to the in-memory cache of the UTXO set.
+ CCoinsViewCache& CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+ {
+ assert(m_coins_views->m_cacheview);
+ return *m_coins_views->m_cacheview.get();
+ }
+
+ //! @returns A reference to the on-disk UTXO set database.
+ CCoinsViewDB& CoinsDB() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+ {
+ return m_coins_views->m_dbview;
+ }
+
+ //! @returns A reference to a wrapped view of the in-memory UTXO set that
+ //! handles disk read errors gracefully.
+ CCoinsViewErrorCatcher& CoinsErrorCatcher() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+ {
+ return m_coins_views->m_catcherview;
+ }
+
+ //! Destructs all objects related to accessing the UTXO set.
+ void ResetCoinsViews() { m_coins_views.reset(); }
+
/**
* Update the on-disk chain state.
* The caches and indexes are flushed depending on the mode we're called with
@@ -597,7 +680,7 @@ public:
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- // Block disconnection on our pcoinsTip:
+ // Apply the effects of a block disconnection on the UTXO set.
bool DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions* disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::mempool.cs);
// Manual block validity manipulation:
@@ -659,11 +742,10 @@ CChain& ChainActive();
/** @returns the global block index map. */
BlockMap& BlockIndex();
-/** Global variable that points to the coins database (protected by cs_main) */
-extern std::unique_ptr<CCoinsViewDB> pcoinsdbview;
-
-/** Global variable that points to the active CCoinsView (protected by cs_main) */
-extern std::unique_ptr<CCoinsViewCache> pcoinsTip;
+// Most often ::ChainstateActive() should be used instead of this, but some code
+// may not be able to assume that this has been initialized yet and so must use it
+// directly, e.g. init.cpp.
+extern std::unique_ptr<CChainState> g_chainstate;
/** Global variable that points to the active block tree (protected by cs_main) */
extern std::unique_ptr<CBlockTreeDB> pblocktree;
diff --git a/src/versionbits.cpp b/src/versionbits.cpp
index 3f297c0ebb..2285579cd9 100644
--- a/src/versionbits.cpp
+++ b/src/versionbits.cpp
@@ -94,7 +94,6 @@ ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex*
return state;
}
-// return the numerical statistics of blocks signalling the specified BIP9 condition in this current period
BIP9Stats AbstractThresholdConditionChecker::GetStateStatisticsFor(const CBlockIndex* pindex, const Consensus::Params& params) const
{
BIP9Stats stats = {};
diff --git a/src/versionbits.h b/src/versionbits.h
index cdc947cd9e..d8dda7d95b 100644
--- a/src/versionbits.h
+++ b/src/versionbits.h
@@ -17,12 +17,17 @@ static const int32_t VERSIONBITS_TOP_MASK = 0xE0000000UL;
/** Total bits available for versionbits */
static const int32_t VERSIONBITS_NUM_BITS = 29;
+/** BIP 9 defines a finite-state-machine to deploy a softfork in multiple stages.
+ * State transitions happen during retarget period if conditions are met
+ * In case of reorg, transitions can go backward. Without transition, state is
+ * inherited between periods. All blocks of a period share the same state.
+ */
enum class ThresholdState {
- DEFINED,
- STARTED,
- LOCKED_IN,
- ACTIVE,
- FAILED,
+ DEFINED, // First state that each softfork starts out as. The genesis block is by definition in this state for each deployment.
+ STARTED, // For blocks past the starttime.
+ LOCKED_IN, // For one retarget period after the first retarget period with STARTED blocks of which at least threshold have the associated bit set in nVersion.
+ ACTIVE, // For all blocks after the LOCKED_IN retarget period (final state)
+ FAILED, // For all blocks once the first retarget period after the timeout time is hit, if LOCKED_IN wasn't already reached (final state)
};
// A map that gives the state for blocks whose height is a multiple of Period().
@@ -30,11 +35,17 @@ enum class ThresholdState {
// will either be nullptr or a block with (height + 1) % Period() == 0.
typedef std::map<const CBlockIndex*, ThresholdState> ThresholdConditionCache;
+/** Display status of an in-progress BIP9 softfork */
struct BIP9Stats {
+ /** Length of blocks of the BIP9 signalling period */
int period;
+ /** Number of blocks with the version bit set required to activate the softfork */
int threshold;
+ /** Number of blocks elapsed since the beginning of the current period */
int elapsed;
+ /** Number of blocks with the version bit set since the beginning of the current period */
int count;
+ /** False if there are not enough blocks left in this period to pass activation threshold */
bool possible;
};
@@ -50,12 +61,17 @@ protected:
virtual int Threshold(const Consensus::Params& params) const =0;
public:
+ /** Returns the numerical statistics of an in-progress BIP9 softfork in the current period */
BIP9Stats GetStateStatisticsFor(const CBlockIndex* pindex, const Consensus::Params& params) const;
- // Note that the functions below take a pindexPrev as input: they compute information for block B based on its parent.
+ /** Returns the state for pindex A based on parent pindexPrev B. Applies any state transition if conditions are present.
+ * Caches state from first block of period. */
ThresholdState GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const;
+ /** Returns the height since when the ThresholdState has started for pindex A based on parent pindexPrev B, all blocks of a period share the same */
int GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const;
};
+/** BIP 9 allows multiple softforks to be deployed in parallel. We cache per-period state for every one of them
+ * keyed by the bit position used to signal support. */
struct VersionBitsCache
{
ThresholdConditionCache caches[Consensus::MAX_VERSION_BITS_DEPLOYMENTS];
diff --git a/src/versionbitsinfo.cpp b/src/versionbitsinfo.cpp
index ecf3482927..82df92ac90 100644
--- a/src/versionbitsinfo.cpp
+++ b/src/versionbitsinfo.cpp
@@ -11,12 +11,4 @@ const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_B
/*.name =*/ "testdummy",
/*.gbt_force =*/ true,
},
- {
- /*.name =*/ "csv",
- /*.gbt_force =*/ true,
- },
- {
- /*.name =*/ "segwit",
- /*.gbt_force =*/ true,
- }
};
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index cbab73d612..30e767e489 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -52,6 +52,23 @@ static inline bool GetAvoidReuseFlag(CWallet * const pwallet, const UniValue& pa
return avoid_reuse;
}
+
+/** Used by RPC commands that have an include_watchonly parameter.
+ * We default to true for watchonly wallets if include_watchonly isn't
+ * explicitly set.
+ */
+static bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& pwallet)
+{
+ if (include_watchonly.isNull()) {
+ // if include_watchonly isn't explicitly set, then check if we have a watchonly wallet
+ return pwallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
+ }
+
+ // otherwise return whatever include_watchonly was set to
+ return include_watchonly.get_bool();
+}
+
+
/** Checks if a CKey is in the given CWallet compressed or otherwise*/
bool HaveKey(const CWallet& wallet, const CKey& key)
{
@@ -710,7 +727,7 @@ static UniValue getbalance(const JSONRPCRequest& request)
{
{"dummy", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Remains for backward compatibility. Must be excluded or set to \"*\"."},
{"minconf", RPCArg::Type::NUM, /* default */ "0", "Only include transactions confirmed at least this many times."},
- {"include_watchonly", RPCArg::Type::BOOL, /* default */ "false", "Also include balance in watch-only addresses (see 'importaddress')"},
+ {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Also include balance in watch-only addresses (see 'importaddress')"},
{"avoid_reuse", RPCArg::Type::BOOL, /* default */ "true", "(only available if avoid_reuse wallet flag is set) Do not include balance in dirty outputs; addresses are considered dirty if they have previously been used in a transaction."},
},
RPCResult{
@@ -743,10 +760,7 @@ static UniValue getbalance(const JSONRPCRequest& request)
min_depth = request.params[1].get_int();
}
- bool include_watchonly = false;
- if (!request.params[2].isNull() && request.params[2].get_bool()) {
- include_watchonly = true;
- }
+ bool include_watchonly = ParseIncludeWatchonly(request.params[2], *pwallet);
bool avoid_reuse = GetAvoidReuseFlag(pwallet, request.params[3]);
@@ -1023,9 +1037,10 @@ static UniValue ListReceived(interfaces::Chain::Lock& locked_chain, CWallet * co
fIncludeEmpty = params[1].get_bool();
isminefilter filter = ISMINE_SPENDABLE;
- if(!params[2].isNull())
- if(params[2].get_bool())
- filter = filter | ISMINE_WATCH_ONLY;
+
+ if (ParseIncludeWatchonly(params[2], *pwallet)) {
+ filter |= ISMINE_WATCH_ONLY;
+ }
bool has_filtered_address = false;
CTxDestination filtered_address = CNoDestination();
@@ -1169,7 +1184,7 @@ static UniValue listreceivedbyaddress(const JSONRPCRequest& request)
{
{"minconf", RPCArg::Type::NUM, /* default */ "1", "The minimum number of confirmations before payments are included."},
{"include_empty", RPCArg::Type::BOOL, /* default */ "false", "Whether to include addresses that haven't received any payments."},
- {"include_watchonly", RPCArg::Type::BOOL, /* default */ "false", "Whether to include watch-only addresses (see 'importaddress')."},
+ {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Whether to include watch-only addresses (see 'importaddress')"},
{"address_filter", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If present, only return information on this address."},
},
RPCResult{
@@ -1220,7 +1235,7 @@ static UniValue listreceivedbylabel(const JSONRPCRequest& request)
{
{"minconf", RPCArg::Type::NUM, /* default */ "1", "The minimum number of confirmations before payments are included."},
{"include_empty", RPCArg::Type::BOOL, /* default */ "false", "Whether to include labels that haven't received any payments."},
- {"include_watchonly", RPCArg::Type::BOOL, /* default */ "false", "Whether to include watch-only addresses (see 'importaddress')."},
+ {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Whether to include watch-only addresses (see 'importaddress')"},
},
RPCResult{
"[\n"
@@ -1361,7 +1376,7 @@ UniValue listtransactions(const JSONRPCRequest& request)
" with the specified label, or \"*\" to disable filtering and return all transactions."},
{"count", RPCArg::Type::NUM, /* default */ "10", "The number of transactions to return"},
{"skip", RPCArg::Type::NUM, /* default */ "0", "The number of transactions to skip"},
- {"include_watchonly", RPCArg::Type::BOOL, /* default */ "false", "Include transactions to watch-only addresses (see 'importaddress')"},
+ {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Include transactions to watch-only addresses (see 'importaddress')"},
},
RPCResult{
"[\n"
@@ -1424,9 +1439,10 @@ UniValue listtransactions(const JSONRPCRequest& request)
if (!request.params[2].isNull())
nFrom = request.params[2].get_int();
isminefilter filter = ISMINE_SPENDABLE;
- if(!request.params[3].isNull())
- if(request.params[3].get_bool())
- filter = filter | ISMINE_WATCH_ONLY;
+
+ if (ParseIncludeWatchonly(request.params[3], *pwallet)) {
+ filter |= ISMINE_WATCH_ONLY;
+ }
if (nCount < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
@@ -1492,7 +1508,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
{
{"blockhash", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If set, the block hash to list transactions since, otherwise list all transactions."},
{"target_confirmations", RPCArg::Type::NUM, /* default */ "1", "Return the nth block hash from the main chain. e.g. 1 would mean the best block hash. Note: this is not used as a filter, but only affects [lastblock] in the return value"},
- {"include_watchonly", RPCArg::Type::BOOL, /* default */ "false", "Include transactions to watch-only addresses (see 'importaddress')"},
+ {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Include transactions to watch-only addresses (see 'importaddress')"},
{"include_removed", RPCArg::Type::BOOL, /* default */ "true", "Show transactions that were removed due to a reorg in the \"removed\" array\n"
" (not guaranteed to work on pruned nodes)"},
},
@@ -1569,8 +1585,8 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
}
}
- if (!request.params[2].isNull() && request.params[2].get_bool()) {
- filter = filter | ISMINE_WATCH_ONLY;
+ if (ParseIncludeWatchonly(request.params[2], *pwallet)) {
+ filter |= ISMINE_WATCH_ONLY;
}
bool include_removed = (request.params[3].isNull() || request.params[3].get_bool());
@@ -1632,7 +1648,7 @@ static UniValue gettransaction(const JSONRPCRequest& request)
"\nGet detailed information about in-wallet transaction <txid>\n",
{
{"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
- {"include_watchonly", RPCArg::Type::BOOL, /* default */ "false", "Whether to include watch-only addresses in balance calculation and details[]"},
+ {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Whether to include watch-only addresses in balance calculation and details[]"},
},
RPCResult{
"{\n"
@@ -1687,9 +1703,10 @@ static UniValue gettransaction(const JSONRPCRequest& request)
uint256 hash(ParseHashV(request.params[0], "txid"));
isminefilter filter = ISMINE_SPENDABLE;
- if(!request.params[1].isNull())
- if(request.params[1].get_bool())
- filter = filter | ISMINE_WATCH_ONLY;
+
+ if (ParseIncludeWatchonly(request.params[1], *pwallet)) {
+ filter |= ISMINE_WATCH_ONLY;
+ }
UniValue entry(UniValue::VOBJ);
auto it = pwallet->mapWallet.find(hash);
@@ -3015,8 +3032,7 @@ void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& f
}
}
- if (options.exists("includeWatching"))
- coinControl.fAllowWatchOnly = options["includeWatching"].get_bool();
+ coinControl.fAllowWatchOnly = ParseIncludeWatchonly(options["includeWatching"], *pwallet);
if (options.exists("lockUnspents"))
lockUnspents = options["lockUnspents"].get_bool();
@@ -3048,6 +3064,9 @@ void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& f
}
}
}
+ } else {
+ // if options is null and not a bool
+ coinControl.fAllowWatchOnly = ParseIncludeWatchonly(NullUniValue, *pwallet);
}
if (tx.vout.size() == 0)
@@ -3102,7 +3121,7 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request)
{"changeAddress", RPCArg::Type::STR, /* default */ "pool address", "The bitcoin address to receive the change"},
{"changePosition", RPCArg::Type::NUM, /* default */ "random", "The index of the change output"},
{"change_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
- {"includeWatching", RPCArg::Type::BOOL, /* default */ "false", "Also select inputs which are watch only"},
+ {"includeWatching", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Also select inputs which are watch only"},
{"lockUnspents", RPCArg::Type::BOOL, /* default */ "false", "Lock selected unspent outputs"},
{"feeRate", RPCArg::Type::AMOUNT, /* default */ "not set: makes wallet determine the fee", "Set a specific fee rate in " + CURRENCY_UNIT + "/kB"},
{"subtractFeeFromOutputs", RPCArg::Type::ARR, /* default */ "empty array", "A json array of integers.\n"
@@ -4047,7 +4066,7 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
{"changeAddress", RPCArg::Type::STR_HEX, /* default */ "pool address", "The bitcoin address to receive the change"},
{"changePosition", RPCArg::Type::NUM, /* default */ "random", "The index of the change output"},
{"change_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
- {"includeWatching", RPCArg::Type::BOOL, /* default */ "false", "Also select inputs which are watch only"},
+ {"includeWatching", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Also select inputs which are watch only"},
{"lockUnspents", RPCArg::Type::BOOL, /* default */ "false", "Lock selected unspent outputs"},
{"feeRate", RPCArg::Type::AMOUNT, /* default */ "not set: makes wallet determine the fee", "Set a specific fee rate in " + CURRENCY_UNIT + "/kB"},
{"subtractFeeFromOutputs", RPCArg::Type::ARR, /* default */ "empty array", "A json array of integers.\n"
diff --git a/test/functional/feature_bip68_sequence.py b/test/functional/feature_bip68_sequence.py
index f0bf09e172..fe6f9eade1 100755
--- a/test/functional/feature_bip68_sequence.py
+++ b/test/functional/feature_bip68_sequence.py
@@ -14,8 +14,8 @@ from test_framework.util import (
assert_equal,
assert_greater_than,
assert_raises_rpc_error,
- get_bip9_status,
satoshi_round,
+ softfork_active,
)
SEQUENCE_LOCKTIME_DISABLE_FLAG = (1<<31)
@@ -52,7 +52,7 @@ class BIP68Test(BitcoinTestFramework):
self.log.info("Running test sequence-lock-unconfirmed-inputs")
self.test_sequence_lock_unconfirmed_inputs()
- self.log.info("Running test BIP68 not consensus before versionbits activation")
+ self.log.info("Running test BIP68 not consensus before activation")
self.test_bip68_not_consensus()
self.log.info("Activating BIP68 (and 112/113)")
@@ -336,12 +336,12 @@ class BIP68Test(BitcoinTestFramework):
self.nodes[0].invalidateblock(self.nodes[0].getblockhash(cur_height+1))
self.nodes[0].generate(10)
- # Make sure that BIP68 isn't being used to validate blocks, prior to
- # versionbits activation. If more blocks are mined prior to this test
+ # Make sure that BIP68 isn't being used to validate blocks prior to
+ # activation height. If more blocks are mined prior to this test
# being run, then it's possible the test has activated the soft fork, and
# this test should be moved to run earlier, or deleted.
def test_bip68_not_consensus(self):
- assert get_bip9_status(self.nodes[0], 'csv')['status'] != 'active'
+ assert not softfork_active(self.nodes[0], 'csv')
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2)
tx1 = FromHex(CTransaction(), self.nodes[0].getrawtransaction(txid))
@@ -391,9 +391,9 @@ class BIP68Test(BitcoinTestFramework):
height = self.nodes[0].getblockcount()
assert_greater_than(min_activation_height - height, 2)
self.nodes[0].generate(min_activation_height - height - 2)
- assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], "locked_in")
+ assert not softfork_active(self.nodes[0], 'csv')
self.nodes[0].generate(1)
- assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], "active")
+ assert softfork_active(self.nodes[0], 'csv')
self.sync_blocks()
# Use self.nodes[1] to test that version 2 transactions are standard.
diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py
index af34f9f0db..e00219ca4a 100755
--- a/test/functional/feature_cltv.py
+++ b/test/functional/feature_cltv.py
@@ -69,14 +69,11 @@ class BIP65Test(BitcoinTestFramework):
self.skip_if_no_wallet()
def test_cltv_info(self, *, is_active):
- assert_equal(
- next(s for s in self.nodes[0].getblockchaininfo()['softforks'] if s['id'] == 'bip65'),
+ assert_equal(self.nodes[0].getblockchaininfo()['softforks']['bip65'],
{
- "id": "bip65",
- "version": 4,
- "reject": {
- "status": is_active
- }
+ "active": is_active,
+ "height": CLTV_HEIGHT,
+ "type": "buried",
},
)
@@ -104,9 +101,9 @@ class BIP65Test(BitcoinTestFramework):
block.hashMerkleRoot = block.calc_merkle_root()
block.solve()
- self.test_cltv_info(is_active=False)
+ self.test_cltv_info(is_active=False) # Not active as of current tip and next block does not need to obey rules
self.nodes[0].p2p.send_and_ping(msg_block(block))
- self.test_cltv_info(is_active=False) # Not active as of current tip, but next block must obey rules
+ self.test_cltv_info(is_active=True) # Not active as of current tip, but next block must obey rules
assert_equal(self.nodes[0].getbestblockhash(), block.hash)
self.log.info("Test that blocks must now be at least version 4")
@@ -155,7 +152,7 @@ class BIP65Test(BitcoinTestFramework):
block.hashMerkleRoot = block.calc_merkle_root()
block.solve()
- self.test_cltv_info(is_active=False) # Not active as of current tip, but next block must obey rules
+ self.test_cltv_info(is_active=True) # Not active as of current tip, but next block must obey rules
self.nodes[0].p2p.send_and_ping(msg_block(block))
self.test_cltv_info(is_active=True) # Active as of current tip
assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.sha256)
diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py
index 887e9dafa3..6bd321992a 100755
--- a/test/functional/feature_csv_activation.py
+++ b/test/functional/feature_csv_activation.py
@@ -2,23 +2,17 @@
# Copyright (c) 2015-2019 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-"""Test activation of the first version bits soft fork.
+"""Test CSV soft fork activation.
This soft fork will activate the following BIPS:
BIP 68 - nSequence relative lock times
BIP 112 - CHECKSEQUENCEVERIFY
BIP 113 - MedianTimePast semantics for nLockTime
-regtest lock-in with 108/144 block signalling
-activation after a further 144 blocks
-
mine 82 blocks whose coinbases will be used to generate inputs for our tests
-mine 61 blocks to transition from DEFINED to STARTED
-mine 144 blocks only 100 of which are signaling readiness in order to fail to change state this period
-mine 144 blocks with 108 signaling and verify STARTED->LOCKED_IN
-mine 140 blocks and seed block chain with the 82 inputs will use for our tests at height 572
-mine 3 blocks and verify still at LOCKED_IN and test that enforcement has not triggered
-mine 1 block and test that enforcement has triggered (which triggers ACTIVE)
+mine 345 blocks and seed block chain with the 82 inputs will use for our tests at height 427
+mine 2 blocks and verify soft fork not yet activated
+mine 1 block and test that soft fork is activated (rules enforced for next block)
Test BIP 113 is enforced
Mine 4 blocks so next height is 580 and test BIP 68 is enforced for time and height
Mine 1 block so next height is 581 and test BIP 68 now passes time but not height
@@ -58,11 +52,12 @@ from test_framework.script import (
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
- get_bip9_status,
hex_str_to_bytes,
+ softfork_active,
)
BASE_RELATIVE_LOCKTIME = 10
+CSV_ACTIVATION_HEIGHT = 432
SEQ_DISABLE_FLAG = 1 << 31
SEQ_RANDOM_HIGH_BIT = 1 << 25
SEQ_TYPE_FLAG = 1 << 22
@@ -148,20 +143,19 @@ class BIP68_112_113Test(BitcoinTestFramework):
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
- def generate_blocks(self, number, version, test_blocks=None):
- if test_blocks is None:
- test_blocks = []
+ def generate_blocks(self, number):
+ test_blocks = []
for i in range(number):
- block = self.create_test_block([], version)
+ block = self.create_test_block([])
test_blocks.append(block)
self.last_block_time += 600
self.tip = block.sha256
self.tipheight += 1
return test_blocks
- def create_test_block(self, txs, version=536870912):
+ def create_test_block(self, txs):
block = create_block(self.tip, create_coinbase(self.tipheight + 1), self.last_block_time + 600)
- block.nVersion = version
+ block.nVersion = 4
block.vtx.extend(txs)
block.hashMerkleRoot = block.calc_merkle_root()
block.rehash()
@@ -187,45 +181,14 @@ class BIP68_112_113Test(BitcoinTestFramework):
self.tip = int(self.nodes[0].getbestblockhash(), 16)
self.nodeaddress = self.nodes[0].getnewaddress()
- self.log.info("Test that the csv softfork is DEFINED")
- assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'defined')
- test_blocks = self.generate_blocks(61, 4)
- self.send_blocks(test_blocks)
-
- self.log.info("Advance from DEFINED to STARTED, height = 143")
- assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'started')
-
- self.log.info("Fail to achieve LOCKED_IN")
- # 100 out of 144 signal bit 0. Use a variety of bits to simulate multiple parallel softforks
-
- test_blocks = self.generate_blocks(50, 536870913) # 0x20000001 (signalling ready)
- test_blocks = self.generate_blocks(20, 4, test_blocks) # 0x00000004 (signalling not)
- test_blocks = self.generate_blocks(50, 536871169, test_blocks) # 0x20000101 (signalling ready)
- test_blocks = self.generate_blocks(24, 536936448, test_blocks) # 0x20010000 (signalling not)
- self.send_blocks(test_blocks)
-
- self.log.info("Failed to advance past STARTED, height = 287")
- assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'started')
-
- self.log.info("Generate blocks to achieve LOCK-IN")
- # 108 out of 144 signal bit 0 to achieve lock-in
- # using a variety of bits to simulate multiple parallel softforks
- test_blocks = self.generate_blocks(58, 536870913) # 0x20000001 (signalling ready)
- test_blocks = self.generate_blocks(26, 4, test_blocks) # 0x00000004 (signalling not)
- test_blocks = self.generate_blocks(50, 536871169, test_blocks) # 0x20000101 (signalling ready)
- test_blocks = self.generate_blocks(10, 536936448, test_blocks) # 0x20010000 (signalling not)
- self.send_blocks(test_blocks)
-
- self.log.info("Advanced from STARTED to LOCKED_IN, height = 431")
- assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'locked_in')
-
- # Generate 140 more version 4 blocks
- test_blocks = self.generate_blocks(140, 4)
+ # Activation height is hardcoded
+ test_blocks = self.generate_blocks(345)
self.send_blocks(test_blocks)
+ assert not softfork_active(self.nodes[0], 'csv')
- # Inputs at height = 572
+ # Inputs at height = 431
#
- # Put inputs for all tests in the chain at height 572 (tip now = 571) (time increases by 600s per block)
+ # Put inputs for all tests in the chain at height 431 (tip now = 430) (time increases by 600s per block)
# Note we reuse inputs for v1 and v2 txs so must test these separately
# 16 normal inputs
bip68inputs = []
@@ -255,7 +218,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
bip113input = send_generic_input_tx(self.nodes[0], self.coinbase_blocks, self.nodeaddress)
self.nodes[0].setmocktime(self.last_block_time + 600)
- inputblockhash = self.nodes[0].generate(1)[0] # 1 block generated for inputs to be in chain at height 572
+ inputblockhash = self.nodes[0].generate(1)[0] # 1 block generated for inputs to be in chain at height 431
self.nodes[0].setmocktime(0)
self.tip = int(inputblockhash, 16)
self.tipheight += 1
@@ -263,11 +226,12 @@ class BIP68_112_113Test(BitcoinTestFramework):
assert_equal(len(self.nodes[0].getblock(inputblockhash, True)["tx"]), 82 + 1)
# 2 more version 4 blocks
- test_blocks = self.generate_blocks(2, 4)
+ test_blocks = self.generate_blocks(2)
self.send_blocks(test_blocks)
- self.log.info("Not yet advanced to ACTIVE, height = 574 (will activate for block 576, not 575)")
- assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'locked_in')
+ assert_equal(self.tipheight, CSV_ACTIVATION_HEIGHT - 2)
+ self.log.info("Height = {}, CSV not yet active (will activate for block {}, not {})".format(self.tipheight, CSV_ACTIVATION_HEIGHT, CSV_ACTIVATION_HEIGHT - 1))
+ assert not softfork_active(self.nodes[0], 'csv')
# Test both version 1 and version 2 transactions for all tests
# BIP113 test transaction will be modified before each use to put in appropriate block time
@@ -340,10 +304,11 @@ class BIP68_112_113Test(BitcoinTestFramework):
self.send_blocks([self.create_test_block(success_txs)])
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
- # 1 more version 4 block to get us to height 575 so the fork should now be active for the next block
- test_blocks = self.generate_blocks(1, 4)
+ # 1 more version 4 block to get us to height 432 so the fork should now be active for the next block
+ assert not softfork_active(self.nodes[0], 'csv')
+ test_blocks = self.generate_blocks(1)
self.send_blocks(test_blocks)
- assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'active')
+ assert softfork_active(self.nodes[0], 'csv')
self.log.info("Post-Soft Fork Tests.")
@@ -364,8 +329,8 @@ class BIP68_112_113Test(BitcoinTestFramework):
self.send_blocks([self.create_test_block([bip113tx])])
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
- # Next block height = 580 after 4 blocks of random version
- test_blocks = self.generate_blocks(4, 1234)
+ # Next block height = 437 after 4 blocks of random version
+ test_blocks = self.generate_blocks(4)
self.send_blocks(test_blocks)
self.log.info("BIP 68 tests")
@@ -392,8 +357,8 @@ class BIP68_112_113Test(BitcoinTestFramework):
for tx in bip68heighttxs:
self.send_blocks([self.create_test_block([tx])], success=False)
- # Advance one block to 581
- test_blocks = self.generate_blocks(1, 1234)
+ # Advance one block to 438
+ test_blocks = self.generate_blocks(1)
self.send_blocks(test_blocks)
# Height txs should fail and time txs should now pass 9 * 600 > 10 * 512
@@ -403,8 +368,8 @@ class BIP68_112_113Test(BitcoinTestFramework):
for tx in bip68heighttxs:
self.send_blocks([self.create_test_block([tx])], success=False)
- # Advance one block to 582
- test_blocks = self.generate_blocks(1, 1234)
+ # Advance one block to 439
+ test_blocks = self.generate_blocks(1)
self.send_blocks(test_blocks)
# All BIP 68 txs should pass
diff --git a/test/functional/feature_dbcrash.py b/test/functional/feature_dbcrash.py
index ff014de0e0..b86f6af4ca 100755
--- a/test/functional/feature_dbcrash.py
+++ b/test/functional/feature_dbcrash.py
@@ -58,7 +58,7 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
self.base_args = ["-limitdescendantsize=0", "-maxmempool=0", "-rpcservertimeout=900", "-dbbatchsize=200000"]
# Set different crash ratios and cache sizes. Note that not all of
- # -dbcache goes to pcoinsTip.
+ # -dbcache goes to the in-memory coins cache.
self.node0_args = ["-dbcrashratio=8", "-dbcache=4"] + self.base_args
self.node1_args = ["-dbcrashratio=16", "-dbcache=8"] + self.base_args
self.node2_args = ["-dbcrashratio=24", "-dbcache=16"] + self.base_args
diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py
index 067e3be1f4..1bd9586364 100755
--- a/test/functional/feature_dersig.py
+++ b/test/functional/feature_dersig.py
@@ -52,14 +52,11 @@ class BIP66Test(BitcoinTestFramework):
self.skip_if_no_wallet()
def test_dersig_info(self, *, is_active):
- assert_equal(
- next(s for s in self.nodes[0].getblockchaininfo()['softforks'] if s['id'] == 'bip66'),
+ assert_equal(self.nodes[0].getblockchaininfo()['softforks']['bip66'],
{
- "id": "bip66",
- "version": 3,
- "reject": {
- "status": is_active
- }
+ "active": is_active,
+ "height": DERSIG_HEIGHT,
+ "type": "buried",
},
)
@@ -88,9 +85,9 @@ class BIP66Test(BitcoinTestFramework):
block.rehash()
block.solve()
- self.test_dersig_info(is_active=False)
+ self.test_dersig_info(is_active=False) # Not active as of current tip and next block does not need to obey rules
self.nodes[0].p2p.send_and_ping(msg_block(block))
- self.test_dersig_info(is_active=False) # Not active as of current tip, but next block must obey rules
+ self.test_dersig_info(is_active=True) # Not active as of current tip, but next block must obey rules
assert_equal(self.nodes[0].getbestblockhash(), block.hash)
self.log.info("Test that blocks must now be at least version 3")
@@ -144,7 +141,7 @@ class BIP66Test(BitcoinTestFramework):
block.rehash()
block.solve()
- self.test_dersig_info(is_active=False) # Not active as of current tip, but next block must obey rules
+ self.test_dersig_info(is_active=True) # Not active as of current tip, but next block must obey rules
self.nodes[0].p2p.send_and_ping(msg_block(block))
self.test_dersig_info(is_active=True) # Active as of current tip
assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.sha256)
diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py
index 60a703c48f..250dee1528 100755
--- a/test/functional/feature_nulldummy.py
+++ b/test/functional/feature_nulldummy.py
@@ -41,7 +41,7 @@ class NULLDUMMYTest(BitcoinTestFramework):
self.setup_clean_chain = True
# This script tests NULLDUMMY activation, which is part of the 'segwit' deployment, so we go through
# normal segwit activation here (and don't use the default always-on behaviour).
- self.extra_args = [['-whitelist=127.0.0.1', '-vbparams=segwit:0:999999999999', '-addresstype=legacy']]
+ self.extra_args = [['-whitelist=127.0.0.1', '-segwitheight=432', '-addresstype=legacy']]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py
index a71d4071d5..d47065d1cb 100755
--- a/test/functional/feature_segwit.py
+++ b/test/functional/feature_segwit.py
@@ -55,20 +55,20 @@ class SegWitTest(BitcoinTestFramework):
[
"-acceptnonstdtxn=1",
"-rpcserialversion=0",
- "-vbparams=segwit:0:999999999999",
+ "-segwitheight=432",
"-addresstype=legacy",
],
[
"-acceptnonstdtxn=1",
"-blockversion=4",
"-rpcserialversion=1",
- "-vbparams=segwit:0:999999999999",
+ "-segwitheight=432",
"-addresstype=legacy",
],
[
"-acceptnonstdtxn=1",
"-blockversion=536870915",
- "-vbparams=segwit:0:999999999999",
+ "-segwitheight=432",
"-addresstype=legacy",
],
]
diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py
index eb3336bd3b..7905cf5018 100755
--- a/test/functional/p2p_compactblocks.py
+++ b/test/functional/p2p_compactblocks.py
@@ -14,7 +14,7 @@ from test_framework.messages import BlockTransactions, BlockTransactionsRequest,
from test_framework.mininode import mininode_lock, P2PInterface
from test_framework.script import CScript, OP_TRUE, OP_DROP
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, get_bip9_status, wait_until
+from test_framework.util import assert_equal, wait_until, softfork_active
# TestP2PConn: A peer we use to send messages to bitcoind, and store responses.
class TestP2PConn(P2PInterface):
@@ -803,7 +803,7 @@ class CompactBlocksTest(BitcoinTestFramework):
# We will need UTXOs to construct transactions in later tests.
self.make_utxos()
- assert_equal(get_bip9_status(self.nodes[0], "segwit")["status"], 'active')
+ assert softfork_active(self.nodes[0], "segwit")
self.log.info("Testing SENDCMPCT p2p message... ")
self.test_sendcmpct(self.segwit_node, old_node=self.old_node)
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index dca71aec43..98f6b1d71d 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -76,7 +76,7 @@ from test_framework.util import (
assert_equal,
connect_nodes,
disconnect_nodes,
- get_bip9_status,
+ softfork_active,
hex_str_to_bytes,
assert_raises_rpc_error,
)
@@ -88,6 +88,8 @@ VB_TOP_BITS = 0x20000000
MAX_SIGOP_COST = 80000
+SEGWIT_HEIGHT = 120
+
class UTXO():
"""Used to keep track of anyone-can-spend outputs that we can use in the tests."""
def __init__(self, sha256, n, value):
@@ -185,9 +187,9 @@ class SegWitTest(BitcoinTestFramework):
self.num_nodes = 3
# This test tests SegWit both pre and post-activation, so use the normal BIP9 activation.
self.extra_args = [
- ["-whitelist=127.0.0.1", "-acceptnonstdtxn=1", "-vbparams=segwit:0:999999999999"],
- ["-whitelist=127.0.0.1", "-acceptnonstdtxn=0", "-vbparams=segwit:0:999999999999"],
- ["-whitelist=127.0.0.1", "-acceptnonstdtxn=1", "-vbparams=segwit:0:0"],
+ ["-whitelist=127.0.0.1", "-acceptnonstdtxn=1", "-segwitheight={}".format(SEGWIT_HEIGHT)],
+ ["-whitelist=127.0.0.1", "-acceptnonstdtxn=0", "-segwitheight={}".format(SEGWIT_HEIGHT)],
+ ["-whitelist=127.0.0.1", "-acceptnonstdtxn=1", "-segwitheight=-1"]
]
def skip_test_if_missing_module(self):
@@ -231,26 +233,18 @@ class SegWitTest(BitcoinTestFramework):
# Keep a place to store utxo's that can be used in later tests
self.utxo = []
- # Segwit status 'defined'
- self.segwit_status = 'defined'
+ self.log.info("Starting tests before segwit activation")
+ self.segwit_active = False
self.test_non_witness_transaction()
- self.test_unnecessary_witness_before_segwit_activation()
self.test_v0_outputs_arent_spendable()
self.test_block_relay()
- self.advance_to_segwit_started()
-
- # Segwit status 'started'
-
self.test_getblocktemplate_before_lockin()
- self.advance_to_segwit_lockin()
-
- # Segwit status 'locked_in'
-
self.test_unnecessary_witness_before_segwit_activation()
self.test_witness_tx_relay_before_segwit_activation()
- self.test_block_relay()
self.test_standardness_v0()
+
+ self.log.info("Advancing to segwit activation")
self.advance_to_segwit_active()
# Segwit status 'active'
@@ -282,15 +276,15 @@ class SegWitTest(BitcoinTestFramework):
def subtest(func): # noqa: N805
"""Wraps the subtests for logging and state assertions."""
def func_wrapper(self, *args, **kwargs):
- self.log.info("Subtest: {} (Segwit status = {})".format(func.__name__, self.segwit_status))
+ self.log.info("Subtest: {} (Segwit active = {})".format(func.__name__, self.segwit_active))
# Assert segwit status is as expected
- assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], self.segwit_status)
+ assert_equal(softfork_active(self.nodes[0], 'segwit'), self.segwit_active)
func(self, *args, **kwargs)
# Each subtest should leave some utxos for the next subtest
assert self.utxo
self.sync_blocks()
# Assert segwit status is as expected at end of subtest
- assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], self.segwit_status)
+ assert_equal(softfork_active(self.nodes[0], 'segwit'), self.segwit_active)
return func_wrapper
@@ -392,7 +386,7 @@ class SegWitTest(BitcoinTestFramework):
# Check that we can getdata for witness blocks or regular blocks,
# and the right thing happens.
- if self.segwit_status != 'active':
+ if not self.segwit_active:
# Before activation, we should be able to request old blocks with
# or without witness, and they should be the same.
chain_height = self.nodes[0].getblockcount()
@@ -536,32 +530,18 @@ class SegWitTest(BitcoinTestFramework):
self.utxo.append(UTXO(txid, 2, value))
@subtest
- def advance_to_segwit_started(self):
- """Mine enough blocks for segwit's vb state to be 'started'."""
- height = self.nodes[0].getblockcount()
- # Will need to rewrite the tests here if we are past the first period
- assert height < VB_PERIOD - 1
- # Advance to end of period, status should now be 'started'
- self.nodes[0].generate(VB_PERIOD - height - 1)
- assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'started')
- self.segwit_status = 'started'
-
- @subtest
def test_getblocktemplate_before_lockin(self):
txid = int(self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1), 16)
for node in [self.nodes[0], self.nodes[2]]:
gbt_results = node.getblocktemplate({"rules": ["segwit"]})
- block_version = gbt_results['version']
if node == self.nodes[2]:
# If this is a non-segwit node, we should not get a witness
- # commitment, nor a version bit signalling segwit.
- assert_equal(block_version & (1 << VB_WITNESS_BIT), 0)
+ # commitment.
assert 'default_witness_commitment' not in gbt_results
else:
- # For segwit-aware nodes, check the version bit and the witness
- # commitment are correct.
- assert block_version & (1 << VB_WITNESS_BIT) != 0
+ # For segwit-aware nodes, check the witness
+ # commitment is correct.
assert 'default_witness_commitment' in gbt_results
witness_commitment = gbt_results['default_witness_commitment']
@@ -571,18 +551,9 @@ class SegWitTest(BitcoinTestFramework):
script = get_witness_script(witness_root, 0)
assert_equal(witness_commitment, script.hex())
- @subtest
- def advance_to_segwit_lockin(self):
- """Mine enough blocks to lock in segwit, but don't activate."""
- height = self.nodes[0].getblockcount()
- # Advance to end of period, and verify lock-in happens at the end
- self.nodes[0].generate(VB_PERIOD - 1)
- height = self.nodes[0].getblockcount()
- assert (height % VB_PERIOD) == VB_PERIOD - 2
- assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'started')
+ # Clear out the mempool
self.nodes[0].generate(1)
- assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'locked_in')
- self.segwit_status = 'locked_in'
+ self.sync_blocks()
@subtest
def test_witness_tx_relay_before_segwit_activation(self):
@@ -686,7 +657,7 @@ class SegWitTest(BitcoinTestFramework):
tx3.wit.vtxinwit.append(CTxInWitness())
tx3.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
tx3.rehash()
- if self.segwit_status != 'active':
+ if not self.segwit_active:
# Just check mempool acceptance, but don't add the transaction to the mempool, since witness is disallowed
# in blocks and the tx is impossible to mine right now.
assert_equal(self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()]), [{'txid': tx3.hash, 'allowed': True}])
@@ -707,12 +678,13 @@ class SegWitTest(BitcoinTestFramework):
@subtest
def advance_to_segwit_active(self):
"""Mine enough blocks to activate segwit."""
+ assert not softfork_active(self.nodes[0], 'segwit')
height = self.nodes[0].getblockcount()
- self.nodes[0].generate(VB_PERIOD - (height % VB_PERIOD) - 2)
- assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'locked_in')
+ self.nodes[0].generate(SEGWIT_HEIGHT - height - 2)
+ assert not softfork_active(self.nodes[0], 'segwit')
self.nodes[0].generate(1)
- assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'active')
- self.segwit_status = 'active'
+ assert softfork_active(self.nodes[0], 'segwit')
+ self.segwit_active = True
@subtest
def test_p2sh_witness(self):
@@ -1924,13 +1896,13 @@ class SegWitTest(BitcoinTestFramework):
# Restart with the new binary
self.stop_node(2)
- self.start_node(2, extra_args=["-vbparams=segwit:0:999999999999"])
+ self.start_node(2, extra_args=["-segwitheight={}".format(SEGWIT_HEIGHT)])
connect_nodes(self.nodes[0], 2)
self.sync_blocks()
# Make sure that this peer thinks segwit has activated.
- assert get_bip9_status(self.nodes[2], 'segwit')['status'] == "active"
+ assert softfork_active(self.nodes[2], 'segwit')
# Make sure this peer's blocks match those of node0.
height = self.nodes[2].getblockcount()
diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py
index facb05b54c..6c30e05084 100755
--- a/test/functional/rpc_blockchain.py
+++ b/test/functional/rpc_blockchain.py
@@ -78,7 +78,6 @@ class BlockchainTest(BitcoinTestFramework):
keys = [
'bestblockhash',
- 'bip9_softforks',
'blocks',
'chain',
'chainwork',
@@ -124,6 +123,31 @@ class BlockchainTest(BitcoinTestFramework):
assert_equal(res['prune_target_size'], 576716800)
assert_greater_than(res['size_on_disk'], 0)
+ assert_equal(res['softforks'], {
+ 'bip34': {'type': 'buried', 'active': False, 'height': 500},
+ 'bip66': {'type': 'buried', 'active': False, 'height': 1251},
+ 'bip65': {'type': 'buried', 'active': False, 'height': 1351},
+ 'csv': {'type': 'buried', 'active': False, 'height': 432},
+ 'segwit': {'type': 'buried', 'active': True, 'height': 0},
+ 'testdummy': {
+ 'type': 'bip9',
+ 'bip9': {
+ 'status': 'started',
+ 'bit': 28,
+ 'startTime': 0,
+ 'timeout': 0x7fffffffffffffff, # testdummy does not have a timeout so is set to the max int64 value
+ 'since': 144,
+ 'statistics': {
+ 'period': 144,
+ 'threshold': 108,
+ 'elapsed': 57,
+ 'count': 57,
+ 'possible': True,
+ },
+ },
+ 'active': False}
+ })
+
def _test_getchaintxstats(self):
self.log.info("Test getchaintxstats")
diff --git a/test/functional/test_framework/address.py b/test/functional/test_framework/address.py
index f36cffe957..194f2f061b 100644
--- a/test/functional/test_framework/address.py
+++ b/test/functional/test_framework/address.py
@@ -4,6 +4,8 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Encode and decode BASE58, P2PKH and P2SH addresses."""
+import enum
+
from .script import hash256, hash160, sha256, CScript, OP_0
from .util import hex_str_to_bytes
@@ -11,6 +13,13 @@ from . import segwit_addr
ADDRESS_BCRT1_UNSPENDABLE = 'bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3xueyj'
+
+class AddressType(enum.Enum):
+ bech32 = 'bech32'
+ p2sh_segwit = 'p2sh-segwit'
+ legacy = 'legacy' # P2PKH
+
+
chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index 7beddc6407..3d9be0d0a6 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -335,9 +335,9 @@ def delete_cookie_file(datadir, chain):
logger.debug("Deleting leftover cookie file")
os.remove(os.path.join(datadir, chain, ".cookie"))
-def get_bip9_status(node, key):
- info = node.getblockchaininfo()
- return info['bip9_softforks'][key]
+def softfork_active(node, key):
+ """Return whether a softfork is active."""
+ return node.getblockchaininfo()['softforks'][key]['active']
def set_node_times(nodes, t):
for node in nodes:
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 1742a8e319..bca5ac644f 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -129,6 +129,8 @@ BASE_SCRIPTS = [
'wallet_multiwallet.py --usecli',
'wallet_createwallet.py',
'wallet_createwallet.py --usecli',
+ 'wallet_watchonly.py',
+ 'wallet_watchonly.py --usecli',
'interface_http.py',
'interface_rpc.py',
'rpc_psbt.py',
@@ -228,6 +230,7 @@ def main():
epilog='''
Help text and arguments for individual test script:''',
formatter_class=argparse.RawTextHelpFormatter)
+ parser.add_argument('--ansi', action='store_true', default=sys.stdout.isatty(), help="Use ANSI colors and dots in output (enabled by default when standard output is a TTY)")
parser.add_argument('--combinedlogslen', '-c', type=int, default=0, metavar='n', help='On failure, print a log (of length n lines) to the console, combined from the test framework and all test nodes.')
parser.add_argument('--coverage', action='store_true', help='generate a basic coverage report for the RPC interface')
parser.add_argument('--ci', action='store_true', help='Run checks and code that are usually only enabled in a continuous integration environment')
@@ -240,7 +243,14 @@ def main():
parser.add_argument('--tmpdirprefix', '-t', default=tempfile.gettempdir(), help="Root directory for datadirs")
parser.add_argument('--failfast', action='store_true', help='stop execution after the first test failure')
parser.add_argument('--filter', help='filter scripts to run by regular expression')
+
args, unknown_args = parser.parse_known_args()
+ if not args.ansi:
+ global BOLD, GREEN, RED, GREY
+ BOLD = ("", "")
+ GREEN = ("", "")
+ RED = ("", "")
+ GREY = ("", "")
# args to be passed on always start with two dashes; tests are the remaining unknown args
tests = [arg for arg in unknown_args if arg[:2] != "--"]
@@ -342,9 +352,10 @@ def main():
combined_logs_len=args.combinedlogslen,
failfast=args.failfast,
runs_ci=args.ci,
+ use_term_control=args.ansi,
)
-def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=False, args=None, combined_logs_len=0, failfast=False, runs_ci):
+def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=False, args=None, combined_logs_len=0, failfast=False, runs_ci, use_term_control):
args = args or []
# Warn if bitcoind is already running (unix only)
@@ -386,6 +397,7 @@ def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=
test_list=test_list,
flags=flags,
timeout_duration=40 * 60 if runs_ci else float('inf'), # in seconds
+ use_term_control=use_term_control,
)
start_time = time.time()
test_results = []
@@ -469,7 +481,7 @@ class TestHandler:
Trigger the test scripts passed in via the list.
"""
- def __init__(self, *, num_tests_parallel, tests_dir, tmpdir, test_list, flags, timeout_duration):
+ def __init__(self, *, num_tests_parallel, tests_dir, tmpdir, test_list, flags, timeout_duration, use_term_control):
assert num_tests_parallel >= 1
self.num_jobs = num_tests_parallel
self.tests_dir = tests_dir
@@ -479,6 +491,7 @@ class TestHandler:
self.flags = flags
self.num_running = 0
self.jobs = []
+ self.use_term_control = use_term_control
def get_next(self):
while self.num_running < self.num_jobs and self.test_list:
@@ -530,11 +543,13 @@ class TestHandler:
status = "Failed"
self.num_running -= 1
self.jobs.remove(job)
- clearline = '\r' + (' ' * dot_count) + '\r'
- print(clearline, end='', flush=True)
+ if self.use_term_control:
+ clearline = '\r' + (' ' * dot_count) + '\r'
+ print(clearline, end='', flush=True)
dot_count = 0
return TestResult(name, status, int(time.time() - start_time)), testdir, stdout, stderr
- print('.', end='', flush=True)
+ if self.use_term_control:
+ print('.', end='', flush=True)
dot_count += 1
def kill_and_join(self):
diff --git a/test/functional/wallet_import_rescan.py b/test/functional/wallet_import_rescan.py
index 47c97f62bf..4e20892596 100755
--- a/test/functional/wallet_import_rescan.py
+++ b/test/functional/wallet_import_rescan.py
@@ -20,6 +20,7 @@ happened previously.
"""
from test_framework.test_framework import BitcoinTestFramework
+from test_framework.address import AddressType
from test_framework.util import (
connect_nodes,
assert_equal,
@@ -27,21 +28,30 @@ from test_framework.util import (
)
import collections
+from decimal import Decimal
import enum
import itertools
+import random
Call = enum.Enum("Call", "single multiaddress multiscript")
Data = enum.Enum("Data", "address pub priv")
Rescan = enum.Enum("Rescan", "no yes late_timestamp")
-class Variant(collections.namedtuple("Variant", "call data rescan prune")):
+class Variant(collections.namedtuple("Variant", "call data address_type rescan prune")):
"""Helper for importing one key and verifying scanned transactions."""
def do_import(self, timestamp):
"""Call one key import RPC."""
rescan = self.rescan == Rescan.yes
+ assert_equal(self.address["solvable"], True)
+ assert_equal(self.address["isscript"], self.address_type == AddressType.p2sh_segwit)
+ assert_equal(self.address["iswitness"], self.address_type == AddressType.bech32)
+ if self.address["isscript"]:
+ assert_equal(self.address["embedded"]["isscript"], False)
+ assert_equal(self.address["embedded"]["iswitness"], True)
+
if self.call == Call.single:
if self.data == Data.address:
response = self.node.importaddress(address=self.address["address"], label=self.label, rescan=rescan)
@@ -52,7 +62,7 @@ class Variant(collections.namedtuple("Variant", "call data rescan prune")):
assert_equal(response, None)
elif self.call in (Call.multiaddress, Call.multiscript):
- response = self.node.importmulti([{
+ request = {
"scriptPubKey": {
"address": self.address["address"]
} if self.call == Call.multiaddress else self.address["scriptPubKey"],
@@ -61,13 +71,21 @@ class Variant(collections.namedtuple("Variant", "call data rescan prune")):
"keys": [self.key] if self.data == Data.priv else [],
"label": self.label,
"watchonly": self.data != Data.priv
- }], {"rescan": self.rescan in (Rescan.yes, Rescan.late_timestamp)})
+ }
+ if self.address_type == AddressType.p2sh_segwit and self.data != Data.address:
+ # We need solving data when providing a pubkey or privkey as data
+ request.update({"redeemscript": self.address['embedded']['scriptPubKey']})
+ response = self.node.importmulti(
+ requests=[request],
+ options={"rescan": self.rescan in (Rescan.yes, Rescan.late_timestamp)},
+ )
assert_equal(response, [{"success": True}])
- def check(self, txid=None, amount=None, confirmations=None):
+ def check(self, txid=None, amount=None, confirmation_height=None):
"""Verify that listtransactions/listreceivedbyaddress return expected values."""
txs = self.node.listtransactions(label=self.label, count=10000, include_watchonly=True)
+ current_height = self.node.getblockcount()
assert_equal(len(txs), self.expected_txs)
addresses = self.node.listreceivedbyaddress(minconf=0, include_watchonly=True, address_filter=self.address['address'])
@@ -82,13 +100,13 @@ class Variant(collections.namedtuple("Variant", "call data rescan prune")):
assert_equal(tx["category"], "receive")
assert_equal(tx["label"], self.label)
assert_equal(tx["txid"], txid)
- assert_equal(tx["confirmations"], confirmations)
+ assert_equal(tx["confirmations"], 1 + current_height - confirmation_height)
assert_equal("trusted" not in tx, True)
address, = [ad for ad in addresses if txid in ad["txids"]]
assert_equal(address["address"], self.address["address"])
assert_equal(address["amount"], self.expected_balance)
- assert_equal(address["confirmations"], confirmations)
+ assert_equal(address["confirmations"], 1 + current_height - confirmation_height)
# Verify the transaction is correctly marked watchonly depending on
# whether the transaction pays to an imported public key or
# imported private key. The test setup ensures that transaction
@@ -102,7 +120,7 @@ class Variant(collections.namedtuple("Variant", "call data rescan prune")):
# List of Variants for each way a key or address could be imported.
-IMPORT_VARIANTS = [Variant(*variants) for variants in itertools.product(Call, Data, Rescan, (False, True))]
+IMPORT_VARIANTS = [Variant(*variants) for variants in itertools.product(Call, Data, AddressType, Rescan, (False, True))]
# List of nodes to import keys to. Half the nodes will have pruning disabled,
# half will have it enabled. Different nodes will be used for imports that are
@@ -116,6 +134,13 @@ IMPORT_NODES = [ImportNode(*fields) for fields in itertools.product((False, True
# Rescans start at the earliest block up to 2 hours before the key timestamp.
TIMESTAMP_WINDOW = 2 * 60 * 60
+AMOUNT_DUST = 0.00000546
+
+
+def get_rand_amount():
+ r = random.uniform(AMOUNT_DUST, 1)
+ return Decimal(str(round(r, 8)))
+
class ImportRescanTest(BitcoinTestFramework):
def set_test_params(self):
@@ -125,12 +150,12 @@ class ImportRescanTest(BitcoinTestFramework):
self.skip_if_no_wallet()
def setup_network(self):
- extra_args = [["-addresstype=legacy"] for _ in range(self.num_nodes)]
+ self.extra_args = [[]] * self.num_nodes
for i, import_node in enumerate(IMPORT_NODES, 2):
if import_node.prune:
- extra_args[i] += ["-prune=1"]
+ self.extra_args[i] += ["-prune=1"]
- self.add_nodes(self.num_nodes, extra_args=extra_args)
+ self.add_nodes(self.num_nodes, extra_args=self.extra_args)
# Import keys with pruning disabled
self.start_nodes(extra_args=[[]] * self.num_nodes)
@@ -147,17 +172,23 @@ class ImportRescanTest(BitcoinTestFramework):
# each possible type of wallet import RPC.
for i, variant in enumerate(IMPORT_VARIANTS):
variant.label = "label {} {}".format(i, variant)
- variant.address = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress(variant.label))
+ variant.address = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress(
+ label=variant.label,
+ address_type=variant.address_type.value,
+ ))
variant.key = self.nodes[1].dumpprivkey(variant.address["address"])
- variant.initial_amount = 1 - (i + 1) / 64
+ variant.initial_amount = get_rand_amount()
variant.initial_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.initial_amount)
+ self.nodes[0].generate(1) # Generate one block for each send
+ variant.confirmation_height = self.nodes[0].getblockcount()
+ variant.timestamp = self.nodes[0].getblockheader(self.nodes[0].getbestblockhash())["time"]
- # Generate a block containing the initial transactions, then another
- # block further in the future (past the rescan window).
- self.nodes[0].generate(1)
+ # Generate a block further in the future (past the rescan window).
assert_equal(self.nodes[0].getrawmempool(), [])
- timestamp = self.nodes[0].getblockheader(self.nodes[0].getbestblockhash())["time"]
- set_node_times(self.nodes, timestamp + TIMESTAMP_WINDOW + 1)
+ set_node_times(
+ self.nodes,
+ self.nodes[0].getblockheader(self.nodes[0].getbestblockhash())["time"] + TIMESTAMP_WINDOW + 1,
+ )
self.nodes[0].generate(1)
self.sync_all()
@@ -167,11 +198,11 @@ class ImportRescanTest(BitcoinTestFramework):
self.log.info('Run import for variant {}'.format(variant))
expect_rescan = variant.rescan == Rescan.yes
variant.node = self.nodes[2 + IMPORT_NODES.index(ImportNode(variant.prune, expect_rescan))]
- variant.do_import(timestamp)
+ variant.do_import(variant.timestamp)
if expect_rescan:
variant.expected_balance = variant.initial_amount
variant.expected_txs = 1
- variant.check(variant.initial_txid, variant.initial_amount, 2)
+ variant.check(variant.initial_txid, variant.initial_amount, variant.confirmation_height)
else:
variant.expected_balance = 0
variant.expected_txs = 0
@@ -179,11 +210,11 @@ class ImportRescanTest(BitcoinTestFramework):
# Create new transactions sending to each address.
for i, variant in enumerate(IMPORT_VARIANTS):
- variant.sent_amount = 1 - (2 * i + 1) / 128
+ variant.sent_amount = get_rand_amount()
variant.sent_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.sent_amount)
+ self.nodes[0].generate(1) # Generate one block for each send
+ variant.confirmation_height = self.nodes[0].getblockcount()
- # Generate a block containing the new transactions.
- self.nodes[0].generate(1)
assert_equal(self.nodes[0].getrawmempool(), [])
self.sync_all()
@@ -192,7 +223,7 @@ class ImportRescanTest(BitcoinTestFramework):
self.log.info('Run check for variant {}'.format(variant))
variant.expected_balance += variant.sent_amount
variant.expected_txs += 1
- variant.check(variant.sent_txid, variant.sent_amount, 1)
+ variant.check(variant.sent_txid, variant.sent_amount, variant.confirmation_height)
if __name__ == "__main__":
ImportRescanTest().main()
diff --git a/test/functional/wallet_watchonly.py b/test/functional/wallet_watchonly.py
new file mode 100644
index 0000000000..be8d7714fb
--- /dev/null
+++ b/test/functional/wallet_watchonly.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python3
+# Copyright (c) 2018-2019 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test createwallet arguments.
+"""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ assert_raises_rpc_error
+)
+
+
+class CreateWalletWatchonlyTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = False
+ self.num_nodes = 1
+ self.supports_cli = True
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def run_test(self):
+ node = self.nodes[0]
+
+ self.nodes[0].createwallet(wallet_name='default')
+ def_wallet = node.get_wallet_rpc('default')
+
+ a1 = def_wallet.getnewaddress()
+ wo_change = def_wallet.getnewaddress()
+ wo_addr = def_wallet.getnewaddress()
+
+ self.nodes[0].createwallet(wallet_name='wo', disable_private_keys=True)
+ wo_wallet = node.get_wallet_rpc('wo')
+
+ wo_wallet.importpubkey(pubkey=def_wallet.getaddressinfo(wo_addr)['pubkey'])
+ wo_wallet.importpubkey(pubkey=def_wallet.getaddressinfo(wo_change)['pubkey'])
+
+ # generate some btc for testing
+ node.generatetoaddress(101, a1)
+
+ # send 1 btc to our watch-only address
+ txid = def_wallet.sendtoaddress(wo_addr, 1)
+ self.nodes[0].generate(1)
+
+ # getbalance
+ self.log.info('include_watchonly should default to true for watch-only wallets')
+ self.log.info('Testing getbalance watch-only defaults')
+ assert_equal(wo_wallet.getbalance(), 1)
+ assert_equal(len(wo_wallet.listtransactions()), 1)
+ assert_equal(wo_wallet.getbalance(include_watchonly=False), 0)
+
+ self.log.info('Testing listreceivedbyaddress watch-only defaults')
+ result = wo_wallet.listreceivedbyaddress()
+ assert_equal(len(result), 1)
+ assert_equal(result[0]["involvesWatchonly"], True)
+ result = wo_wallet.listreceivedbyaddress(include_watchonly=False)
+ assert_equal(len(result), 0)
+
+ self.log.info('Testing listreceivedbylabel watch-only defaults')
+ result = wo_wallet.listreceivedbylabel()
+ assert_equal(len(result), 1)
+ assert_equal(result[0]["involvesWatchonly"], True)
+ result = wo_wallet.listreceivedbylabel(include_watchonly=False)
+ assert_equal(len(result), 0)
+
+ self.log.info('Testing listtransactions watch-only defaults')
+ result = wo_wallet.listtransactions()
+ assert_equal(len(result), 1)
+ assert_equal(result[0]["involvesWatchonly"], True)
+ result = wo_wallet.listtransactions(include_watchonly=False)
+ assert_equal(len(result), 0)
+
+ self.log.info('Testing listsinceblock watch-only defaults')
+ result = wo_wallet.listsinceblock()
+ assert_equal(len(result["transactions"]), 1)
+ assert_equal(result["transactions"][0]["involvesWatchonly"], True)
+ result = wo_wallet.listsinceblock(include_watchonly=False)
+ assert_equal(len(result["transactions"]), 0)
+
+ self.log.info('Testing gettransaction watch-only defaults')
+ result = wo_wallet.gettransaction(txid)
+ assert_equal(result["details"][0]["involvesWatchonly"], True)
+ result = wo_wallet.gettransaction(txid=txid, include_watchonly=False)
+ assert_equal(len(result["details"]), 0)
+
+ self.log.info('Testing walletcreatefundedpsbt watch-only defaults')
+ inputs = []
+ outputs = [{a1: 0.5}]
+ options = {'changeAddress': wo_change}
+ no_wo_options = {'changeAddress': wo_change, 'includeWatching': False}
+
+ result = wo_wallet.walletcreatefundedpsbt(inputs=inputs, outputs=outputs, options=options)
+ assert_equal("psbt" in result, True)
+ assert_raises_rpc_error(-4, "Insufficient funds", wo_wallet.walletcreatefundedpsbt, inputs, outputs, 0, no_wo_options)
+
+ self.log.info('Testing fundrawtransaction watch-only defaults')
+ rawtx = wo_wallet.createrawtransaction(inputs=inputs, outputs=outputs)
+ result = wo_wallet.fundrawtransaction(hexstring=rawtx, options=options)
+ assert_equal("hex" in result, True)
+ assert_raises_rpc_error(-4, "Insufficient funds", wo_wallet.fundrawtransaction, rawtx, no_wo_options)
+
+
+
+if __name__ == '__main__':
+ CreateWalletWatchonlyTest().main()
diff --git a/test/lint/lint-python-dead-code-whitelist b/test/lint/lint-python-dead-code-whitelist
new file mode 100644
index 0000000000..2522c8fa1c
--- /dev/null
+++ b/test/lint/lint-python-dead-code-whitelist
@@ -0,0 +1,45 @@
+BadInputOutpointIndex # unused class (test/functional/data/invalid_txs.py)
+_.carbon_path # unused attribute (contrib/macdeploy/custom_dsstore.py)
+connection_lost # unused function (test/functional/test_framework/mininode.py)
+connection_made # unused function (test/functional/test_framework/mininode.py)
+_.converter # unused attribute (test/functional/test_framework/test_framework.py)
+_.daemon # unused attribute (test/functional/test_framework/socks5.py)
+data_received # unused function (test/functional/test_framework/mininode.py)
+DuplicateInput # unused class (test/functional/data/invalid_txs.py)
+_.filename # unused attribute (contrib/macdeploy/custom_dsstore.py)
+InvalidOPIFConstruction # unused class (test/functional/data/invalid_txs.py)
+_.is_compressed # unused property (test/functional/test_framework/key.py)
+legacy # unused variable (test/functional/test_framework/address.py)
+msg_generic # unused class (test/functional/test_framework/messages.py)
+NonexistentInput # unused class (test/functional/data/invalid_txs.py)
+on_addr # unused function (test/functional/test_framework/mininode.py)
+on_blocktxn # unused function (test/functional/test_framework/mininode.py)
+on_block # unused function (test/functional/test_framework/mininode.py)
+on_cmpctblock # unused function (test/functional/test_framework/mininode.py)
+on_feefilter # unused function (test/functional/test_framework/mininode.py)
+on_getaddr # unused function (test/functional/test_framework/mininode.py)
+on_getblocks # unused function (test/functional/test_framework/mininode.py)
+on_getblocktxn # unused function (test/functional/test_framework/mininode.py)
+on_getdata # unused function (test/functional/test_framework/mininode.py)
+on_getheaders # unused function (test/functional/test_framework/mininode.py)
+on_headers # unused function (test/functional/test_framework/mininode.py)
+on_inv # unused function (test/functional/test_framework/mininode.py)
+on_mempool # unused function (test/functional/test_framework/mininode.py)
+on_notfound # unused function (test/functional/test_framework/mininode.py)
+on_ping # unused function (test/functional/test_framework/mininode.py)
+on_pong # unused function (test/functional/test_framework/mininode.py)
+on_reject # unused function (test/functional/test_framework/mininode.py)
+on_sendcmpct # unused function (test/functional/test_framework/mininode.py)
+on_sendheaders # unused function (test/functional/test_framework/mininode.py)
+on_tx # unused function (test/functional/test_framework/mininode.py)
+on_verack # unused function (test/functional/test_framework/mininode.py)
+on_version # unused function (test/functional/test_framework/mininode.py)
+_.optionxform # unused attribute (test/util/bitcoin-util-test.py)
+OutputMissing # unused class (test/functional/data/invalid_txs.py)
+_.posix_path # unused attribute (contrib/macdeploy/custom_dsstore.py)
+profile_with_perf # unused function (test/functional/test_framework/test_node.py)
+SizeTooSmall # unused class (test/functional/data/invalid_txs.py)
+SpendNegative # unused class (test/functional/data/invalid_txs.py)
+SpendTooMuch # unused class (test/functional/data/invalid_txs.py)
+TooManySigops # unused class (test/functional/data/invalid_txs.py)
+verify_ecdsa # unused function (test/functional/test_framework/key.py)
diff --git a/test/lint/lint-python-dead-code.sh b/test/lint/lint-python-dead-code.sh
index 588ba428d7..77bf5990a7 100755
--- a/test/lint/lint-python-dead-code.sh
+++ b/test/lint/lint-python-dead-code.sh
@@ -15,5 +15,5 @@ fi
vulture \
--min-confidence 60 \
- --ignore-names "argtypes,connection_lost,connection_made,converter,data_received,daemon,errcheck,is_compressed,is_valid,verify_ecdsa,msg_generic,on_*,optionxform,restype,profile_with_perf" \
- $(git ls-files -- "*.py" ":(exclude)contrib/" ":(exclude)test/functional/data/invalid_txs.py")
+ $(git rev-parse --show-toplevel) \
+ $(dirname "${BASH_SOURCE[0]}")/lint-python-dead-code-whitelist