aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.appveyor.yml5
-rw-r--r--.gitignore1
-rw-r--r--.travis.yml25
-rwxr-xr-x.travis/test_06_script_a.sh (renamed from .travis/test_06_script.sh)16
-rwxr-xr-x.travis/test_06_script_b.sh21
-rw-r--r--.tx/config2
-rw-r--r--build_msvc/bench_bitcoin/bench_bitcoin.vcxproj6
-rw-r--r--build_msvc/bitcoin-tx/bitcoin-tx.vcxproj3
-rw-r--r--build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj198
-rw-r--r--build_msvc/bitcoin.sln43
-rw-r--r--build_msvc/bitcoind/bitcoind.vcxproj6
-rw-r--r--build_msvc/common.vcxproj11
-rw-r--r--build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in8
-rw-r--r--build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj29
-rw-r--r--build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in8
-rw-r--r--build_msvc/libbitcoin_wallet_tool/libbitcoin_wallet_tool.vcxproj.in166
-rw-r--r--build_msvc/libbitcoinconsensus/libbitcoinconsensus.vcxproj8
-rw-r--r--build_msvc/libleveldb/libleveldb.vcxproj202
-rw-r--r--build_msvc/libsecp256k1/libsecp256k1.vcxproj157
-rw-r--r--build_msvc/libsecp256k1_config.h29
-rw-r--r--build_msvc/msvc-autogen.py1
-rw-r--r--build_msvc/test_bitcoin/test_bitcoin.vcxproj14
-rw-r--r--build_msvc/testconsensus/testconsensus.vcxproj3
-rw-r--r--configure.ac32
-rw-r--r--contrib/bitcoin-cli.bash-completion2
-rwxr-xr-xcontrib/devtools/copyright_header.py47
-rwxr-xr-xcontrib/devtools/gen-manpages.sh3
-rw-r--r--contrib/gitian-keys/keys.txt1
-rw-r--r--contrib/init/bitcoind.service34
-rwxr-xr-xcontrib/linearize/linearize-hashes.py4
-rwxr-xr-xcontrib/verify-commits/verify-commits.py14
-rw-r--r--depends/packages/zeromq.mk4
-rw-r--r--doc/JSON-RPC-interface.md79
-rw-r--r--doc/README_osx.md97
-rw-r--r--doc/REST-interface.md7
-rw-r--r--doc/build-osx.md100
-rw-r--r--doc/dependencies.md2
-rw-r--r--doc/developer-notes.md62
-rw-r--r--doc/fuzzing.md16
-rw-r--r--doc/init.md18
-rw-r--r--doc/man/bitcoin-cli.16
-rw-r--r--doc/man/bitcoin-qt.18
-rw-r--r--doc/man/bitcoin-tx.18
-rw-r--r--doc/man/bitcoin-wallet.167
-rw-r--r--doc/man/bitcoind.18
-rw-r--r--doc/release-notes-14491.md5
-rw-r--r--doc/release-notes-14667.md4
-rw-r--r--doc/release-notes-14941.md5
-rw-r--r--doc/release-notes-14982.md5
-rw-r--r--doc/release-notes-15226.md8
-rw-r--r--doc/release-notes.md79
-rw-r--r--doc/release-notes/release-notes-pr12255.md17
-rw-r--r--doc/release-process.md2
-rw-r--r--doc/translation_process.md20
-rw-r--r--doc/translation_strings_policy.md16
-rw-r--r--src/Makefile.am43
-rw-r--r--src/Makefile.leveldb.include2
-rw-r--r--src/Makefile.test.include397
-rw-r--r--src/addrdb.cpp7
-rw-r--r--src/addrdb.h9
-rw-r--r--src/banman.cpp220
-rw-r--r--src/banman.h70
-rw-r--r--src/bench/bench_bitcoin.cpp9
-rw-r--r--src/bitcoin-cli.cpp7
-rw-r--r--src/bitcoin-tx.cpp11
-rw-r--r--src/bitcoin-wallet-res.rc35
-rw-r--r--src/bitcoin-wallet.cpp117
-rw-r--r--src/chainparams.cpp1
-rw-r--r--src/coins.h12
-rw-r--r--src/compat.h4
-rw-r--r--src/crypto/sha512.h2
-rw-r--r--src/dummywallet.cpp9
-rw-r--r--src/httpserver.cpp4
-rw-r--r--src/init.cpp94
-rw-r--r--src/interfaces/chain.cpp142
-rw-r--r--src/interfaces/chain.h89
-rw-r--r--src/interfaces/node.cpp27
-rw-r--r--src/interfaces/node.h11
-rw-r--r--src/interfaces/wallet.cpp21
-rw-r--r--src/interfaces/wallet.h7
-rw-r--r--src/key.cpp2
-rw-r--r--src/key_io.cpp4
-rw-r--r--src/leveldb/db/c.cc2
-rw-r--r--src/leveldb/port/port_win.h7
-rw-r--r--src/leveldb/util/env_win.cc25
-rw-r--r--src/logging.cpp8
-rw-r--r--src/logging.h8
-rw-r--r--src/net.cpp294
-rw-r--r--src/net.h86
-rw-r--r--src/net_processing.cpp213
-rw-r--r--src/net_processing.h4
-rw-r--r--src/netaddress.cpp16
-rw-r--r--src/netbase.cpp4
-rw-r--r--src/optional.h26
-rw-r--r--src/primitives/transaction.h2
-rw-r--r--src/qt/bitcoin.cpp18
-rw-r--r--src/qt/bitcoingui.cpp46
-rw-r--r--src/qt/bitcoingui.h6
-rw-r--r--src/qt/bitcoinstrings.cpp23
-rw-r--r--src/qt/clientmodel.cpp4
-rw-r--r--src/qt/forms/debugwindow.ui3
-rw-r--r--src/qt/forms/optionsdialog.ui2
-rw-r--r--src/qt/guiconstants.h3
-rw-r--r--src/qt/guiutil.cpp26
-rw-r--r--src/qt/intro.cpp2
-rw-r--r--src/qt/locale/bitcoin_af.ts196
-rw-r--r--src/qt/locale/bitcoin_af_ZA.ts92
-rw-r--r--src/qt/locale/bitcoin_am.ts451
-rw-r--r--src/qt/locale/bitcoin_ar.ts33
-rw-r--r--src/qt/locale/bitcoin_bg.ts40
-rw-r--r--src/qt/locale/bitcoin_cs.ts176
-rw-r--r--src/qt/locale/bitcoin_da.ts14
-rw-r--r--src/qt/locale/bitcoin_de.ts18
-rw-r--r--src/qt/locale/bitcoin_el_GR.ts166
-rw-r--r--src/qt/locale/bitcoin_en.ts550
-rw-r--r--src/qt/locale/bitcoin_en_GB.ts130
-rw-r--r--src/qt/locale/bitcoin_es.ts14
-rw-r--r--src/qt/locale/bitcoin_es_VE.ts96
-rw-r--r--src/qt/locale/bitcoin_eu_ES.ts32
-rw-r--r--src/qt/locale/bitcoin_fa.ts24
-rw-r--r--src/qt/locale/bitcoin_fa_IR.ts1246
-rw-r--r--src/qt/locale/bitcoin_fi.ts162
-rw-r--r--src/qt/locale/bitcoin_fr.ts26
-rw-r--r--src/qt/locale/bitcoin_he.ts32
-rw-r--r--src/qt/locale/bitcoin_hi_IN.ts108
-rw-r--r--src/qt/locale/bitcoin_hr.ts2143
-rw-r--r--src/qt/locale/bitcoin_id.ts969
-rw-r--r--src/qt/locale/bitcoin_id_ID.ts180
-rw-r--r--src/qt/locale/bitcoin_is.ts997
-rw-r--r--src/qt/locale/bitcoin_it.ts8
-rw-r--r--src/qt/locale/bitcoin_it_IT.ts12
-rw-r--r--src/qt/locale/bitcoin_ja.ts100
-rw-r--r--src/qt/locale/bitcoin_ka.ts8
-rw-r--r--src/qt/locale/bitcoin_ko.ts471
-rw-r--r--src/qt/locale/bitcoin_ko_KR.ts11
-rw-r--r--src/qt/locale/bitcoin_lt.ts374
-rw-r--r--src/qt/locale/bitcoin_ml.ts336
-rw-r--r--src/qt/locale/bitcoin_nl.ts14
-rw-r--r--src/qt/locale/bitcoin_pl.ts11
-rw-r--r--src/qt/locale/bitcoin_pt_BR.ts13
-rw-r--r--src/qt/locale/bitcoin_pt_PT.ts111
-rw-r--r--src/qt/locale/bitcoin_ro.ts4
-rw-r--r--src/qt/locale/bitcoin_ro_RO.ts144
-rw-r--r--src/qt/locale/bitcoin_ru.ts4
-rw-r--r--src/qt/locale/bitcoin_ru_RU.ts150
-rw-r--r--src/qt/locale/bitcoin_sk.ts86
-rw-r--r--src/qt/locale/bitcoin_sl_SI.ts4
-rw-r--r--src/qt/locale/bitcoin_sn.ts367
-rw-r--r--src/qt/locale/bitcoin_sv.ts180
-rw-r--r--src/qt/locale/bitcoin_szl.ts2123
-rw-r--r--src/qt/locale/bitcoin_tr.ts88
-rw-r--r--src/qt/locale/bitcoin_tr_TR.ts12
-rw-r--r--src/qt/locale/bitcoin_uk.ts6
-rw-r--r--src/qt/locale/bitcoin_ur_PK.ts60
-rw-r--r--src/qt/locale/bitcoin_vi.ts10
-rw-r--r--src/qt/locale/bitcoin_zh_CN.ts289
-rw-r--r--src/qt/locale/bitcoin_zh_TW.ts10
-rw-r--r--src/qt/modaloverlay.cpp8
-rw-r--r--src/qt/modaloverlay.h1
-rw-r--r--src/qt/optionsdialog.cpp15
-rw-r--r--src/qt/optionsmodel.cpp9
-rw-r--r--src/qt/receivecoinsdialog.cpp9
-rw-r--r--src/qt/rpcconsole.cpp18
-rw-r--r--src/qt/test/addressbooktests.cpp1
-rw-r--r--src/qt/test/paymentservertests.cpp6
-rw-r--r--src/qt/test/wallettests.cpp12
-rw-r--r--src/qt/transactionview.cpp2
-rw-r--r--src/qt/walletcontroller.cpp49
-rw-r--r--src/qt/walletcontroller.h30
-rw-r--r--src/qt/walletmodel.cpp12
-rw-r--r--src/qt/walletmodel.h5
-rw-r--r--src/random.cpp362
-rw-r--r--src/random.h105
-rw-r--r--src/rest.cpp49
-rw-r--r--src/rpc/blockchain.cpp384
-rw-r--r--src/rpc/client.cpp5
-rw-r--r--src/rpc/mining.cpp127
-rw-r--r--src/rpc/mining.h3
-rw-r--r--src/rpc/misc.cpp199
-rw-r--r--src/rpc/net.cpp193
-rw-r--r--src/rpc/rawtransaction.cpp236
-rw-r--r--src/rpc/server.cpp40
-rw-r--r--src/rpc/util.cpp45
-rw-r--r--src/rpc/util.h59
-rw-r--r--src/scheduler.cpp2
-rw-r--r--src/scheduler.h6
-rw-r--r--src/script/descriptor.cpp18
-rw-r--r--src/script/sign.cpp2
-rw-r--r--src/script/sign.h2
-rw-r--r--src/streams.h32
-rw-r--r--src/support/lockedpool.cpp4
-rw-r--r--src/sync.cpp8
-rw-r--r--src/test/bloom_tests.cpp18
-rw-r--r--src/test/coins_tests.cpp2
-rw-r--r--src/test/denialofservice_tests.cpp70
-rw-r--r--src/test/fuzz/fuzz.cpp77
-rw-r--r--src/test/fuzz/fuzz.h17
-rw-r--r--src/test/random_tests.cpp10
-rw-r--r--src/test/test_bitcoin.cpp23
-rw-r--r--src/test/test_bitcoin.h11
-rw-r--r--src/test/test_bitcoin_fuzzy.cpp256
-rw-r--r--src/test/test_bitcoin_main.cpp2
-rw-r--r--src/test/util_tests.cpp5
-rw-r--r--src/txmempool.h3
-rw-r--r--src/util/system.cpp68
-rw-r--r--src/util/system.h4
-rw-r--r--src/util/time.cpp11
-rw-r--r--src/util/time.h1
-rw-r--r--src/validation.cpp21
-rw-r--r--src/validation.h12
-rw-r--r--src/validationinterface.cpp10
-rw-r--r--src/wallet/crypter.cpp6
-rw-r--r--src/wallet/crypter.h2
-rw-r--r--src/wallet/db.cpp55
-rw-r--r--src/wallet/db.h34
-rw-r--r--src/wallet/init.cpp15
-rw-r--r--src/wallet/rpcdump.cpp650
-rw-r--r--src/wallet/rpcwallet.cpp714
-rw-r--r--src/wallet/test/db_tests.cpp72
-rw-r--r--src/wallet/test/wallet_tests.cpp55
-rw-r--r--src/wallet/wallet.cpp362
-rw-r--r--src/wallet/wallet.h92
-rw-r--r--src/wallet/wallettool.cpp138
-rw-r--r--src/wallet/wallettool.h20
-rw-r--r--src/zmq/zmqpublishnotifier.cpp1
-rw-r--r--src/zmq/zmqrpc.cpp14
-rw-r--r--test/README.md23
-rw-r--r--test/functional/README.md36
-rwxr-xr-xtest/functional/example_test.py2
-rwxr-xr-xtest/functional/feature_pruning.py2
-rwxr-xr-xtest/functional/feature_segwit.py4
-rwxr-xr-xtest/functional/interface_rest.py32
-rwxr-xr-xtest/functional/p2p_invalid_messages.py85
-rwxr-xr-xtest/functional/p2p_segwit.py2
-rwxr-xr-xtest/functional/p2p_sendheaders.py2
-rwxr-xr-xtest/functional/rpc_deriveaddresses.py50
-rwxr-xr-xtest/functional/rpc_psbt.py5
-rwxr-xr-xtest/functional/rpc_rawtransaction.py3
-rwxr-xr-xtest/functional/test_framework/mininode.py6
-rwxr-xr-xtest/functional/test_framework/test_framework.py17
-rwxr-xr-xtest/functional/test_framework/test_node.py119
-rwxr-xr-xtest/functional/test_runner.py22
-rwxr-xr-xtest/functional/tool_wallet.py101
-rwxr-xr-xtest/functional/wallet_abandonconflict.py46
-rwxr-xr-xtest/functional/wallet_basic.py54
-rwxr-xr-xtest/functional/wallet_createwallet.py100
-rwxr-xr-xtest/functional/wallet_disableprivatekeys.py35
-rwxr-xr-xtest/functional/wallet_importmulti.py85
-rwxr-xr-xtest/functional/wallet_multiwallet.py8
-rwxr-xr-xtest/lint/check-doc.py4
-rwxr-xr-xtest/lint/lint-python-dead-code.sh2
-rwxr-xr-xtest/lint/lint-python.sh148
-rw-r--r--test/sanitizer_suppressions/ubsan1
253 files changed, 19240 insertions, 3490 deletions
diff --git a/.appveyor.yml b/.appveyor.yml
index 249d0b8df9..31c3aba8c6 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -7,7 +7,7 @@ clone_depth: 5
environment:
APPVEYOR_SAVE_CACHE_ON_ERROR: true
CLCACHE_SERVER: 1
- PACKAGES: boost-filesystem boost-signals2 boost-test libevent openssl zeromq berkeleydb secp256k1 leveldb
+ PACKAGES: boost-filesystem boost-signals2 boost-test libevent openssl zeromq berkeleydb
PATH: 'C:\Python37-x64;C:\Python37-x64\Scripts;%PATH%'
PYTHONUTF8: 1
cache:
@@ -17,6 +17,7 @@ install:
- cmd: pip install --quiet git+https://github.com/frerich/clcache.git@v4.2.0
# Disable zmq test for now since python zmq library on Windows would cause Access violation sometimes.
# - cmd: pip install zmq
+- cmd: vcpkg remove --outdated --recurse
- cmd: vcpkg install --triplet %PLATFORM%-windows-static %PACKAGES% > NUL
- cmd: del /s /q C:\Tools\vcpkg\installed\%PLATFORM%-windows-static\debug # Remove unused debug library
before_build:
@@ -54,5 +55,5 @@ test_script:
- cmd: src\bench_bitcoin.exe -evals=1 -scaling=0 > NUL
- ps: python test\util\bitcoin-util-test.py
- cmd: python test\util\rpcauth-test.py
-- cmd: python test\functional\test_runner.py --ci --force --quiet --combinedlogslen=4000 --failfast
+- cmd: python test\functional\test_runner.py --ci --quiet --combinedlogslen=4000 --failfast
deploy: off
diff --git a/.gitignore b/.gitignore
index 380d2eab98..994d67402f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@ src/bitcoin
src/bitcoind
src/bitcoin-cli
src/bitcoin-tx
+src/bitcoin-wallet
src/test/test_bitcoin
src/test/test_bitcoin_fuzzy
src/qt/test/test_bitcoin-qt
diff --git a/.travis.yml b/.travis.yml
index 6181726fb6..d5086b084a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -32,7 +32,8 @@ install:
before_script:
- set -o errexit; source .travis/test_05_before_script.sh
script:
- - if [ $SECONDS -gt 1200 ]; then set +o errexit; echo "Travis early exit to cache current state"; false; else set -o errexit; source .travis/test_06_script.sh; fi
+ - if [ $SECONDS -gt 1200 ]; then set +o errexit; echo "Travis early exit to cache current state"; false; else set -o errexit; source .travis/test_06_script_a.sh; fi
+ - if [ $SECONDS -gt 1800 ]; then set +o errexit; echo "Travis early exit to cache current state"; false; else set -o errexit; source .travis/test_06_script_b.sh; fi
after_script:
- echo $TRAVIS_COMMIT_RANGE
- echo $TRAVIS_COMMIT_LOG
@@ -65,19 +66,21 @@ jobs:
BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports CXXFLAGS=-Wno-psabi"
- stage: test
- name: 'Win32 [GOAL: deploy] [no gui tests]'
+ name: 'Win32 [GOAL: deploy] [no gui or functional tests]'
env: >-
HOST=i686-w64-mingw32
DPKG_ADD_ARCH="i386"
PACKAGES="python3 nsis g++-mingw-w64-i686 wine-binfmt wine32"
+ RUN_FUNCTIONAL_TESTS=false
GOAL="deploy"
BITCOIN_CONFIG="--enable-reduce-exports --disable-gui-tests"
- stage: test
- name: 'Win64 [GOAL: deploy] [no gui tests]'
+ name: 'Win64 [GOAL: deploy] [no gui or functional tests]'
env: >-
HOST=x86_64-w64-mingw32
PACKAGES="python3 nsis g++-mingw-w64-x86-64 wine-binfmt wine64"
+ RUN_FUNCTIONAL_TESTS=false
GOAL="deploy"
BITCOIN_CONFIG="--enable-reduce-exports --disable-gui-tests"
@@ -97,7 +100,18 @@ jobs:
PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools protobuf-compiler libdbus-1-dev libharfbuzz-dev libprotobuf-dev"
DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1"
GOAL="install"
- BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports --enable-debug CXXFLAGS=\"-g0 -O2\""
+ BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-fuzz --enable-glibc-back-compat --enable-reduce-exports --enable-debug CXXFLAGS=\"-g0 -O2\""
+
+ - stage: test
+ name: 'x86_64 Linux [GOAL: install] [trusty] [no functional tests, no depends, only system libs]'
+ env: >-
+ HOST=x86_64-unknown-linux-gnu
+ DOCKER_NAME_TAG=ubuntu:14.04
+ PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libicu-dev libpng-dev libssl-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev libdb5.1++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev"
+ NO_DEPENDS=1
+ RUN_FUNCTIONAL_TESTS=false
+ GOAL="install"
+ BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=no"
- stage: test
name: 'x86_64 Linux [GOAL: install] [xenial] [no depends, only system libs, sanitizers: thread (TSan), no wallet]'
@@ -115,7 +129,6 @@ jobs:
HOST=x86_64-unknown-linux-gnu
PACKAGES="clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev"
NO_DEPENDS=1
- FUNCTIONAL_TESTS_CONFIG="--exclude wallet_multiwallet.py" # Temporarily suppress ASan heap-use-after-free (see issue #14163)
GOAL="install"
BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS=-DDEBUG_LOCKORDER --with-sanitizers=address,integer,undefined CC=clang CXX=clang++"
@@ -129,7 +142,7 @@ jobs:
BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports"
- stage: test
- name: 'macOS 10.10 [GOAL: deploy]'
+ name: 'macOS 10.10 [GOAL: deploy] [no functional tests]'
env: >-
HOST=x86_64-apple-darwin14
PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev python3-setuptools-git"
diff --git a/.travis/test_06_script.sh b/.travis/test_06_script_a.sh
index 618aa2c3b6..8cc593f936 100755
--- a/.travis/test_06_script.sh
+++ b/.travis/test_06_script_a.sh
@@ -47,18 +47,4 @@ BEGIN_FOLD build
DOCKER_EXEC make $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && DOCKER_EXEC make $GOAL V=1 ; false )
END_FOLD
-if [ "$RUN_UNIT_TESTS" = "true" ]; then
- BEGIN_FOLD unit-tests
- DOCKER_EXEC LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib make $MAKEJOBS check VERBOSE=1
- END_FOLD
-fi
-
-if [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then
- extended="--extended --exclude feature_pruning"
-fi
-
-if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then
- BEGIN_FOLD functional-tests
- DOCKER_EXEC test/functional/test_runner.py --ci --combinedlogslen=4000 --coverage --quiet --failfast ${extended} ${FUNCTIONAL_TESTS_CONFIG}
- END_FOLD
-fi
+cd ${TRAVIS_BUILD_DIR} || (echo "could not enter travis build dir $TRAVIS_BUILD_DIR"; exit 1)
diff --git a/.travis/test_06_script_b.sh b/.travis/test_06_script_b.sh
new file mode 100755
index 0000000000..b6b5925be8
--- /dev/null
+++ b/.travis/test_06_script_b.sh
@@ -0,0 +1,21 @@
+#!/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
+
+cd "build/bitcoin-$HOST" || (echo "could not enter distdir build/bitcoin-$HOST"; exit 1)
+
+if [ "$RUN_UNIT_TESTS" = "true" ]; then
+ BEGIN_FOLD unit-tests
+ DOCKER_EXEC LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib make $MAKEJOBS check VERBOSE=1
+ END_FOLD
+fi
+
+if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then
+ BEGIN_FOLD functional-tests
+ DOCKER_EXEC test/functional/test_runner.py --ci --combinedlogslen=4000 --coverage --quiet --failfast
+ END_FOLD
+fi
diff --git a/.tx/config b/.tx/config
index c0931c0f34..743510a7f2 100644
--- a/.tx/config
+++ b/.tx/config
@@ -1,7 +1,7 @@
[main]
host = https://www.transifex.com
-[bitcoin.qt-translation-017x]
+[bitcoin.qt-translation-018x]
file_filter = src/qt/locale/bitcoin_<lang>.ts
source_file = src/qt/locale/bitcoin_en.ts
source_lang = en
diff --git a/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj b/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj
index b987a337c0..771e8a56f4 100644
--- a/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj
+++ b/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj
@@ -61,6 +61,12 @@
<ProjectReference Include="..\libunivalue\libunivalue.vcxproj">
<Project>{5724ba7d-a09a-4ba8-800b-c4c1561b3d69}</Project>
</ProjectReference>
+ <ProjectReference Include="..\libsecp256k1\libsecp256k1.vcxproj">
+ <Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\libleveldb\libleveldb.vcxproj">
+ <Project>{18430fef-6b61-4c53-b396-718e02850f1b}</Project>
+ </ProjectReference>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
diff --git a/build_msvc/bitcoin-tx/bitcoin-tx.vcxproj b/build_msvc/bitcoin-tx/bitcoin-tx.vcxproj
index a9fae6b739..86fd614990 100644
--- a/build_msvc/bitcoin-tx/bitcoin-tx.vcxproj
+++ b/build_msvc/bitcoin-tx/bitcoin-tx.vcxproj
@@ -38,6 +38,9 @@
<ProjectReference Include="..\libunivalue\libunivalue.vcxproj">
<Project>{5724ba7d-a09a-4ba8-800b-c4c1561b3d69}</Project>
</ProjectReference>
+ <ProjectReference Include="..\libsecp256k1\libsecp256k1.vcxproj">
+ <Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project>
+ </ProjectReference>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
diff --git a/build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj b/build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj
new file mode 100644
index 0000000000..367e68ee51
--- /dev/null
+++ b/build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj
@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Label="configInitTarget" Project="..\common.init.vcxproj" />
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\src\bitcoin-wallet.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\libbitcoinconsensus\libbitcoinconsensus.vcxproj">
+ <Project>{2b384fa8-9ee1-4544-93cb-0d733c25e8ce}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\libbitcoin_cli\libbitcoin_cli.vcxproj">
+ <Project>{0667528c-d734-4009-adf9-c0d6c4a5a5a6}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\libbitcoin_common\libbitcoin_common.vcxproj">
+ <Project>{7c87e378-df58-482e-aa2f-1bc129bc19ce}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\libbitcoin_crypto\libbitcoin_crypto.vcxproj">
+ <Project>{6190199c-6cf4-4dad-bfbd-93fa72a760c1}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\libbitcoin_server\libbitcoin_server.vcxproj">
+ <Project>{460fee33-1fe1-483f-b3bf-931ff8e969a5}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\libbitcoin_util\libbitcoin_util.vcxproj">
+ <Project>{b53a5535-ee9d-4c6f-9a26-f79ee3bc3754}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\libbitcoin_wallet\libbitcoin_wallet.vcxproj">
+ <Project>{93b86837-b543-48a5-a89b-7c87abb77df2}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\libbitcoin_zmq\libbitcoin_zmq.vcxproj">
+ <Project>{792d487f-f14c-49fc-a9de-3fc150f31c3f}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\libunivalue\libunivalue.vcxproj">
+ <Project>{5724ba7d-a09a-4ba8-800b-c4c1561b3d69}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\libbitcoin_wallet_tool\libbitcoin_wallet_tool.vcxproj">
+ <Project>{f91ac55e-6f5e-4c58-9ac5-b40db7deef93}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\libsecp256k1\libsecp256k1.vcxproj">
+ <Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>15.0</VCProjectVersion>
+ <ProjectGuid>{84DE8790-EDE3-4483-81AC-C32F15E861F4}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>bitcointx</RootNamespace>
+ <VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet>
+ <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="Shared">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <Import Label="configTarget" Project="..\common.vcxproj" />
+</Project>
diff --git a/build_msvc/bitcoin.sln b/build_msvc/bitcoin.sln
index 32068d81f6..45bc934d77 100644
--- a/build_msvc/bitcoin.sln
+++ b/build_msvc/bitcoin.sln
@@ -1,4 +1,4 @@
-Microsoft Visual Studio Solution File, Format Version 12.00
+Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2027
MinimumVisualStudioVersion = 10.0.40219.1
@@ -32,6 +32,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bench_bitcoin", "bench_bitc
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bitcoin-tx", "bitcoin-tx\bitcoin-tx.vcxproj", "{D3022AF6-AD33-4CE3-B358-87CB6A1B29CF}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bitcoin-wallet", "bitcoin-wallet\bitcoin-wallet.vcxproj", "{84DE8790-EDE3-4483-81AC-C32F15E861F4}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbitcoin_wallet_tool", "libbitcoin_wallet_tool\libbitcoin_wallet_tool.vcxproj", "{F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsecp256k1", "libsecp256k1\libsecp256k1.vcxproj", "{BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libleveldb", "libleveldb\libleveldb.vcxproj", "{18430FEF-6B61-4C53-B396-718E02850F1B}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -160,6 +168,38 @@ Global
{D3022AF6-AD33-4CE3-B358-87CB6A1B29CF}.Release|x64.Build.0 = Release|x64
{D3022AF6-AD33-4CE3-B358-87CB6A1B29CF}.Release|x86.ActiveCfg = Release|Win32
{D3022AF6-AD33-4CE3-B358-87CB6A1B29CF}.Release|x86.Build.0 = Release|Win32
+ {84DE8790-EDE3-4483-81AC-C32F15E861F4}.Debug|x64.ActiveCfg = Debug|x64
+ {84DE8790-EDE3-4483-81AC-C32F15E861F4}.Debug|x64.Build.0 = Debug|x64
+ {84DE8790-EDE3-4483-81AC-C32F15E861F4}.Debug|x86.ActiveCfg = Debug|Win32
+ {84DE8790-EDE3-4483-81AC-C32F15E861F4}.Debug|x86.Build.0 = Debug|Win32
+ {84DE8790-EDE3-4483-81AC-C32F15E861F4}.Release|x64.ActiveCfg = Release|x64
+ {84DE8790-EDE3-4483-81AC-C32F15E861F4}.Release|x64.Build.0 = Release|x64
+ {84DE8790-EDE3-4483-81AC-C32F15E861F4}.Release|x86.ActiveCfg = Release|Win32
+ {84DE8790-EDE3-4483-81AC-C32F15E861F4}.Release|x86.Build.0 = Release|Win32
+ {F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}.Debug|x64.ActiveCfg = Debug|x64
+ {F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}.Debug|x64.Build.0 = Debug|x64
+ {F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}.Debug|x86.ActiveCfg = Debug|Win32
+ {F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}.Debug|x86.Build.0 = Debug|Win32
+ {F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}.Release|x64.ActiveCfg = Release|x64
+ {F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}.Release|x64.Build.0 = Release|x64
+ {F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}.Release|x86.ActiveCfg = Release|Win32
+ {F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}.Release|x86.Build.0 = Release|Win32
+ {BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}.Debug|x64.ActiveCfg = Debug|x64
+ {BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}.Debug|x64.Build.0 = Debug|x64
+ {BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}.Debug|x86.ActiveCfg = Debug|Win32
+ {BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}.Debug|x86.Build.0 = Debug|Win32
+ {BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}.Release|x64.ActiveCfg = Release|x64
+ {BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}.Release|x64.Build.0 = Release|x64
+ {BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}.Release|x86.ActiveCfg = Release|Win32
+ {BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}.Release|x86.Build.0 = Release|Win32
+ {18430FEF-6B61-4C53-B396-718E02850F1B}.Debug|x64.ActiveCfg = Debug|x64
+ {18430FEF-6B61-4C53-B396-718E02850F1B}.Debug|x64.Build.0 = Debug|x64
+ {18430FEF-6B61-4C53-B396-718E02850F1B}.Debug|x86.ActiveCfg = Debug|Win32
+ {18430FEF-6B61-4C53-B396-718E02850F1B}.Debug|x86.Build.0 = Debug|Win32
+ {18430FEF-6B61-4C53-B396-718E02850F1B}.Release|x64.ActiveCfg = Release|x64
+ {18430FEF-6B61-4C53-B396-718E02850F1B}.Release|x64.Build.0 = Release|x64
+ {18430FEF-6B61-4C53-B396-718E02850F1B}.Release|x86.ActiveCfg = Release|Win32
+ {18430FEF-6B61-4C53-B396-718E02850F1B}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -170,3 +210,4 @@ Global
SolutionGuid = {D0CAE2D0-8DB1-4A0B-80EE-800AA6C64323}
SolutionGuid = {DA7D16A6-E5F0-45B3-B194-C3FE64F1BFCD}
EndGlobalSection
+EndGlobal
diff --git a/build_msvc/bitcoind/bitcoind.vcxproj b/build_msvc/bitcoind/bitcoind.vcxproj
index bb43d9821e..9a071f3bdd 100644
--- a/build_msvc/bitcoind/bitcoind.vcxproj
+++ b/build_msvc/bitcoind/bitcoind.vcxproj
@@ -180,6 +180,12 @@
<ProjectReference Include="..\libunivalue\libunivalue.vcxproj">
<Project>{5724ba7d-a09a-4ba8-800b-c4c1561b3d69}</Project>
</ProjectReference>
+ <ProjectReference Include="..\libsecp256k1\libsecp256k1.vcxproj">
+ <Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\libleveldb\libleveldb.vcxproj">
+ <Project>{18430fef-6b61-4c53-b396-718e02850f1b}</Project>
+ </ProjectReference>
</ItemGroup>
<Import Label="configTarget" Project="..\common.vcxproj" />
</Project>
diff --git a/build_msvc/common.vcxproj b/build_msvc/common.vcxproj
index c7c20622e4..93004dda7c 100644
--- a/build_msvc/common.vcxproj
+++ b/build_msvc/common.vcxproj
@@ -3,20 +3,27 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<PropertyGroup>
<BuildDependsOn>
- CopyConfig;
+ CopyBitcoinConfig;
+ CopySecp256k1Config;
$(BuildDependsOn);
</BuildDependsOn>
</PropertyGroup>
- <Target Name="CopyConfig"
+ <Target Name="CopyBitcoinConfig"
Inputs="$(MSBuildThisFileDirectory)bitcoin_config.h"
Outputs="$(MSBuildThisFileDirectory)..\src\config\bitcoin-config.h">
<Copy SourceFiles="$(MSBuildThisFileDirectory)bitcoin_config.h" DestinationFiles="$(MSBuildThisFileDirectory)..\src\config\bitcoin-config.h" />
</Target>
+ <Target Name="CopySecp256k1Config"
+ Inputs="$(MSBuildThisFileDirectory)libsecp256k1_config.h"
+ Outputs="$(MSBuildThisFileDirectory)..\src\secp256k1\src\libsecp256k1-config.h">
+ <Copy SourceFiles="$(MSBuildThisFileDirectory)libsecp256k1_config.h" DestinationFiles="$(MSBuildThisFileDirectory)..\src\secp256k1\src\libsecp256k1-config.h" />
+ </Target>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>4018;4244;4267;4715;4805;</DisableSpecificWarnings>
<TreatWarningAsError>true</TreatWarningAsError>
+ <PreprocessorDefinitions>_WIN32_WINNT=0x0601;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
</Project>
diff --git a/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in b/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in
index 42145c15ad..b51cdb2991 100644
--- a/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in
+++ b/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in
@@ -91,7 +91,7 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\secp256k1\include;</AdditionalIncludeDirectories>
<SuppressStartupBanner>false</SuppressStartupBanner>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
@@ -109,7 +109,7 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\secp256k1\include;</AdditionalIncludeDirectories>
<SuppressStartupBanner>false</SuppressStartupBanner>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
@@ -129,7 +129,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\secp256k1\include;</AdditionalIncludeDirectories>
<SuppressStartupBanner>false</SuppressStartupBanner>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
@@ -151,7 +151,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\secp256k1\include;</AdditionalIncludeDirectories>
<SuppressStartupBanner>false</SuppressStartupBanner>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
diff --git a/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj b/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj
index 2e8ecb2d2c..43bfb271fb 100644
--- a/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj
+++ b/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj
@@ -61,6 +61,9 @@
<None Include="..\..\src\qt\locale\bitcoin_af_ZA.ts">
<DeploymentContent>true</DeploymentContent>
</None>
+ <None Include="..\..\src\qt\locale\bitcoin_am.ts">
+ <DeploymentContent>true</DeploymentContent>
+ </None>
<None Include="..\..\src\qt\locale\bitcoin_ar.ts">
<DeploymentContent>true</DeploymentContent>
</None>
@@ -73,10 +76,10 @@
<None Include="..\..\src\qt\locale\bitcoin_bg_BG.ts">
<DeploymentContent>true</DeploymentContent>
</None>
- <None Include="..\..\src\qt\locale\bitcoin_ca%40valencia.ts">
+ <None Include="..\..\src\qt\locale\bitcoin_ca.ts">
<DeploymentContent>true</DeploymentContent>
</None>
- <None Include="..\..\src\qt\locale\bitcoin_ca.ts">
+ <None Include="..\..\src\qt\locale\bitcoin_ca%40valencia.ts">
<DeploymentContent>true</DeploymentContent>
</None>
<None Include="..\..\src\qt\locale\bitcoin_ca_ES.ts">
@@ -178,9 +181,15 @@
<None Include="..\..\src\qt\locale\bitcoin_hu.ts">
<DeploymentContent>true</DeploymentContent>
</None>
+ <None Include="..\..\src\qt\locale\bitcoin_id.ts">
+ <DeploymentContent>true</DeploymentContent>
+ </None>
<None Include="..\..\src\qt\locale\bitcoin_id_ID.ts">
<DeploymentContent>true</DeploymentContent>
</None>
+ <None Include="..\..\src\qt\locale\bitcoin_is.ts">
+ <DeploymentContent>true</DeploymentContent>
+ </None>
<None Include="..\..\src\qt\locale\bitcoin_it.ts">
<DeploymentContent>true</DeploymentContent>
</None>
@@ -196,6 +205,9 @@
<None Include="..\..\src\qt\locale\bitcoin_kk_KZ.ts">
<DeploymentContent>true</DeploymentContent>
</None>
+ <None Include="..\..\src\qt\locale\bitcoin_ko.ts">
+ <DeploymentContent>true</DeploymentContent>
+ </None>
<None Include="..\..\src\qt\locale\bitcoin_ko_KR.ts">
<DeploymentContent>true</DeploymentContent>
</None>
@@ -217,6 +229,9 @@
<None Include="..\..\src\qt\locale\bitcoin_mk_MK.ts">
<DeploymentContent>true</DeploymentContent>
</None>
+ <None Include="..\..\src\qt\locale\bitcoin_ml.ts">
+ <DeploymentContent>true</DeploymentContent>
+ </None>
<None Include="..\..\src\qt\locale\bitcoin_mn.ts">
<DeploymentContent>true</DeploymentContent>
</None>
@@ -262,18 +277,24 @@
<None Include="..\..\src\qt\locale\bitcoin_sl_SI.ts">
<DeploymentContent>true</DeploymentContent>
</None>
- <None Include="..\..\src\qt\locale\bitcoin_sq.ts">
+ <None Include="..\..\src\qt\locale\bitcoin_sn.ts">
<DeploymentContent>true</DeploymentContent>
</None>
- <None Include="..\..\src\qt\locale\bitcoin_sr%40latin.ts">
+ <None Include="..\..\src\qt\locale\bitcoin_sq.ts">
<DeploymentContent>true</DeploymentContent>
</None>
<None Include="..\..\src\qt\locale\bitcoin_sr.ts">
<DeploymentContent>true</DeploymentContent>
</None>
+ <None Include="..\..\src\qt\locale\bitcoin_sr%40latin.ts">
+ <DeploymentContent>true</DeploymentContent>
+ </None>
<None Include="..\..\src\qt\locale\bitcoin_sv.ts">
<DeploymentContent>true</DeploymentContent>
</None>
+ <None Include="..\..\src\qt\locale\bitcoin_szl.ts">
+ <DeploymentContent>true</DeploymentContent>
+ </None>
<None Include="..\..\src\qt\locale\bitcoin_ta.ts">
<DeploymentContent>true</DeploymentContent>
</None>
diff --git a/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in b/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in
index e66277123a..acb827bd95 100644
--- a/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in
+++ b/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in
@@ -91,7 +91,7 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\leveldb\include;..\..\src\leveldb\helpers\memenv;</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
@@ -106,7 +106,7 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\leveldb\include;..\..\src\leveldb\helpers\memenv;</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<SuppressStartupBanner>false</SuppressStartupBanner>
</ClCompile>
@@ -124,7 +124,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\leveldb\include;..\..\src\leveldb\helpers\memenv;</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
@@ -143,7 +143,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\leveldb\include;..\..\src\leveldb\helpers\memenv;</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
diff --git a/build_msvc/libbitcoin_wallet_tool/libbitcoin_wallet_tool.vcxproj.in b/build_msvc/libbitcoin_wallet_tool/libbitcoin_wallet_tool.vcxproj.in
new file mode 100644
index 0000000000..b9cf68aee0
--- /dev/null
+++ b/build_msvc/libbitcoin_wallet_tool/libbitcoin_wallet_tool.vcxproj.in
@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Label="configInitTarget" Project="..\common.init.vcxproj" />
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <ItemGroup>
+@SOURCE_FILES@
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="packages.config" />
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>15.0</VCProjectVersion>
+ <ProjectGuid>{F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>libbitcoin_zmq</RootNamespace>
+ <VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet>
+ <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="Shared">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <SuppressStartupBanner>false</SuppressStartupBanner>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <SuppressStartupBanner>false</SuppressStartupBanner>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <SuppressStartupBanner>false</SuppressStartupBanner>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <SuppressStartupBanner>false</SuppressStartupBanner>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <Import Label="configTarget" Project="..\common.vcxproj" />
+</Project>
diff --git a/build_msvc/libbitcoinconsensus/libbitcoinconsensus.vcxproj b/build_msvc/libbitcoinconsensus/libbitcoinconsensus.vcxproj
index 2c6c0a8b7c..961225f9ba 100644
--- a/build_msvc/libbitcoinconsensus/libbitcoinconsensus.vcxproj
+++ b/build_msvc/libbitcoinconsensus/libbitcoinconsensus.vcxproj
@@ -126,7 +126,7 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>false</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\secp256k1\include;</AdditionalIncludeDirectories>
<ExceptionHandling>Sync</ExceptionHandling>
<SuppressStartupBanner>false</SuppressStartupBanner>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@@ -143,7 +143,7 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>false</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\secp256k1\include;</AdditionalIncludeDirectories>
<ExceptionHandling>Sync</ExceptionHandling>
<SuppressStartupBanner>false</SuppressStartupBanner>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@@ -162,7 +162,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>false</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\secp256k1\include;</AdditionalIncludeDirectories>
<ExceptionHandling>Sync</ExceptionHandling>
<SuppressStartupBanner>false</SuppressStartupBanner>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
@@ -183,7 +183,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>false</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\secp256k1\include;</AdditionalIncludeDirectories>
<ExceptionHandling>Sync</ExceptionHandling>
<SuppressStartupBanner>false</SuppressStartupBanner>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
diff --git a/build_msvc/libleveldb/libleveldb.vcxproj b/build_msvc/libleveldb/libleveldb.vcxproj
new file mode 100644
index 0000000000..6de3a2b282
--- /dev/null
+++ b/build_msvc/libleveldb/libleveldb.vcxproj
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Label="configInitTarget" Project="..\common.init.vcxproj" />
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\src\leveldb\db\builder.cc" />
+ <ClCompile Include="..\..\src\leveldb\db\c.cc" />
+ <ClCompile Include="..\..\src\leveldb\db\dbformat.cc" />
+ <ClCompile Include="..\..\src\leveldb\db\db_impl.cc" />
+ <ClCompile Include="..\..\src\leveldb\db\db_iter.cc" />
+ <ClCompile Include="..\..\src\leveldb\db\dumpfile.cc" />
+ <ClCompile Include="..\..\src\leveldb\db\filename.cc" />
+ <ClCompile Include="..\..\src\leveldb\db\log_reader.cc" />
+ <ClCompile Include="..\..\src\leveldb\db\log_writer.cc" />
+ <ClCompile Include="..\..\src\leveldb\db\memtable.cc" />
+ <ClCompile Include="..\..\src\leveldb\db\repair.cc" />
+ <ClCompile Include="..\..\src\leveldb\db\table_cache.cc" />
+ <ClCompile Include="..\..\src\leveldb\db\version_edit.cc" />
+ <ClCompile Include="..\..\src\leveldb\db\version_set.cc" />
+ <ClCompile Include="..\..\src\leveldb\db\write_batch.cc" />
+ <ClCompile Include="..\..\src\leveldb\helpers\memenv\memenv.cc" />
+ <ClCompile Include="..\..\src\leveldb\port\port_posix_sse.cc" />
+ <ClCompile Include="..\..\src\leveldb\port\port_win.cc" />
+ <ClCompile Include="..\..\src\leveldb\table\block.cc" />
+ <ClCompile Include="..\..\src\leveldb\table\block_builder.cc" />
+ <ClCompile Include="..\..\src\leveldb\table\filter_block.cc" />
+ <ClCompile Include="..\..\src\leveldb\table\format.cc" />
+ <ClCompile Include="..\..\src\leveldb\table\iterator.cc" />
+ <ClCompile Include="..\..\src\leveldb\table\merger.cc" />
+ <ClCompile Include="..\..\src\leveldb\table\table.cc" />
+ <ClCompile Include="..\..\src\leveldb\table\table_builder.cc" />
+ <ClCompile Include="..\..\src\leveldb\table\two_level_iterator.cc" />
+ <ClCompile Include="..\..\src\leveldb\util\arena.cc" />
+ <ClCompile Include="..\..\src\leveldb\util\bloom.cc" />
+ <ClCompile Include="..\..\src\leveldb\util\cache.cc" />
+ <ClCompile Include="..\..\src\leveldb\util\coding.cc" />
+ <ClCompile Include="..\..\src\leveldb\util\comparator.cc" />
+ <ClCompile Include="..\..\src\leveldb\util\crc32c.cc" />
+ <ClCompile Include="..\..\src\leveldb\util\env.cc" />
+ <ClCompile Include="..\..\src\leveldb\util\env_win.cc" />
+ <ClCompile Include="..\..\src\leveldb\util\filter_policy.cc" />
+ <ClCompile Include="..\..\src\leveldb\util\hash.cc" />
+ <ClCompile Include="..\..\src\leveldb\util\histogram.cc" />
+ <ClCompile Include="..\..\src\leveldb\util\logging.cc" />
+ <ClCompile Include="..\..\src\leveldb\util\options.cc" />
+ <ClCompile Include="..\..\src\leveldb\util\status.cc" />
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>15.0</VCProjectVersion>
+ <ProjectGuid>{18430FEF-6B61-4C53-B396-718E02850F1B}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>libunivalue</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="Shared">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;LEVELDB_PLATFORM_WINDOWS;LEVELDB_ATOMIC_PRESENT;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <AdditionalIncludeDirectories>..\..\src\leveldb;..\..\src\leveldb\include;</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;LEVELDB_PLATFORM_WINDOWS;LEVELDB_ATOMIC_PRESENT;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <AdditionalIncludeDirectories>..\..\src\leveldb;..\..\src\leveldb\include;</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;LEVELDB_PLATFORM_WINDOWS;LEVELDB_ATOMIC_PRESENT;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <AdditionalIncludeDirectories>..\..\src\leveldb;..\..\src\leveldb\include;</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;LEVELDB_PLATFORM_WINDOWS;LEVELDB_ATOMIC_PRESENT;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <AdditionalIncludeDirectories>..\..\src\leveldb;..\..\src\leveldb\include;</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <Import Label="configTarget" Project="..\common.vcxproj" />
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <TreatWarningAsError>false</TreatWarningAsError>
+ </ClCompile>
+ </ItemDefinitionGroup>
+</Project>
diff --git a/build_msvc/libsecp256k1/libsecp256k1.vcxproj b/build_msvc/libsecp256k1/libsecp256k1.vcxproj
new file mode 100644
index 0000000000..699c7d6871
--- /dev/null
+++ b/build_msvc/libsecp256k1/libsecp256k1.vcxproj
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Label="configInitTarget" Project="..\common.init.vcxproj" />
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\src\secp256k1\src\secp256k1.c" />
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>15.0</VCProjectVersion>
+ <ProjectGuid>{BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>libunivalue</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="Shared">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>ENABLE_MODULE_ECDH;ENABLE_MODULE_RECOVERY;HAVE_CONFIG_H;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <AdditionalIncludeDirectories>..\..\src\secp256k1;</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>ENABLE_MODULE_ECDH;ENABLE_MODULE_RECOVERY;HAVE_CONFIG_H;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <AdditionalIncludeDirectories>..\..\src\secp256k1;</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>ENABLE_MODULE_ECDH;ENABLE_MODULE_RECOVERY;HAVE_CONFIG_H;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <AdditionalIncludeDirectories>..\..\src\secp256k1;</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>ENABLE_MODULE_ECDH;ENABLE_MODULE_RECOVERY;HAVE_CONFIG_H;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <AdditionalIncludeDirectories>..\..\src\secp256k1;</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <Import Label="configTarget" Project="..\common.vcxproj" />
+</Project>
diff --git a/build_msvc/libsecp256k1_config.h b/build_msvc/libsecp256k1_config.h
new file mode 100644
index 0000000000..5187c946a0
--- /dev/null
+++ b/build_msvc/libsecp256k1_config.h
@@ -0,0 +1,29 @@
+/**********************************************************************
+ * Copyright (c) 2013, 2014 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef BITCOIN_LIBSECP256K1_CONFIG_H
+#define BITCOIN_LIBSECP256K1_CONFIG_H
+
+#undef USE_ASM_X86_64
+#undef USE_ENDOMORPHISM
+#undef USE_FIELD_10X26
+#undef USE_FIELD_5X52
+#undef USE_FIELD_INV_BUILTIN
+#undef USE_FIELD_INV_NUM
+#undef USE_NUM_GMP
+#undef USE_NUM_NONE
+#undef USE_SCALAR_4X64
+#undef USE_SCALAR_8X32
+#undef USE_SCALAR_INV_BUILTIN
+#undef USE_SCALAR_INV_NUM
+
+#define USE_NUM_NONE 1
+#define USE_FIELD_INV_BUILTIN 1
+#define USE_SCALAR_INV_BUILTIN 1
+#define USE_FIELD_10X26 1
+#define USE_SCALAR_8X32 1
+
+#endif /* BITCOIN_LIBSECP256K1_CONFIG_H */
diff --git a/build_msvc/msvc-autogen.py b/build_msvc/msvc-autogen.py
index f351532f9d..c8df29eecb 100644
--- a/build_msvc/msvc-autogen.py
+++ b/build_msvc/msvc-autogen.py
@@ -11,6 +11,7 @@ libs = [
'libbitcoin_crypto',
'libbitcoin_server',
'libbitcoin_util',
+ 'libbitcoin_wallet_tool',
'libbitcoin_wallet',
'libbitcoin_zmq',
]
diff --git a/build_msvc/test_bitcoin/test_bitcoin.vcxproj b/build_msvc/test_bitcoin/test_bitcoin.vcxproj
index 2316e473aa..8f39132a22 100644
--- a/build_msvc/test_bitcoin/test_bitcoin.vcxproj
+++ b/build_msvc/test_bitcoin/test_bitcoin.vcxproj
@@ -54,6 +54,12 @@
<ProjectReference Include="..\libunivalue\libunivalue.vcxproj">
<Project>{5724ba7d-a09a-4ba8-800b-c4c1561b3d69}</Project>
</ProjectReference>
+ <ProjectReference Include="..\libsecp256k1\libsecp256k1.vcxproj">
+ <Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\libleveldb\libleveldb.vcxproj">
+ <Project>{18430fef-6b61-4c53-b396-718e02850f1b}</Project>
+ </ProjectReference>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
@@ -127,7 +133,7 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\test;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\leveldb\include;..\..\src\test;</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
@@ -144,7 +150,7 @@
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\test;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\leveldb\include;..\..\src\test;</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
@@ -162,7 +168,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\test;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\leveldb\include;..\..\src\test;</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
@@ -182,7 +188,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\test;</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\leveldb\include;..\..\src\test;</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
diff --git a/build_msvc/testconsensus/testconsensus.vcxproj b/build_msvc/testconsensus/testconsensus.vcxproj
index d73988df1c..db2f8a6216 100644
--- a/build_msvc/testconsensus/testconsensus.vcxproj
+++ b/build_msvc/testconsensus/testconsensus.vcxproj
@@ -168,6 +168,9 @@
<ProjectReference Include="..\libbitcoin_util\libbitcoin_util.vcxproj">
<Project>{b53a5535-ee9d-4c6f-9a26-f79ee3bc3754}</Project>
</ProjectReference>
+ <ProjectReference Include="..\libsecp256k1\libsecp256k1.vcxproj">
+ <Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project>
+ </ProjectReference>
</ItemGroup>
<Import Label="configTarget" Project="..\common.vcxproj" />
</Project>
diff --git a/configure.ac b/configure.ac
index c4b1d63bfe..ddd6c7f8eb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -19,6 +19,7 @@ BITCOIN_DAEMON_NAME=bitcoind
BITCOIN_GUI_NAME=bitcoin-qt
BITCOIN_CLI_NAME=bitcoin-cli
BITCOIN_TX_NAME=bitcoin-tx
+BITCOIN_WALLET_TOOL_NAME=bitcoin-wallet
dnl Unless the user specified ARFLAGS, force it to be cr
AC_ARG_VAR(ARFLAGS, [Flags for the archiver, defaults to <cr> if not set])
@@ -102,7 +103,6 @@ AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"])
AC_ARG_VAR(PYTHONPATH, Augments the default search path for python module files)
-# Enable wallet
AC_ARG_ENABLE([wallet],
[AS_HELP_STRING([--disable-wallet],
[disable wallet (enabled by default)])],
@@ -147,6 +147,11 @@ AC_ARG_ENABLE([extended-functional-tests],
[use_extended_functional_tests=$enableval],
[use_extended_functional_tests=no])
+AC_ARG_ENABLE([fuzz],
+ AS_HELP_STRING([--enable-fuzz],[enable building of fuzz targets (default no)]),
+ [enable_fuzz=$enableval],
+ [enable_fuzz=no])
+
AC_ARG_WITH([qrencode],
[AS_HELP_STRING([--with-qrencode],
[enable QR code support (default is yes if qt is enabled and libqrencode is found)])],
@@ -415,7 +420,7 @@ CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS"
AC_ARG_WITH([utils],
[AS_HELP_STRING([--with-utils],
- [build bitcoin-cli bitcoin-tx (default=yes)])],
+ [build bitcoin-cli bitcoin-tx bitcoin-wallet (default=yes)])],
[build_bitcoin_utils=$withval],
[build_bitcoin_utils=yes])
@@ -431,6 +436,12 @@ AC_ARG_ENABLE([util-tx],
[build_bitcoin_tx=$enableval],
[build_bitcoin_tx=$build_bitcoin_utils])
+AC_ARG_ENABLE([util-wallet],
+ [AS_HELP_STRING([--enable-util-wallet],
+ [build bitcoin-wallet])],
+ [build_bitcoin_wallet=$enableval],
+ [build_bitcoin_wallet=$build_bitcoin_utils])
+
AC_ARG_WITH([libs],
[AS_HELP_STRING([--with-libs],
[build libraries (default=yes)])],
@@ -485,7 +496,7 @@ case $host in
AC_MSG_ERROR("windres not found")
fi
- CPPFLAGS="$CPPFLAGS -D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB"
+ CPPFLAGS="$CPPFLAGS -D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -D_WIN32_WINNT=0x0601"
LEVELDB_TARGET_FLAGS="-DOS_WINDOWS"
if test "x$CXXFLAGS_overridden" = "xno"; then
CXXFLAGS="$CXXFLAGS -w"
@@ -900,7 +911,7 @@ BITCOIN_QT_INIT
dnl sets $bitcoin_enable_qt, $bitcoin_enable_qt_test, $bitcoin_enable_qt_dbus
BITCOIN_QT_CONFIGURE([$use_pkgconfig])
-if test x$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnononononono; then
+if test x$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnonononononono; then
use_boost=no
else
use_boost=yes
@@ -1182,7 +1193,7 @@ dnl univalue check
need_bundled_univalue=yes
-if test x$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnononononono; then
+if test x$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnonononononono; then
need_bundled_univalue=no
else
@@ -1244,6 +1255,10 @@ AC_MSG_CHECKING([whether to build bitcoin-tx])
AM_CONDITIONAL([BUILD_BITCOIN_TX], [test x$build_bitcoin_tx = xyes])
AC_MSG_RESULT($build_bitcoin_tx)
+AC_MSG_CHECKING([whether to build bitcoin-wallet])
+AM_CONDITIONAL([BUILD_BITCOIN_WALLET], [test x$build_bitcoin_wallet = xyes])
+AC_MSG_RESULT($build_bitcoin_wallet)
+
AC_MSG_CHECKING([whether to build libraries])
AM_CONDITIONAL([BUILD_BITCOIN_LIBS], [test x$build_bitcoin_libs = xyes])
if test x$build_bitcoin_libs = xyes; then
@@ -1385,7 +1400,7 @@ else
AC_MSG_RESULT([no])
fi
-if test x$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$use_bench$use_tests = xnonononononono; then
+if test x$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$use_bench$use_tests = xnononononononono; then
AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-libs --with-daemon --with-gui --enable-bench or --enable-tests])
fi
@@ -1394,6 +1409,7 @@ AM_CONDITIONAL([BUILD_DARWIN], [test x$BUILD_OS = xdarwin])
AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows])
AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet = xyes])
AM_CONDITIONAL([ENABLE_TESTS],[test x$BUILD_TEST = xyes])
+AM_CONDITIONAL([ENABLE_FUZZ],[test x$enable_fuzz = xyes])
AM_CONDITIONAL([ENABLE_QT],[test x$bitcoin_enable_qt = xyes])
AM_CONDITIONAL([ENABLE_QT_TESTS],[test x$BUILD_TEST_QT = xyes])
AM_CONDITIONAL([ENABLE_BIP70],[test x$enable_bip70 = xyes])
@@ -1431,6 +1447,7 @@ AC_SUBST(BITCOIN_DAEMON_NAME)
AC_SUBST(BITCOIN_GUI_NAME)
AC_SUBST(BITCOIN_CLI_NAME)
AC_SUBST(BITCOIN_TX_NAME)
+AC_SUBST(BITCOIN_WALLET_TOOL_NAME)
AC_SUBST(RELDFLAGS)
AC_SUBST(DEBUG_CPPFLAGS)
@@ -1536,6 +1553,9 @@ if test x$bitcoin_enable_qt != xno; then
fi
echo " with zmq = $use_zmq"
echo " with test = $use_tests"
+if test x$use_tests != xno; then
+ echo " with fuzz = $enable_fuzz"
+fi
echo " with bench = $use_bench"
echo " with upnp = $use_upnp"
echo " use asm = $use_asm"
diff --git a/contrib/bitcoin-cli.bash-completion b/contrib/bitcoin-cli.bash-completion
index 732981fe7c..f4cac84182 100644
--- a/contrib/bitcoin-cli.bash-completion
+++ b/contrib/bitcoin-cli.bash-completion
@@ -50,7 +50,7 @@ _bitcoin_cli() {
COMPREPLY=( $( compgen -W "true false" -- "$cur" ) )
return 0
;;
- signrawtransaction)
+ signrawtransactionwithkey|signrawtransactionwithwallet)
COMPREPLY=( $( compgen -W "ALL NONE SINGLE ALL|ANYONECANPAY NONE|ANYONECANPAY SINGLE|ANYONECANPAY" -- "$cur" ) )
return 0
;;
diff --git a/contrib/devtools/copyright_header.py b/contrib/devtools/copyright_header.py
index 6d7a592f01..f2987f2260 100755
--- a/contrib/devtools/copyright_header.py
+++ b/contrib/devtools/copyright_header.py
@@ -48,15 +48,22 @@ def applies_to_file(filename):
# obtain list of files in repo according to INCLUDE and EXCLUDE
################################################################################
-GIT_LS_CMD = 'git ls-files'
+GIT_LS_CMD = 'git ls-files --full-name'.split(' ')
+GIT_TOPLEVEL_CMD = 'git rev-parse --show-toplevel'.split(' ')
-def call_git_ls():
- out = subprocess.check_output(GIT_LS_CMD.split(' '))
+def call_git_ls(base_directory):
+ out = subprocess.check_output([*GIT_LS_CMD, base_directory])
return [f for f in out.decode("utf-8").split('\n') if f != '']
-def get_filenames_to_examine():
- filenames = call_git_ls()
- return sorted([filename for filename in filenames if
+def call_git_toplevel():
+ "Returns the absolute path to the project root"
+ return subprocess.check_output(GIT_TOPLEVEL_CMD).strip().decode("utf-8")
+
+def get_filenames_to_examine(base_directory):
+ "Returns an array of absolute paths to any project files in the base_directory that pass the include/exclude filters"
+ root = call_git_toplevel()
+ filenames = call_git_ls(base_directory)
+ return sorted([os.path.join(root, filename) for filename in filenames if
applies_to_file(filename)])
################################################################################
@@ -83,24 +90,12 @@ def compile_copyright_regex(copyright_style, year_style, name):
EXPECTED_HOLDER_NAMES = [
"Satoshi Nakamoto\n",
"The Bitcoin Core developers\n",
- "The Bitcoin Core developers \n",
"Bitcoin Core Developers\n",
- "the Bitcoin Core developers\n",
- "The Bitcoin developers\n",
- "The LevelDB Authors\. All rights reserved\.\n",
"BitPay Inc\.\n",
- "BitPay, Inc\.\n",
"University of Illinois at Urbana-Champaign\.\n",
- "MarcoFalke\n",
"Pieter Wuille\n",
- "Pieter Wuille +\*\n",
- "Pieter Wuille, Gregory Maxwell +\*\n",
- "Pieter Wuille, Andrew Poelstra +\*\n",
- "Andrew Poelstra +\*\n",
"Wladimir J. van der Laan\n",
"Jeff Garzik\n",
- "Diederik Huys, Pieter Wuille +\*\n",
- "Thomas Daede, Cory Fields +\*\n",
"Jan-Klaas Kollhof\n",
"Sam Rushing\n",
"ArtForz -- public domain half-a-node\n",
@@ -146,7 +141,7 @@ def file_has_without_c_style_copyright_for_holder(contents, holder_name):
################################################################################
def read_file(filename):
- return open(os.path.abspath(filename), 'r', encoding="utf8").read()
+ return open(filename, 'r', encoding="utf8").read()
def gather_file_info(filename):
info = {}
@@ -260,12 +255,9 @@ def print_report(file_infos, verbose):
print(SEPARATOR)
def exec_report(base_directory, verbose):
- original_cwd = os.getcwd()
- os.chdir(base_directory)
- filenames = get_filenames_to_examine()
+ filenames = get_filenames_to_examine(base_directory)
file_infos = [gather_file_info(f) for f in filenames]
print_report(file_infos, verbose)
- os.chdir(original_cwd)
################################################################################
# report cmd
@@ -325,13 +317,13 @@ def get_most_recent_git_change_year(filename):
################################################################################
def read_file_lines(filename):
- f = open(os.path.abspath(filename), 'r', encoding="utf8")
+ f = open(filename, 'r', encoding="utf8")
file_lines = f.readlines()
f.close()
return file_lines
def write_file_lines(filename, file_lines):
- f = open(os.path.abspath(filename), 'w', encoding="utf8")
+ f = open(filename, 'w', encoding="utf8")
f.write(''.join(file_lines))
f.close()
@@ -399,11 +391,8 @@ def update_updatable_copyright(filename):
"Copyright updated! -> %s" % last_git_change_year)
def exec_update_header_year(base_directory):
- original_cwd = os.getcwd()
- os.chdir(base_directory)
- for filename in get_filenames_to_examine():
+ for filename in get_filenames_to_examine(base_directory):
update_updatable_copyright(filename)
- os.chdir(original_cwd)
################################################################################
# update cmd
diff --git a/contrib/devtools/gen-manpages.sh b/contrib/devtools/gen-manpages.sh
index b5de5a395f..63b9847100 100755
--- a/contrib/devtools/gen-manpages.sh
+++ b/contrib/devtools/gen-manpages.sh
@@ -10,6 +10,7 @@ MANDIR=${MANDIR:-$TOPDIR/doc/man}
BITCOIND=${BITCOIND:-$BINDIR/bitcoind}
BITCOINCLI=${BITCOINCLI:-$BINDIR/bitcoin-cli}
BITCOINTX=${BITCOINTX:-$BINDIR/bitcoin-tx}
+WALLET_TOOL=${WALLET_TOOL:-$BINDIR/bitcoin-wallet}
BITCOINQT=${BITCOINQT:-$BINDIR/qt/bitcoin-qt}
[ ! -x $BITCOIND ] && echo "$BITCOIND not found or not executable." && exit 1
@@ -23,7 +24,7 @@ BTCVER=($($BITCOINCLI --version | head -n1 | awk -F'[ -]' '{ print $6, $7 }'))
echo "[COPYRIGHT]" > footer.h2m
$BITCOIND --version | sed -n '1!p' >> footer.h2m
-for cmd in $BITCOIND $BITCOINCLI $BITCOINTX $BITCOINQT; do
+for cmd in $BITCOIND $BITCOINCLI $BITCOINTX $WALLET_TOOL $BITCOINQT; do
cmdname="${cmd##*/}"
help2man -N --version-string=${BTCVER[0]} --include=footer.h2m -o ${MANDIR}/${cmdname}.1 ${cmd}
sed -i "s/\\\-${BTCVER[1]}//g" ${MANDIR}/${cmdname}.1
diff --git a/contrib/gitian-keys/keys.txt b/contrib/gitian-keys/keys.txt
index 593fba1d09..80c18aa889 100644
--- a/contrib/gitian-keys/keys.txt
+++ b/contrib/gitian-keys/keys.txt
@@ -9,6 +9,7 @@ BF6273FAEF7CC0BA1F562E50989F6B3048A116B5 Dev Random
9A1689B60D1B3CCE9262307A2F40A9BF167FBA47 Erik Mossberg (erkmos)
D35176BE9264832E4ACA8986BF0792FBE95DC863 fivepiece
01CDF4627A3B88AAE4A571C87588242FBE38D3A8 Gavin Andresen
+D1DBF2C4B96F2DEBF4C16654410108112E7EA81F Hennadii Stepanov (hebasto)
D3CC177286005BB8FF673294C5242A1AB3936517 jl2012
32EE5C4C3FA15CCADB46ABE529D4BCB6416F53EC Jonas Schnelli
4B4E840451149DD7FB0D633477DFAB5C3108B9A8 Jorge Timon
diff --git a/contrib/init/bitcoind.service b/contrib/init/bitcoind.service
index 877abafd19..cfc5f77580 100644
--- a/contrib/init/bitcoind.service
+++ b/contrib/init/bitcoind.service
@@ -5,21 +5,45 @@
# See "man systemd.service" for details.
# Note that almost all daemon options could be specified in
-# /etc/bitcoin/bitcoin.conf
+# /etc/bitcoin/bitcoin.conf, except for those explicitly specified as arguments
+# in ExecStart=
[Unit]
Description=Bitcoin daemon
After=network.target
[Service]
-ExecStart=/usr/bin/bitcoind -daemon -conf=/etc/bitcoin/bitcoin.conf -pid=/run/bitcoind/bitcoind.pid
-# Creates /run/bitcoind owned by bitcoin
-RuntimeDirectory=bitcoind
-User=bitcoin
+ExecStart=/usr/bin/bitcoind -daemon \
+ -pid=/run/bitcoind/bitcoind.pid \
+ -conf=/etc/bitcoin/bitcoin.conf \
+ -datadir=/var/lib/bitcoind
+
+# Process management
+####################
+
Type=forking
PIDFile=/run/bitcoind/bitcoind.pid
Restart=on-failure
+# Directory creation and permissions
+####################################
+
+# Run as bitcoin:bitcoin
+User=bitcoin
+Group=bitcoin
+
+# /run/bitcoind
+RuntimeDirectory=bitcoind
+RuntimeDirectoryMode=0710
+
+# /etc/bitcoin
+ConfigurationDirectory=bitcoin
+ConfigurationDirectoryMode=0710
+
+# /var/lib/bitcoind
+StateDirectory=bitcoind
+StateDirectoryMode=0710
+
# Hardening measures
####################
diff --git a/contrib/linearize/linearize-hashes.py b/contrib/linearize/linearize-hashes.py
index e10b46d831..8529470e09 100755
--- a/contrib/linearize/linearize-hashes.py
+++ b/contrib/linearize/linearize-hashes.py
@@ -7,7 +7,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
-from http.client import HttpConnection
+from http.client import HTTPConnection
import json
import re
import base64
@@ -27,7 +27,7 @@ class BitcoinRPC:
authpair = "%s:%s" % (username, password)
authpair = authpair.encode('utf-8')
self.authhdr = b"Basic " + base64.b64encode(authpair)
- self.conn = HttpConnection(host, port=port, timeout=30)
+ self.conn = HTTPConnection(host, port=port, timeout=30)
def execute(self, obj):
try:
diff --git a/contrib/verify-commits/verify-commits.py b/contrib/verify-commits/verify-commits.py
index b3c8064ec2..6bbed01073 100755
--- a/contrib/verify-commits/verify-commits.py
+++ b/contrib/verify-commits/verify-commits.py
@@ -91,7 +91,7 @@ def main():
no_sha1 = True
prev_commit = ""
initial_commit = current_commit
- branch = subprocess.check_output([GIT, 'show', '-s', '--format=%H', initial_commit], universal_newlines=True, encoding='utf8').splitlines()[0]
+ branch = subprocess.check_output([GIT, 'show', '-s', '--format=%H', initial_commit]).decode('utf8').splitlines()[0]
# Iterate through commits
while True:
@@ -112,7 +112,7 @@ def main():
if prev_commit != "":
print("No parent of {} was signed with a trusted key!".format(prev_commit), file=sys.stderr)
print("Parents are:", file=sys.stderr)
- parents = subprocess.check_output([GIT, 'show', '-s', '--format=format:%P', prev_commit], universal_newlines=True, encoding='utf8').splitlines()[0].split(' ')
+ parents = subprocess.check_output([GIT, 'show', '-s', '--format=format:%P', prev_commit]).decode('utf8').splitlines()[0].split(' ')
for parent in parents:
subprocess.call([GIT, 'show', '-s', parent], stdout=sys.stderr)
else:
@@ -122,25 +122,25 @@ def main():
# Check the Tree-SHA512
if (verify_tree or prev_commit == "") and current_commit not in incorrect_sha512_allowed:
tree_hash = tree_sha512sum(current_commit)
- if ("Tree-SHA512: {}".format(tree_hash)) not in subprocess.check_output([GIT, 'show', '-s', '--format=format:%B', current_commit], universal_newlines=True, encoding='utf8').splitlines():
+ if ("Tree-SHA512: {}".format(tree_hash)) not in subprocess.check_output([GIT, 'show', '-s', '--format=format:%B', current_commit]).decode('utf8').splitlines():
print("Tree-SHA512 did not match for commit " + current_commit, file=sys.stderr)
sys.exit(1)
# Merge commits should only have two parents
- parents = subprocess.check_output([GIT, 'show', '-s', '--format=format:%P', current_commit], universal_newlines=True, encoding='utf8').splitlines()[0].split(' ')
+ parents = subprocess.check_output([GIT, 'show', '-s', '--format=format:%P', current_commit]).decode('utf8').splitlines()[0].split(' ')
if len(parents) > 2:
print("Commit {} is an octopus merge".format(current_commit), file=sys.stderr)
sys.exit(1)
# Check that the merge commit is clean
- commit_time = int(subprocess.check_output([GIT, 'show', '-s', '--format=format:%ct', current_commit], universal_newlines=True, encoding='utf8').splitlines()[0])
+ commit_time = int(subprocess.check_output([GIT, 'show', '-s', '--format=format:%ct', current_commit]).decode('utf8').splitlines()[0])
check_merge = commit_time > time.time() - args.clean_merge * 24 * 60 * 60 # Only check commits in clean_merge days
allow_unclean = current_commit in unclean_merge_allowed
if len(parents) == 2 and check_merge and not allow_unclean:
- current_tree = subprocess.check_output([GIT, 'show', '--format=%T', current_commit], universal_newlines=True, encoding='utf8').splitlines()[0]
+ current_tree = subprocess.check_output([GIT, 'show', '--format=%T', current_commit]).decode('utf8').splitlines()[0]
subprocess.call([GIT, 'checkout', '--force', '--quiet', parents[0]])
subprocess.call([GIT, 'merge', '--no-ff', '--quiet', '--no-gpg-sign', parents[1]], stdout=subprocess.DEVNULL)
- recreated_tree = subprocess.check_output([GIT, 'show', '--format=format:%T', 'HEAD'], universal_newlines=True, encoding='utf8').splitlines()[0]
+ recreated_tree = subprocess.check_output([GIT, 'show', '--format=format:%T', 'HEAD']).decode('utf8').splitlines()[0]
if current_tree != recreated_tree:
print("Merge commit {} is not clean".format(current_commit), file=sys.stderr)
subprocess.call([GIT, 'diff', current_commit])
diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk
index c9068e83a5..dfbc50580c 100644
--- a/depends/packages/zeromq.mk
+++ b/depends/packages/zeromq.mk
@@ -1,8 +1,8 @@
package=zeromq
-$(package)_version=4.2.5
+$(package)_version=4.3.1
$(package)_download_path=https://github.com/zeromq/libzmq/releases/download/v$($(package)_version)/
$(package)_file_name=$(package)-$($(package)_version).tar.gz
-$(package)_sha256_hash=cc9090ba35713d59bb2f7d7965f877036c49c5558ea0c290b0dcc6f2a17e489f
+$(package)_sha256_hash=bcbabe1e2c7d0eec4ed612e10b94b112dd5f06fcefa994a0c79a45d835cd21eb
$(package)_patches=0001-fix-build-with-older-mingw64.patch 0002-disable-pthread_set_name_np.patch
define $(package)_set_vars
diff --git a/doc/JSON-RPC-interface.md b/doc/JSON-RPC-interface.md
index 59df541567..982afd5d56 100644
--- a/doc/JSON-RPC-interface.md
+++ b/doc/JSON-RPC-interface.md
@@ -5,6 +5,85 @@ The headless daemon `bitcoind` has the JSON-RPC API enabled by default, the GUI
option. In the GUI it is possible to execute RPC methods in the Debug Console
Dialog.
+## Security
+
+The RPC interface allows other programs to control Bitcoin Core,
+including the ability to spend funds from your wallets, affect consensus
+verification, read private data, and otherwise perform operations that
+can cause loss of money, data, or privacy. This section suggests how
+you should use and configure Bitcoin Core to reduce the risk that its
+RPC interface will be abused.
+
+- **Securing the executable:** Anyone with physical or remote access to
+ the computer, container, or virtual machine running Bitcoin Core can
+ compromise either the whole program or just the RPC interface. This
+ includes being able to record any passphrases you enter for unlocking
+ your encrypted wallets or changing settings so that your Bitcoin Core
+ program tells you that certain transactions have multiple
+ confirmations even when they aren't part of the best block chain. For
+ this reason, you should not use Bitcoin Core for security sensitive
+ operations on systems you do not exclusively control, such as shared
+ computers or virtual private servers.
+
+- **Securing local network access:** By default, the RPC interface can
+ only be accessed by a client running on the same computer and only
+ after the client provides a valid authentication credential (username
+ and passphrase). Any program on your computer with access to the file
+ system and local network can obtain this level of access.
+ Additionally, other programs on your computer can attempt to provide
+ an RPC interface on the same port as used by Bitcoin Core in order to
+ trick you into revealing your authentication credentials. For this
+ reason, it is important to only use Bitcoin Core for
+ security-sensitive operations on a computer whose other programs you
+ trust.
+
+- **Securing remote network access:** You may optionally allow other
+ computers to remotely control Bitcoin Core by setting the `rpcallowip`
+ and `rpcbind` configuration parameters. These settings are only meant
+ for enabling connections over secure private networks or connections
+ that have been otherwise secured (e.g. using a VPN or port forwarding
+ with SSH or stunnel). **Do not enable RPC connections over the public
+ Internet.** Although Bitcoin Core's RPC interface does use
+ authentication, it does not use encryption, so your login credentials
+ are sent as clear text that can be read by anyone on your network
+ path. Additionally, the RPC interface has not been hardened to
+ withstand arbitrary Internet traffic, so changing the above settings
+ to expose it to the Internet (even using something like a Tor hidden
+ service) could expose you to unconsidered vulnerabilities. See
+ `bitcoind -help` for more information about these settings and other
+ settings described in this document.
+
+ Related, if you use Bitcoin Core inside a Docker container, you may
+ need to expose the RPC port to the host system. The default way to
+ do this in Docker also exposes the port to the public Internet.
+ Instead, expose it only on the host system's localhost, for example:
+ `-p 127.0.0.1:8332:8332`
+
+- **Secure authentication:** By default, Bitcoin Core generates unique
+ login credentials each time it restarts and puts them into a file
+ readable only by the user that started Bitcoin Core, allowing any of
+ that user's RPC clients with read access to the file to login
+ automatically. The file is `.cookie` in the Bitcoin Core
+ configuration directory, and using these credentials is the preferred
+ RPC authentication method. If you need to generate static login
+ credentials for your programs, you can use the script in the
+ `share/rpcauth` directory in the Bitcoin Core source tree. As a final
+ fallback, you can directly use manually-chosen `rpcuser` and
+ `rpcpassword` configuration parameters---but you must ensure that you
+ choose a strong and unique passphrase (and still don't use insecure
+ networks, as mentioned above).
+
+- **Secure string handling:** The RPC interface does not guarantee any
+ escaping of data beyond what's necessary to encode it as JSON,
+ although it does usually provide serialized data using a hex
+ representation of the bytes. If you use RPC data in your programs or
+ provide its data to other programs, you must ensure any problem
+ strings are properly escaped. For example, multiple websites have
+ been manipulated because they displayed decoded hex strings that
+ included HTML `<script>` tags. For this reason, and other
+ non-security reasons, it is recommended to display all serialized data
+ in hex form only.
+
## RPC consistency guarantees
State that can be queried via RPCs is guaranteed to be at least up-to-date with
diff --git a/doc/README_osx.md b/doc/README_osx.md
deleted file mode 100644
index 739e22d634..0000000000
--- a/doc/README_osx.md
+++ /dev/null
@@ -1,97 +0,0 @@
-Deterministic macOS DMG Notes.
-
-Working macOS DMGs are created in Linux by combining a recent clang,
-the Apple binutils (ld, ar, etc) and DMG authoring tools.
-
-Apple uses clang extensively for development and has upstreamed the necessary
-functionality so that a vanilla clang can take advantage. It supports the use
-of -F, -target, -mmacosx-version-min, and --sysroot, which are all necessary
-when building for macOS.
-
-Apple's version of binutils (called cctools) contains lots of functionality
-missing in the FSF's binutils. In addition to extra linker options for
-frameworks and sysroots, several other tools are needed as well such as
-install_name_tool, lipo, and nmedit. These do not build under linux, so they
-have been patched to do so. The work here was used as a starting point:
-[mingwandroid/toolchain4](https://github.com/mingwandroid/toolchain4).
-
-In order to build a working toolchain, the following source packages are needed
-from Apple: cctools, dyld, and ld64.
-
-These tools inject timestamps by default, which produce non-deterministic
-binaries. The ZERO_AR_DATE environment variable is used to disable that.
-
-This version of cctools has been patched to use the current version of clang's
-headers and its libLTO.so rather than those from llvmgcc, as it was
-originally done in toolchain4.
-
-To complicate things further, all builds must target an Apple SDK. These SDKs
-are free to download, but not redistributable.
-To obtain it, register for a developer account, then download the [Xcode 7.3.1 dmg](https://developer.apple.com/devcenter/download.action?path=/Developer_Tools/Xcode_7.3.1/Xcode_7.3.1.dmg).
-
-This file is several gigabytes in size, but only a single directory inside is
-needed:
-```
-Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk
-```
-
-Unfortunately, the usual linux tools (7zip, hpmount, loopback mount) are incapable of opening this file.
-To create a tarball suitable for Gitian input, there are two options:
-
-Using macOS, you can mount the dmg, and then create it with:
-```
- $ hdiutil attach Xcode_7.3.1.dmg
- $ tar -C /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ -czf MacOSX10.11.sdk.tar.gz MacOSX10.11.sdk
-```
-
-Alternatively, you can use 7zip and SleuthKit to extract the files one by one.
-The script contrib/macdeploy/extract-osx-sdk.sh automates this. First ensure
-the dmg file is in the current directory, and then run the script. You may wish
-to delete the intermediate 5.hfs file and MacOSX10.11.sdk (the directory) when
-you've confirmed the extraction succeeded.
-
-```bash
-apt-get install p7zip-full sleuthkit
-contrib/macdeploy/extract-osx-sdk.sh
-rm -rf 5.hfs MacOSX10.11.sdk
-```
-
-The Gitian descriptors build 2 sets of files: Linux tools, then Apple binaries
-which are created using these tools. The build process has been designed to
-avoid including the SDK's files in Gitian's outputs. All interim tarballs are
-fully deterministic and may be freely redistributed.
-
-genisoimage is used to create the initial DMG. It is not deterministic as-is,
-so it has been patched. A system genisoimage will work fine, but it will not
-be deterministic because the file-order will change between invocations.
-The patch can be seen here: [theuni/osx-cross-depends](https://raw.githubusercontent.com/theuni/osx-cross-depends/master/patches/cdrtools/genisoimage.diff).
-No effort was made to fix this cleanly, so it likely leaks memory badly. But
-it's only used for a single invocation, so that's no real concern.
-
-genisoimage cannot compress DMGs, so afterwards, the 'dmg' tool from the
-libdmg-hfsplus project is used to compress it. There are several bugs in this
-tool and its maintainer has seemingly abandoned the project. It has been forked
-and is available (with fixes) here: [theuni/libdmg-hfsplus](https://github.com/theuni/libdmg-hfsplus).
-
-The 'dmg' tool has the ability to create DMGs from scratch as well, but this
-functionality is broken. Only the compression feature is currently used.
-Ideally, the creation could be fixed and genisoimage would no longer be necessary.
-
-Background images and other features can be added to DMG files by inserting a
-.DS_Store before creation. This is generated by the script
-contrib/macdeploy/custom_dsstore.py.
-
-As of OS X 10.9 Mavericks, using an Apple-blessed key to sign binaries is a
-requirement in order to satisfy the new Gatekeeper requirements. Because this
-private key cannot be shared, we'll have to be a bit creative in order for the
-build process to remain somewhat deterministic. Here's how it works:
-
-- Builders use Gitian to create an unsigned release. This outputs an unsigned
- dmg which users may choose to bless and run. It also outputs an unsigned app
- structure in the form of a tarball, which also contains all of the tools
- that have been previously (deterministically) built in order to create a
- final dmg.
-- The Apple keyholder uses this unsigned app to create a detached signature,
- using the script that is also included there. Detached signatures are available from this [repository](https://github.com/bitcoin-core/bitcoin-detached-sigs).
-- Builders feed the unsigned app + detached signature back into Gitian. It
- uses the pre-built tools to recombine the pieces into a deterministic dmg.
diff --git a/doc/REST-interface.md b/doc/REST-interface.md
index 44df698382..d21df36130 100644
--- a/doc/REST-interface.md
+++ b/doc/REST-interface.md
@@ -27,6 +27,7 @@ For full TX query capability, one must enable the transaction index via "txindex
`GET /rest/block/notxdetails/<BLOCK-HASH>.<bin|hex|json>`
Given a block hash: returns a block, in binary, hex-encoded binary or JSON formats.
+Responds with 404 if the block doesn't exist.
The HTTP request and response are both handled entirely in-memory, thus making maximum memory usage at least 2.66MB (1 MB max block, plus hex encoding) per request.
@@ -36,6 +37,12 @@ With the /notxdetails/ option JSON response will only contain the transaction ha
`GET /rest/headers/<COUNT>/<BLOCK-HASH>.<bin|hex|json>`
Given a block hash: returns <COUNT> amount of blockheaders in upward direction.
+Returns empty if the block doesn't exist or it isn't in the active chain.
+
+#### Blockhash by height
+`GET /rest/blockhashbyheight/<HEIGHT>.<bin|hex|json>`
+
+Given a height: returns hash of block in best-block-chain at height provided.
#### Chaininfos
`GET /rest/chaininfo.json`
diff --git a/doc/build-osx.md b/doc/build-osx.md
index c9a59bab83..119896dc67 100644
--- a/doc/build-osx.md
+++ b/doc/build-osx.md
@@ -105,3 +105,103 @@ Notes
* Tested on OS X 10.10 Yosemite through macOS 10.13 High Sierra on 64-bit Intel processors only.
* Building with downloaded Qt binaries is not officially supported. See the notes in [#7714](https://github.com/bitcoin/bitcoin/issues/7714)
+
+Deterministic macOS DMG Notes
+-----------------------------
+
+Working macOS DMGs are created in Linux by combining a recent clang,
+the Apple binutils (ld, ar, etc) and DMG authoring tools.
+
+Apple uses clang extensively for development and has upstreamed the necessary
+functionality so that a vanilla clang can take advantage. It supports the use
+of -F, -target, -mmacosx-version-min, and --sysroot, which are all necessary
+when building for macOS.
+
+Apple's version of binutils (called cctools) contains lots of functionality
+missing in the FSF's binutils. In addition to extra linker options for
+frameworks and sysroots, several other tools are needed as well such as
+install_name_tool, lipo, and nmedit. These do not build under linux, so they
+have been patched to do so. The work here was used as a starting point:
+[mingwandroid/toolchain4](https://github.com/mingwandroid/toolchain4).
+
+In order to build a working toolchain, the following source packages are needed
+from Apple: cctools, dyld, and ld64.
+
+These tools inject timestamps by default, which produce non-deterministic
+binaries. The ZERO_AR_DATE environment variable is used to disable that.
+
+This version of cctools has been patched to use the current version of clang's
+headers and its libLTO.so rather than those from llvmgcc, as it was
+originally done in toolchain4.
+
+To complicate things further, all builds must target an Apple SDK. These SDKs
+are free to download, but not redistributable.
+To obtain it, register for a developer account, then download the [Xcode 7.3.1 dmg](https://developer.apple.com/devcenter/download.action?path=/Developer_Tools/Xcode_7.3.1/Xcode_7.3.1.dmg).
+
+This file is several gigabytes in size, but only a single directory inside is
+needed:
+```
+Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk
+```
+
+Unfortunately, the usual linux tools (7zip, hpmount, loopback mount) are incapable of opening this file.
+To create a tarball suitable for Gitian input, there are two options:
+
+Using macOS, you can mount the dmg, and then create it with:
+```
+ $ hdiutil attach Xcode_7.3.1.dmg
+ $ tar -C /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ -czf MacOSX10.11.sdk.tar.gz MacOSX10.11.sdk
+```
+
+Alternatively, you can use 7zip and SleuthKit to extract the files one by one.
+The script contrib/macdeploy/extract-osx-sdk.sh automates this. First ensure
+the dmg file is in the current directory, and then run the script. You may wish
+to delete the intermediate 5.hfs file and MacOSX10.11.sdk (the directory) when
+you've confirmed the extraction succeeded.
+
+```bash
+apt-get install p7zip-full sleuthkit
+contrib/macdeploy/extract-osx-sdk.sh
+rm -rf 5.hfs MacOSX10.11.sdk
+```
+
+The Gitian descriptors build 2 sets of files: Linux tools, then Apple binaries
+which are created using these tools. The build process has been designed to
+avoid including the SDK's files in Gitian's outputs. All interim tarballs are
+fully deterministic and may be freely redistributed.
+
+genisoimage is used to create the initial DMG. It is not deterministic as-is,
+so it has been patched. A system genisoimage will work fine, but it will not
+be deterministic because the file-order will change between invocations.
+The patch can be seen here: [theuni/osx-cross-depends](https://raw.githubusercontent.com/theuni/osx-cross-depends/master/patches/cdrtools/genisoimage.diff).
+No effort was made to fix this cleanly, so it likely leaks memory badly. But
+it's only used for a single invocation, so that's no real concern.
+
+genisoimage cannot compress DMGs, so afterwards, the 'dmg' tool from the
+libdmg-hfsplus project is used to compress it. There are several bugs in this
+tool and its maintainer has seemingly abandoned the project. It has been forked
+and is available (with fixes) here: [theuni/libdmg-hfsplus](https://github.com/theuni/libdmg-hfsplus).
+
+The 'dmg' tool has the ability to create DMGs from scratch as well, but this
+functionality is broken. Only the compression feature is currently used.
+Ideally, the creation could be fixed and genisoimage would no longer be necessary.
+
+Background images and other features can be added to DMG files by inserting a
+.DS_Store before creation. This is generated by the script
+contrib/macdeploy/custom_dsstore.py.
+
+As of OS X 10.9 Mavericks, using an Apple-blessed key to sign binaries is a
+requirement in order to satisfy the new Gatekeeper requirements. Because this
+private key cannot be shared, we'll have to be a bit creative in order for the
+build process to remain somewhat deterministic. Here's how it works:
+
+- Builders use Gitian to create an unsigned release. This outputs an unsigned
+ dmg which users may choose to bless and run. It also outputs an unsigned app
+ structure in the form of a tarball, which also contains all of the tools
+ that have been previously (deterministically) built in order to create a
+ final dmg.
+- The Apple keyholder uses this unsigned app to create a detached signature,
+ using the script that is also included there. Detached signatures are available from this [repository](https://github.com/bitcoin-core/bitcoin-detached-sigs).
+- Builders feed the unsigned app + detached signature back into Gitian. It
+ uses the pre-built tools to recombine the pieces into a deterministic dmg.
+
diff --git a/doc/dependencies.md b/doc/dependencies.md
index 50dde02fad..b833e9151f 100644
--- a/doc/dependencies.md
+++ b/doc/dependencies.md
@@ -26,5 +26,5 @@ These are the dependencies currently used by Bitcoin Core. You can find instruct
| Qt | [5.9.7](https://download.qt.io/official_releases/qt/) | [5.2](https://github.com/bitcoin/bitcoin/pull/14725) | No | | |
| XCB | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L87) (Linux only) |
| xkbcommon | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L86) (Linux only) |
-| ZeroMQ | [4.2.5](https://github.com/zeromq/libzmq/releases) | 4.0.0 | No | | |
+| ZeroMQ | [4.3.1](https://github.com/zeromq/libzmq/releases) | 4.0.0 | No | | |
| zlib | [1.2.11](https://zlib.net/) | | | | No |
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index e0def4ea27..1deb5d791a 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -17,6 +17,7 @@ Developer Notes
- [DEBUG_LOCKORDER](#debug_lockorder)
- [Valgrind suppressions file](#valgrind-suppressions-file)
- [Compiling for test coverage](#compiling-for-test-coverage)
+ - [Performance profiling with perf](#performance-profiling-with-perf)
- [Locking/mutex usage notes](#lockingmutex-usage-notes)
- [Threads](#threads)
- [Ignoring IDE/editor files](#ignoring-ideeditor-files)
@@ -35,6 +36,7 @@ Developer Notes
- [Subtrees](#subtrees)
- [Git and GitHub tips](#git-and-github-tips)
- [Scripted diffs](#scripted-diffs)
+ - [Release notes](#release-notes)
- [RPC interface guidelines](#rpc-interface-guidelines)
<!-- markdown-toc end -->
@@ -264,6 +266,51 @@ make cov
# A coverage report will now be accessible at `./test_bitcoin.coverage/index.html`.
```
+### Performance profiling with perf
+
+Profiling is a good way to get a precise idea of where time is being spent in
+code. One tool for doing profiling on Linux platforms is called
+[`perf`](http://www.brendangregg.com/perf.html), and has been integrated into
+the functional test framework. Perf can observe a running process and sample
+(at some frequency) where its execution is.
+
+Perf installation is contingent on which kernel version you're running; see
+[this StackExchange
+thread](https://askubuntu.com/questions/50145/how-to-install-perf-monitoring-tool)
+for specific instructions.
+
+Certain kernel parameters may need to be set for perf to be able to inspect the
+running process' stack.
+
+```sh
+$ sudo sysctl -w kernel.perf_event_paranoid=-1
+$ sudo sysctl -w kernel.kptr_restrict=0
+```
+
+Make sure you [understand the security
+trade-offs](https://lwn.net/Articles/420403/) of setting these kernel
+parameters.
+
+To profile a running bitcoind process for 60 seconds, you could use an
+invocation of `perf record` like this:
+
+```sh
+$ perf record \
+ -g --call-graph dwarf --per-thread -F 140 \
+ -p `pgrep bitcoind` -- sleep 60
+```
+
+You could then analyze the results by running
+
+```sh
+perf report --stdio | c++filt | less
+```
+
+or using a graphical tool like [Hotspot](https://github.com/KDAB/hotspot).
+
+See the functional test documentation for how to invoke perf within tests.
+
+
**Sanitizers**
Bitcoin Core can be compiled with various "sanitizers" enabled, which add
@@ -874,6 +921,21 @@ test/lint/commit-script-check.sh origin/master..HEAD
Commit [`bb81e173`](https://github.com/bitcoin/bitcoin/commit/bb81e173) is an example of a scripted-diff.
+Release notes
+-------------
+
+Release notes should be written for any PR that:
+
+- introduces a notable new feature
+- fixes a significant bug
+- changes an API or configuration model
+- makes any other visible change to the end-user experience.
+
+Release notes should be added to a PR-specific release note file at
+`/doc/release-notes-<PR number>.md` to avoid conflicts between multiple PRs.
+All `release-notes*` files are merged into a single
+[/doc/release-notes.md](/doc/release-notes.md) file prior to the release.
+
RPC interface guidelines
--------------------------
diff --git a/doc/fuzzing.md b/doc/fuzzing.md
index 23317e938e..08b73d3b3c 100644
--- a/doc/fuzzing.md
+++ b/doc/fuzzing.md
@@ -1,9 +1,9 @@
Fuzz-testing Bitcoin Core
==========================
-A special test harness `test_bitcoin_fuzzy` is provided to provide an easy
-entry point for fuzzers and the like. In this document we'll describe how to
-use it with AFL and libFuzzer.
+A special test harness in `src/test/fuzz/` is provided for each fuzz target to
+provide an easy entry point for fuzzers and the like. In this document we'll
+describe how to use it with AFL and libFuzzer.
## AFL
@@ -23,10 +23,10 @@ export AFLPATH=$PWD
To build Bitcoin Core using AFL instrumentation (this assumes that the
`AFLPATH` was set as above):
```
-./configure --disable-ccache --disable-shared --enable-tests CC=${AFLPATH}/afl-gcc CXX=${AFLPATH}/afl-g++
+./configure --disable-ccache --disable-shared --enable-tests --enable-fuzz CC=${AFLPATH}/afl-gcc CXX=${AFLPATH}/afl-g++
export AFL_HARDEN=1
cd src/
-make test/test_bitcoin_fuzzy
+make
```
We disable ccache because we don't want to pollute the ccache with instrumented
objects, and similarly don't want to use non-instrumented cached objects linked
@@ -35,7 +35,7 @@ in.
The fuzzing can be sped up significantly (~200x) by using `afl-clang-fast` and
`afl-clang-fast++` in place of `afl-gcc` and `afl-g++` when compiling. When
compiling using `afl-clang-fast`/`afl-clang-fast++` the resulting
-`test_bitcoin_fuzzy` binary will be instrumented in such a way that the AFL
+binary will be instrumented in such a way that the AFL
features "persistent mode" and "deferred forkserver" can be used. See
https://github.com/mcarpenter/afl/tree/master/llvm_mode for details.
@@ -63,7 +63,7 @@ Extract these (or other starting inputs) into the `inputs` directory before star
To start the actual fuzzing use:
```
-$AFLPATH/afl-fuzz -i ${AFLIN} -o ${AFLOUT} -m52 -- test/test_bitcoin_fuzzy
+$AFLPATH/afl-fuzz -i ${AFLIN} -o ${AFLOUT} -m52 -- test/fuzz/fuzz_target_foo
```
You may have to change a few kernel parameters to test optimally - `afl-fuzz`
@@ -77,7 +77,7 @@ found in the `compiler-rt` runtime libraries package).
To build the `test/test_bitcoin_fuzzy` executable run
```
-./configure --disable-ccache --with-sanitizers=fuzzer,address CC=clang CXX=clang++
+./configure --disable-ccache --enable-fuzz --with-sanitizers=fuzzer,address CC=clang CXX=clang++
make
```
diff --git a/doc/init.md b/doc/init.md
index 5778b09d05..a6c9bb94d8 100644
--- a/doc/init.md
+++ b/doc/init.md
@@ -56,7 +56,7 @@ All three configurations assume several paths that might need to be adjusted.
Binary: `/usr/bin/bitcoind`
Configuration file: `/etc/bitcoin/bitcoin.conf`
Data directory: `/var/lib/bitcoind`
-PID file: `/var/run/bitcoind/bitcoind.pid` (OpenRC and Upstart) or `/var/lib/bitcoind/bitcoind.pid` (systemd)
+PID file: `/var/run/bitcoind/bitcoind.pid` (OpenRC and Upstart) or `/run/bitcoind/bitcoind.pid` (systemd)
Lock file: `/var/lock/subsys/bitcoind` (CentOS)
The configuration file, PID directory (if applicable) and data directory
@@ -65,6 +65,22 @@ reasons to make the configuration file and data directory only readable by the
bitcoin user and group. Access to bitcoin-cli and other bitcoind rpc clients
can then be controlled by group membership.
+NOTE: When using the systemd .service file, the creation of the aforementioned
+directories and the setting of their permissions is automatically handled by
+systemd. Directories are given a permission of 710, giving the bitcoin group
+access to files under it _if_ the files themselves give permission to the
+bitcoin group to do so (e.g. when `-sysperms` is specified). This does not allow
+for the listing of files under the directory.
+
+NOTE: It is not currently possible to override `datadir` in
+`/etc/bitcoin/bitcoin.conf` with the current systemd, OpenRC, and Upstart init
+files out-of-the-box. This is because the command line options specified in the
+init files take precedence over the configurations in
+`/etc/bitcoin/bitcoin.conf`. However, some init systems have their own
+configuration mechanisms that would allow for overriding the command line
+options specified in the init files (e.g. setting `BITCOIND_DATADIR` for
+OpenRC).
+
### macOS
Binary: `/usr/local/bin/bitcoind`
diff --git a/doc/man/bitcoin-cli.1 b/doc/man/bitcoin-cli.1
index 553addfa84..95c1d24dff 100644
--- a/doc/man/bitcoin-cli.1
+++ b/doc/man/bitcoin-cli.1
@@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6.
-.TH BITCOIN-CLI "1" "December 2018" "bitcoin-cli v0.17.99.0" "User Commands"
+.TH BITCOIN-CLI "1" "February 2019" "bitcoin-cli v0.17.99.0" "User Commands"
.SH NAME
bitcoin-cli \- manual page for bitcoin-cli v0.17.99.0
.SH SYNOPSIS
@@ -20,7 +20,7 @@ Bitcoin Core RPC client version v0.17.99.0
.HP
\-?
.IP
-This help message
+Print this help message and exit
.HP
\fB\-conf=\fR<file>
.IP
@@ -104,7 +104,7 @@ Chain selection options:
.IP
Use the test chain
.SH COPYRIGHT
-Copyright (C) 2009-2018 The Bitcoin Core developers
+Copyright (C) 2009-2019 The Bitcoin Core developers
Please contribute if you find Bitcoin Core useful. Visit
<https://bitcoincore.org> for further information about the software.
diff --git a/doc/man/bitcoin-qt.1 b/doc/man/bitcoin-qt.1
index 1d87acd3de..052d420608 100644
--- a/doc/man/bitcoin-qt.1
+++ b/doc/man/bitcoin-qt.1
@@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6.
-.TH BITCOIN-QT "1" "December 2018" "bitcoin-qt v0.17.99.0" "User Commands"
+.TH BITCOIN-QT "1" "February 2019" "bitcoin-qt v0.17.99.0" "User Commands"
.SH NAME
bitcoin-qt \- manual page for bitcoin-qt v0.17.99.0
.SH SYNOPSIS
@@ -56,7 +56,7 @@ Specify data directory
.HP
\fB\-dbcache=\fR<n>
.IP
-Set database cache size in megabytes (4 to 16384, default: 450)
+Set database cache size in MiB (4 to 16384, default: 450)
.HP
\fB\-debuglogfile=\fR<file>
.IP
@@ -500,7 +500,7 @@ mining and transaction creation (default: 0.00001)
\fB\-whitelistforcerelay\fR
.IP
Force relay of transactions from whitelisted peers even if they violate
-local relay policy (default: 1)
+local relay policy (default: 0)
.HP
\fB\-whitelistrelay\fR
.IP
@@ -606,7 +606,7 @@ Set SSL root certificates for payment request (default: \fB\-system\-\fR)
.IP
Show splash screen on startup (default: 1)
.SH COPYRIGHT
-Copyright (C) 2009-2018 The Bitcoin Core developers
+Copyright (C) 2009-2019 The Bitcoin Core developers
Please contribute if you find Bitcoin Core useful. Visit
<https://bitcoincore.org> for further information about the software.
diff --git a/doc/man/bitcoin-tx.1 b/doc/man/bitcoin-tx.1
index f16c68ca14..6b6071d9b7 100644
--- a/doc/man/bitcoin-tx.1
+++ b/doc/man/bitcoin-tx.1
@@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6.
-.TH BITCOIN-TX "1" "December 2018" "bitcoin-tx v0.17.99.0" "User Commands"
+.TH BITCOIN-TX "1" "February 2019" "bitcoin-tx v0.17.99.0" "User Commands"
.SH NAME
bitcoin-tx \- manual page for bitcoin-tx v0.17.99.0
.SH SYNOPSIS
@@ -14,7 +14,7 @@ Bitcoin Core bitcoin\-tx utility version v0.17.99.0
.HP
\-?
.IP
-This help message
+Print this help message and exit
.HP
\fB\-create\fR
.IP
@@ -92,7 +92,7 @@ sign=SIGHASH\-FLAGS
.IP
Add zero or more signatures to transaction. This command requires JSON
registers:prevtxs=JSON object, privatekeys=JSON object. See
-signrawtransaction docs for format of sighash flags, JSON
+signrawtransactionwithkey docs for format of sighash flags, JSON
objects.
.PP
Register Commands:
@@ -105,7 +105,7 @@ set=NAME:JSON\-STRING
.IP
Set register NAME to given JSON\-STRING
.SH COPYRIGHT
-Copyright (C) 2009-2018 The Bitcoin Core developers
+Copyright (C) 2009-2019 The Bitcoin Core developers
Please contribute if you find Bitcoin Core useful. Visit
<https://bitcoincore.org> for further information about the software.
diff --git a/doc/man/bitcoin-wallet.1 b/doc/man/bitcoin-wallet.1
new file mode 100644
index 0000000000..1cb8cdebcd
--- /dev/null
+++ b/doc/man/bitcoin-wallet.1
@@ -0,0 +1,67 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6.
+.TH BITCOIN-WALLET "1" "February 2019" "bitcoin-wallet v0.17.99.0" "User Commands"
+.SH NAME
+bitcoin-wallet \- manual page for bitcoin-wallet v0.17.99.0
+.SH DESCRIPTION
+Bitcoin Core bitcoin\-wallet version v0.17.99.0
+.PP
+wallet\-tool is an offline tool for creating and interacting with Bitcoin Core wallet files.
+By default wallet\-tool will act on wallets in the default mainnet wallet directory in the datadir.
+To change the target wallet, use the \fB\-datadir\fR, \fB\-wallet\fR and \fB\-testnet\fR/\-regtest arguments.
+.SS "Usage:"
+.IP
+bitcoin\-wallet [options] <command>
+.SH OPTIONS
+.HP
+\-?
+.IP
+Print this help message and exit
+.HP
+\fB\-datadir=\fR<dir>
+.IP
+Specify data directory
+.HP
+\fB\-wallet=\fR<wallet\-name>
+.IP
+Specify wallet name
+.PP
+Debugging/Testing options:
+.HP
+\fB\-debug=\fR<category>
+.IP
+Output debugging information (default: 0).
+.HP
+\fB\-printtoconsole\fR
+.IP
+Send trace/debug info to console (default: 1 when no \fB\-debug\fR is true, 0
+otherwise.
+.PP
+Chain selection options:
+.HP
+\fB\-testnet\fR
+.IP
+Use the test chain
+.PP
+Commands:
+.IP
+create
+.IP
+Create new wallet file
+.IP
+info
+.IP
+Get wallet info
+.SH COPYRIGHT
+Copyright (C) 2009-2019 The Bitcoin Core developers
+
+Please contribute if you find Bitcoin Core useful. Visit
+<https://bitcoincore.org> for further information about the software.
+The source code is available from <https://github.com/bitcoin/bitcoin>.
+
+This is experimental software.
+Distributed under the MIT software license, see the accompanying file COPYING
+or <https://opensource.org/licenses/MIT>
+
+This product includes software developed by the OpenSSL Project for use in the
+OpenSSL Toolkit <https://www.openssl.org> and cryptographic software written by
+Eric Young and UPnP software written by Thomas Bernard.
diff --git a/doc/man/bitcoind.1 b/doc/man/bitcoind.1
index 5c4b1cd03b..5e057d923f 100644
--- a/doc/man/bitcoind.1
+++ b/doc/man/bitcoind.1
@@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6.
-.TH BITCOIND "1" "December 2018" "bitcoind v0.17.99.0" "User Commands"
+.TH BITCOIND "1" "February 2019" "bitcoind v0.17.99.0" "User Commands"
.SH NAME
bitcoind \- manual page for bitcoind v0.17.99.0
.SH SYNOPSIS
@@ -56,7 +56,7 @@ Specify data directory
.HP
\fB\-dbcache=\fR<n>
.IP
-Set database cache size in megabytes (4 to 16384, default: 450)
+Set database cache size in MiB (4 to 16384, default: 450)
.HP
\fB\-debuglogfile=\fR<file>
.IP
@@ -500,7 +500,7 @@ mining and transaction creation (default: 0.00001)
\fB\-whitelistforcerelay\fR
.IP
Force relay of transactions from whitelisted peers even if they violate
-local relay policy (default: 1)
+local relay policy (default: 0)
.HP
\fB\-whitelistrelay\fR
.IP
@@ -580,7 +580,7 @@ Username for JSON\-RPC connections
.IP
Accept command line and JSON\-RPC commands
.SH COPYRIGHT
-Copyright (C) 2009-2018 The Bitcoin Core developers
+Copyright (C) 2009-2019 The Bitcoin Core developers
Please contribute if you find Bitcoin Core useful. Visit
<https://bitcoincore.org> for further information about the software.
diff --git a/doc/release-notes-14491.md b/doc/release-notes-14491.md
new file mode 100644
index 0000000000..1cf36e85cf
--- /dev/null
+++ b/doc/release-notes-14491.md
@@ -0,0 +1,5 @@
+Descriptor import support
+---------------------
+
+The `importmulti` RPC now supports importing of addresses from descriptors. A "desc" parameter can be provided instead of the "scriptPubKey" in a request, as well as an optional range for ranged descriptors to specify the start and end of the range to import. More information about
+descriptors can be found [here](https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md).
diff --git a/doc/release-notes-14667.md b/doc/release-notes-14667.md
new file mode 100644
index 0000000000..5cb1d0aee7
--- /dev/null
+++ b/doc/release-notes-14667.md
@@ -0,0 +1,4 @@
+New RPC methods
+------------
+
+- `deriveaddresses` returns one or more addresses corresponding to an [output descriptor](/doc/descriptors.md).
diff --git a/doc/release-notes-14941.md b/doc/release-notes-14941.md
deleted file mode 100644
index c3820d0368..0000000000
--- a/doc/release-notes-14941.md
+++ /dev/null
@@ -1,5 +0,0 @@
-Miscellaneous RPC changes
-------------
-
-- The `unloadwallet` RPC is now synchronous, meaning that it blocks until the
- wallet is fully unloaded.
diff --git a/doc/release-notes-14982.md b/doc/release-notes-14982.md
deleted file mode 100644
index 3f0bf8aacd..0000000000
--- a/doc/release-notes-14982.md
+++ /dev/null
@@ -1,5 +0,0 @@
-New RPCs
---------
-
-- The RPC `getrpcinfo` returns runtime details of the RPC server. At the moment
- it returns the active commands and the corresponding execution time.
diff --git a/doc/release-notes-15226.md b/doc/release-notes-15226.md
new file mode 100644
index 0000000000..3be84db3e9
--- /dev/null
+++ b/doc/release-notes-15226.md
@@ -0,0 +1,8 @@
+Miscellaneous RPC changes
+------------
+
+- The RPC `createwallet` now has an optional `blank` argument that can be used to create a blank wallet.
+Blank wallets do not have any keys or HD seed.
+They cannot be opened in software older than 0.18.
+Once a blank wallet has a HD seed set (by using `sethdseed`) or private keys, scripts, addresses, and other watch only things have been imported, the wallet is no longer blank and can be opened in 0.17.x.
+Encrypting a blank wallet will also set a HD seed for it.
diff --git a/doc/release-notes.md b/doc/release-notes.md
index 53b5a2119f..113b8c07d0 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -111,6 +111,15 @@ Configuration option changes
ambiguous whether the hash character is meant for the password or as a
comment.
+- The `whitelistforcerelay` option is used to relay transactions from
+ whitelisted peers even when not accepted to the mempool. This option now
+ defaults to being off, so that changes in policy and disconnect/ban behavior
+ will not cause a node that is whitelisting another to be dropped by peers.
+ Users can still explicitly enable this behavior with the command line option
+ (and may want to consider [contacting](https://bitcoincore.org/en/contact/)
+ the Bitcoin Core project to let us know about their
+ use-case, as this feature could be deprecated in the future).
+
Documentation
-------------
@@ -122,6 +131,10 @@ Documentation
to the [REST interface documentation](https://github.com/bitcoin/bitcoin/blob/master/doc/REST-interface.md)
indicating that the same rules apply.
+- Further information is added to the [JSON-RPC
+ documentation](https://github.com/bitcoin/bitcoin/blob/master/doc/JSON-RPC-interface.md)
+ about how to secure this interface.
+
- A new [document](https://github.com/bitcoin/bitcoin/blob/master/doc/bitcoin-conf.md)
about the `bitcoin.conf` file describes how to use it to configure
Bitcoin Core.
@@ -182,14 +195,18 @@ Deprecated or removed RPCs
New RPCs
--------
-- A new `getnodeaddresses` RPC returns peer addresses known to this
+- The `getnodeaddresses` RPC returns peer addresses known to this
node. It may be used to find nodes to connect to without using a DNS
seeder.
-- A new `listwalletdir` RPC returns a list of wallets in the wallet
+- The `listwalletdir` RPC returns a list of wallets in the wallet
directory (either the default wallet directory or the directory
configured by the `-walletdir` parameter).
+- The `getrpcinfo` returns runtime details of the RPC server. At the
+ moment, it returns an array of the currently active commands and how
+ long they've been running.
+
Updated RPCs
------------
@@ -246,6 +263,22 @@ in the Low-level Changes section below.
- See the [Mining](#mining) section for changes to `getblocktemplate`.
+- The `getrawtransaction` RPC & REST endpoints no longer check the
+ unspent UTXO set for a transaction. The remaining behaviors are as
+ follows: 1. If a blockhash is provided, check the corresponding block.
+ 2. If no blockhash is provided, check the mempool. 3. If no blockhash
+ is provided but txindex is enabled, also check txindex.
+
+- The `unloadwallet` RPC is now synchronous, meaning it will not return
+ until the wallet is fully unloaded.
+
+REST changes
+------------
+
+- A new `/rest/blockhashbyheight/` endpoint is added for fetching the
+ hash of the block in the current best blockchain based on its height
+ (how many blocks it is after the Genesis Block).
+
Graphical User Interface (GUI)
------------------------------
@@ -262,6 +295,22 @@ Graphical User Interface (GUI)
balance shown if the wallet was created using the `createwallet` RPC
and the `disable_private_keys` parameter was set to true.
+- The launch-on-startup option is no longer available on macOS if
+ compiled with macosx min version greater than 10.11 (use
+ CXXFLAGS="-mmacosx-version-min=10.11"
+ CFLAGS="-mmacosx-version-min=10.11" for setting the deployment
+ sdk version)
+
+Tools
+----
+
+- A new `bitcoin-wallet` tool is now distributed alongside Bitcoin
+ Core's other executables. Without needing to use any RPCs, this tool
+ can currently create a new wallet file or display some basic
+ information about an existing wallet, such as whether the wallet is
+ encrypted, whether it uses an HD seed, how many transactions it
+ contains, and how many address book entries it has.
+
Low-level changes
=================
@@ -286,6 +335,32 @@ Configuration
deterministic wallets. This release makes specifying `-usehd` an
invalid configuration option.
+Network
+-------
+
+- This release allows peers that your node automatically disconnected
+ for misbehavior (e.g. sending invalid data) to reconnect to your node
+ if you have unused incoming connection slots. If your slots fill up,
+ a misbehaving node will be disconnected to make room for nodes without
+ a history of problems (unless the misbehaving node helps your node in
+ some other way, such as by connecting to a part of the Internet from
+ which you don't have many other peers). Previously, Bitcoin Core
+ banned the IP addresses of misbehaving peers for a period of time
+ (default of 1 day); this was easily circumvented by attackers with
+ multiple IP addresses. If you manually ban a peer, such as by using
+ the `setban` RPC, all connections from that peer will still be
+ rejected.
+
+Security
+--------
+
+- This release changes the Random Number Generator (RNG) used from
+ OpenSSL to Bitcoin Core's own implementation, although entropy
+ gathered by Bitcoin Core is fed out to OpenSSL and then read back in
+ when the program needs strong randomness. This moves Bitcoin Core a
+ little closer to no longer needing to depend on OpenSSL, a dependency
+ that has caused security issues in the past.
+
Changes for particular platforms
--------------------------------
diff --git a/doc/release-notes/release-notes-pr12255.md b/doc/release-notes/release-notes-pr12255.md
new file mode 100644
index 0000000000..5ac8b44283
--- /dev/null
+++ b/doc/release-notes/release-notes-pr12255.md
@@ -0,0 +1,17 @@
+systemd init file
+=========
+
+The systemd init file (`contrib/init/bitcoind.service`) has been changed to use
+`/var/lib/bitcoind` as the data directory instead of `~bitcoin/.bitcoin`. This
+change makes Bitcoin Core more consistent with other services, and makes the
+systemd init config more consistent with existing Upstart and OpenRC configs.
+
+The configuration, PID, and data directories are now completely managed by
+systemd, which will take care of their creation, permissions, etc. See
+[`systemd.exec (5)`](https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RuntimeDirectory=)
+for more details.
+
+When using the provided init files under `contrib/init`, overriding the
+`datadir` option in `/etc/bitcoin/bitcoin.conf` will have no effect. This is
+because the command line arguments specified in the init files take precedence
+over the options specified in `/etc/bitcoin/bitcoin.conf`.
diff --git a/doc/release-process.md b/doc/release-process.md
index 9fcd5e2298..d20a3dc6b3 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -92,7 +92,7 @@ Ensure gitian-builder is up-to-date:
echo 'f9a8cdb38b9c309326764ebc937cba1523a3a751a7ab05df3ecc99d18ae466c9 inputs/osslsigncode-1.7.1.tar.gz' | sha256sum -c
popd
-Create the macOS SDK tarball, see the [macOS readme](README_osx.md) for details, and copy it into the inputs directory.
+Create the macOS SDK tarball, see the [macOS build instructions](build-osx.md#deterministic-macos-dmg-notes) for details, and copy it into the inputs directory.
### Optional: Seed the Gitian sources cache and offline git repositories
diff --git a/doc/translation_process.md b/doc/translation_process.md
index 19f145e9bf..9692832842 100644
--- a/doc/translation_process.md
+++ b/doc/translation_process.md
@@ -68,11 +68,21 @@ The Transifex Bitcoin project config file is included as part of the repo. It ca
To assist in updating translations, we have created a script to help.
1. `python contrib/devtools/update-translations.py`
-2. Update `src/qt/bitcoin_locale.qrc` manually or via
- `ls src/qt/locale/*ts|xargs -n1 basename|sed 's/\(bitcoin_\(.*\)\).ts/<file alias="\2">locale\/\1.qm<\/file>/'`
-3. Update `src/Makefile.qt.include` manually or via
- `ls src/qt/locale/*ts|xargs -n1 basename|sed 's/\(bitcoin_\(.*\)\).ts/ qt\/locale\/\1.ts \\/'`
-4. `git add` new translations from `src/qt/locale/`
+2. `git add` new translations from `src/qt/locale/`
+3. Update `src/qt/bitcoin_locale.qrc` manually or via
+```bash
+git ls-files src/qt/locale/*ts|xargs -n1 basename|sed 's/\(bitcoin_\(.*\)\).ts/<file alias="\2">locale\/\1.qm<\/file>/'
+```
+4. Update `src/Makefile.qt.include` manually or via
+```bash
+git ls-files src/qt/locale/*ts|xargs -n1 basename|sed 's/\(bitcoin_\(.*\)\).ts/ qt\/locale\/\1.ts \\/'
+```
+5. Update `build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj` or via
+```bash
+git ls-files src/qt/locale/*ts|xargs -n1 basename |
+ sed 's/@/%40/' |
+ sed 's/\(bitcoin_\(.*\)\).ts/ <None Include="..\\..\\src\\qt\\locale\\\1.ts">\n <DeploymentContent>true<\/DeploymentContent>\n <\/None>/'
+```
**Do not directly download translations** one by one from the Transifex website, as we do a few post-processing steps before committing the translations.
diff --git a/doc/translation_strings_policy.md b/doc/translation_strings_policy.md
index 737d11f045..634aca3559 100644
--- a/doc/translation_strings_policy.md
+++ b/doc/translation_strings_policy.md
@@ -33,25 +33,25 @@ General recommendations
Try not to burden translators with translating messages that are e.g. slight variations of other messages.
In the GUI, avoid the use of text where an icon or symbol will do.
-Make sure that placeholder texts in forms don't end up in the list of strings to be translated (use `<string notr="true">`).
+Make sure that placeholder texts in forms do not end up in the list of strings to be translated (use `<string notr="true">`).
### Make translated strings understandable
-Try to write translation strings in an understandable way, for both the user and the translator. Avoid overly technical or detailed messages
+Try to write translation strings in an understandable way, for both the user and the translator. Avoid overly technical or detailed messages.
### Do not translate internal errors
-Do not translate internal errors, or log messages, or messages that appear on the RPC interface. If an error is to be shown to the user,
-use a translatable generic message, then log the detailed message to the log. E.g. "A fatal internal error occurred, see debug.log for details".
+Do not translate internal errors, log messages, or messages that appear on the RPC interface. If an error is to be shown to the user,
+use a translatable generic message, then log the detailed message to the log. E.g., "A fatal internal error occurred, see debug.log for details".
This helps troubleshooting; if the error is the same for everyone, the likelihood is increased that it can be found using a search engine.
### Avoid fragments
-Avoid dividing up a message into fragments. Translators see every string separately, so may misunderstand the context if the messages are not self-contained.
+Avoid dividing up a message into fragments. Translators see every string separately, so they may misunderstand the context if the messages are not self-contained.
### Avoid HTML in translation strings
-There have been difficulties with use of HTML in translation strings; translators should not be able to accidentally affect the formatting of messages.
+There have been difficulties with the use of HTML in translation strings; translators should not be able to accidentally affect the formatting of messages.
This may sometimes be at conflict with the recommendation in the previous section.
### Plurals
@@ -66,7 +66,7 @@ Plurals can be complex in some languages. A quote from the gettext documentation
25-31 pliko'w
and so on
-In Qt code use tr's third argument for optional plurality. For example:
+In Qt code, use tr's third argument for optional plurality. For example:
tr("%n hour(s)","",secs/HOUR_IN_SECONDS);
tr("%n day(s)","",secs/DAY_IN_SECONDS);
@@ -82,7 +82,7 @@ This adds `<numerusform>`s to the respective `.ts` file, which can be translated
</translation>
</message>
-Where it is possible try to avoid embedding numbers into the flow of the string at all. e.g.
+Where possible, try to avoid embedding numbers into the flow of the string at all. E.g.,
WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)
diff --git a/src/Makefile.am b/src/Makefile.am
index 09daaebd23..a57fcb0711 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -41,6 +41,7 @@ LIBBITCOINCONSENSUS=libbitcoinconsensus.la
endif
if ENABLE_WALLET
LIBBITCOIN_WALLET=libbitcoin_wallet.a
+LIBBITCOIN_WALLET_TOOL=libbitcoin_wallet_tool.a
endif
LIBBITCOIN_CRYPTO= $(LIBBITCOIN_CRYPTO_BASE)
@@ -70,6 +71,7 @@ EXTRA_LIBRARIES += \
$(LIBBITCOIN_SERVER) \
$(LIBBITCOIN_CLI) \
$(LIBBITCOIN_WALLET) \
+ $(LIBBITCOIN_WALLET_TOOL) \
$(LIBBITCOIN_ZMQ)
lib_LTLIBRARIES = $(LIBBITCOINCONSENSUS)
@@ -89,6 +91,11 @@ endif
if BUILD_BITCOIN_TX
bin_PROGRAMS += bitcoin-tx
endif
+if ENABLE_WALLET
+if BUILD_BITCOIN_WALLET
+ bin_PROGRAMS += bitcoin-wallet
+endif
+endif
.PHONY: FORCE check-symbols check-security
# bitcoin core #
@@ -96,6 +103,7 @@ BITCOIN_CORE_H = \
addrdb.h \
addrman.h \
attributes.h \
+ banman.h \
base58.h \
bech32.h \
bloom.h \
@@ -145,6 +153,7 @@ BITCOIN_CORE_H = \
netbase.h \
netmessagemaker.h \
noui.h \
+ optional.h \
outputtype.h \
policy/feerate.h \
policy/fees.h \
@@ -203,6 +212,7 @@ BITCOIN_CORE_H = \
wallet/rpcwallet.h \
wallet/wallet.h \
wallet/walletdb.h \
+ wallet/wallettool.h \
wallet/walletutil.h \
wallet/coinselection.h \
warnings.h \
@@ -225,6 +235,7 @@ libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_server_a_SOURCES = \
addrdb.cpp \
addrman.cpp \
+ banman.cpp \
bloom.cpp \
blockencodings.cpp \
blockfilter.cpp \
@@ -305,6 +316,12 @@ libbitcoin_wallet_a_SOURCES = \
wallet/coinselection.cpp \
$(BITCOIN_CORE_H)
+libbitcoin_wallet_tool_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+libbitcoin_wallet_tool_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+libbitcoin_wallet_tool_a_SOURCES = \
+ wallet/wallettool.cpp \
+ $(BITCOIN_CORE_H)
+
# crypto primitives library
crypto_libbitcoin_crypto_base_a_CPPFLAGS = $(AM_CPPFLAGS)
crypto_libbitcoin_crypto_base_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
@@ -522,6 +539,32 @@ bitcoin_tx_LDADD = \
bitcoin_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
#
+# bitcoin-wallet binary #
+bitcoin_wallet_SOURCES = bitcoin-wallet.cpp
+bitcoin_wallet_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+bitcoin_wallet_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+bitcoin_wallet_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+
+if TARGET_WINDOWS
+bitcoin_wallet_SOURCES += bitcoin-wallet-res.rc
+endif
+
+bitcoin_wallet_LDADD = \
+ $(LIBBITCOIN_WALLET_TOOL) \
+ $(LIBBITCOIN_WALLET) \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBLEVELDB) \
+ $(LIBLEVELDB_SSE42) \
+ $(LIBMEMENV) \
+ $(LIBSECP256K1)
+
+bitcoin_wallet_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS)
+#
+
# bitcoinconsensus library #
if BUILD_BITCOIN_LIBS
include_HEADERS = script/bitcoinconsensus.h
diff --git a/src/Makefile.leveldb.include b/src/Makefile.leveldb.include
index 833f3d2a10..bd08bcb4ed 100644
--- a/src/Makefile.leveldb.include
+++ b/src/Makefile.leveldb.include
@@ -24,7 +24,7 @@ LEVELDB_CPPFLAGS_INT += -DLEVELDB_ATOMIC_PRESENT
LEVELDB_CPPFLAGS_INT += -D__STDC_LIMIT_MACROS
if TARGET_WINDOWS
-LEVELDB_CPPFLAGS_INT += -DLEVELDB_PLATFORM_WINDOWS -DWINVER=0x0500 -D__USE_MINGW_ANSI_STDIO=1
+LEVELDB_CPPFLAGS_INT += -DLEVELDB_PLATFORM_WINDOWS -D__USE_MINGW_ANSI_STDIO=1
else
LEVELDB_CPPFLAGS_INT += -DLEVELDB_PLATFORM_POSIX
endif
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 8ce7562434..12112375ea 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -3,7 +3,33 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
bin_PROGRAMS += test/test_bitcoin
-noinst_PROGRAMS += test/test_bitcoin_fuzzy
+
+FUZZ_TARGETS = \
+ test/fuzz/address_deserialize \
+ test/fuzz/addrman_deserialize \
+ test/fuzz/banentry_deserialize \
+ test/fuzz/block_deserialize \
+ test/fuzz/blockheader_deserialize \
+ test/fuzz/blocklocator_deserialize \
+ test/fuzz/blockmerkleroot \
+ test/fuzz/blocktransactions_deserialize \
+ test/fuzz/blocktransactionsrequest_deserialize \
+ test/fuzz/blockundo_deserialize \
+ test/fuzz/bloomfilter_deserialize \
+ test/fuzz/coins_deserialize \
+ test/fuzz/diskblockindex_deserialize \
+ test/fuzz/inv_deserialize \
+ test/fuzz/messageheader_deserialize \
+ test/fuzz/netaddr_deserialize \
+ test/fuzz/service_deserialize \
+ test/fuzz/transaction_deserialize \
+ test/fuzz/txoutcompressor_deserialize \
+ test/fuzz/txundo_deserialize
+
+if ENABLE_FUZZ
+noinst_PROGRAMS += $(FUZZ_TARGETS:=)
+endif
+
TEST_SRCDIR = test
TEST_BINARY=test/test_bitcoin$(EXEEXT)
@@ -27,6 +53,10 @@ BITCOIN_TEST_SUITE = \
test/test_bitcoin.h \
test/test_bitcoin.cpp
+FUZZ_SUITE = \
+ test/fuzz/fuzz.cpp \
+ test/fuzz/fuzz.h
+
# test_bitcoin binary #
BITCOIN_TESTS =\
test/arith_uint256_tests.cpp \
@@ -108,6 +138,7 @@ endif
if ENABLE_WALLET
BITCOIN_TESTS += \
+ wallet/test/db_tests.cpp \
wallet/test/psbt_wallet_tests.cpp \
wallet/test/wallet_tests.cpp \
wallet/test/wallet_crypto_tests.cpp \
@@ -138,28 +169,348 @@ test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -s
if ENABLE_ZMQ
test_test_bitcoin_LDADD += $(ZMQ_LIBS)
endif
-#
-
-# test_bitcoin_fuzzy binary #
-test_test_bitcoin_fuzzy_SOURCES = test/test_bitcoin_fuzzy.cpp
-test_test_bitcoin_fuzzy_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
-test_test_bitcoin_fuzzy_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
-test_test_bitcoin_fuzzy_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-
-test_test_bitcoin_fuzzy_LDADD = \
- $(LIBUNIVALUE) \
- $(LIBBITCOIN_SERVER) \
- $(LIBBITCOIN_COMMON) \
- $(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CONSENSUS) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
- $(LIBBITCOIN_CRYPTO_SHANI) \
- $(LIBSECP256K1)
-
-test_test_bitcoin_fuzzy_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
-#
+
+if ENABLE_FUZZ
+test_fuzz_block_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp
+test_fuzz_block_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCK_DESERIALIZE=1
+test_fuzz_block_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_block_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_block_deserialize_LDADD = \
+ $(LIBUNIVALUE) \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBBITCOIN_CRYPTO_SSE41) \
+ $(LIBBITCOIN_CRYPTO_AVX2) \
+ $(LIBBITCOIN_CRYPTO_SHANI) \
+ $(LIBSECP256K1)
+test_fuzz_block_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+
+test_fuzz_transaction_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp
+test_fuzz_transaction_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DTRANSACTION_DESERIALIZE=1
+test_fuzz_transaction_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_transaction_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_transaction_deserialize_LDADD = \
+ $(LIBUNIVALUE) \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBBITCOIN_CRYPTO_SSE41) \
+ $(LIBBITCOIN_CRYPTO_AVX2) \
+ $(LIBBITCOIN_CRYPTO_SHANI) \
+ $(LIBSECP256K1)
+test_fuzz_transaction_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+
+test_fuzz_blocklocator_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp
+test_fuzz_blocklocator_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKLOCATOR_DESERIALIZE=1
+test_fuzz_blocklocator_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_blocklocator_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_blocklocator_deserialize_LDADD = \
+ $(LIBUNIVALUE) \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBBITCOIN_CRYPTO_SSE41) \
+ $(LIBBITCOIN_CRYPTO_AVX2) \
+ $(LIBBITCOIN_CRYPTO_SHANI) \
+ $(LIBSECP256K1)
+test_fuzz_blocklocator_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+
+test_fuzz_blockmerkleroot_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp
+test_fuzz_blockmerkleroot_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKMERKLEROOT=1
+test_fuzz_blockmerkleroot_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_blockmerkleroot_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_blockmerkleroot_LDADD = \
+ $(LIBUNIVALUE) \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBBITCOIN_CRYPTO_SSE41) \
+ $(LIBBITCOIN_CRYPTO_AVX2) \
+ $(LIBBITCOIN_CRYPTO_SHANI) \
+ $(LIBSECP256K1)
+test_fuzz_blockmerkleroot_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+
+test_fuzz_addrman_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp
+test_fuzz_addrman_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DADDRMAN_DESERIALIZE=1
+test_fuzz_addrman_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_addrman_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_addrman_deserialize_LDADD = \
+ $(LIBUNIVALUE) \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBBITCOIN_CRYPTO_SSE41) \
+ $(LIBBITCOIN_CRYPTO_AVX2) \
+ $(LIBBITCOIN_CRYPTO_SHANI) \
+ $(LIBSECP256K1)
+test_fuzz_addrman_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+
+test_fuzz_blockheader_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp
+test_fuzz_blockheader_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKHEADER_DESERIALIZE=1
+test_fuzz_blockheader_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_blockheader_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_blockheader_deserialize_LDADD = \
+ $(LIBUNIVALUE) \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBBITCOIN_CRYPTO_SSE41) \
+ $(LIBBITCOIN_CRYPTO_AVX2) \
+ $(LIBBITCOIN_CRYPTO_SHANI) \
+ $(LIBSECP256K1)
+test_fuzz_blockheader_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+
+test_fuzz_banentry_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp
+test_fuzz_banentry_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBANENTRY_DESERIALIZE=1
+test_fuzz_banentry_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_banentry_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_banentry_deserialize_LDADD = \
+ $(LIBUNIVALUE) \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBBITCOIN_CRYPTO_SSE41) \
+ $(LIBBITCOIN_CRYPTO_AVX2) \
+ $(LIBBITCOIN_CRYPTO_SHANI) \
+ $(LIBSECP256K1)
+test_fuzz_banentry_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+
+test_fuzz_txundo_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp
+test_fuzz_txundo_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DTXUNDO_DESERIALIZE=1
+test_fuzz_txundo_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_txundo_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_txundo_deserialize_LDADD = \
+ $(LIBUNIVALUE) \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBBITCOIN_CRYPTO_SSE41) \
+ $(LIBBITCOIN_CRYPTO_AVX2) \
+ $(LIBBITCOIN_CRYPTO_SHANI) \
+ $(LIBSECP256K1)
+test_fuzz_txundo_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+
+test_fuzz_blockundo_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp
+test_fuzz_blockundo_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKUNDO_DESERIALIZE=1
+test_fuzz_blockundo_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_blockundo_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_blockundo_deserialize_LDADD = \
+ $(LIBUNIVALUE) \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBBITCOIN_CRYPTO_SSE41) \
+ $(LIBBITCOIN_CRYPTO_AVX2) \
+ $(LIBBITCOIN_CRYPTO_SHANI) \
+ $(LIBSECP256K1)
+test_fuzz_blockundo_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+
+test_fuzz_coins_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp
+test_fuzz_coins_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DCOINS_DESERIALIZE=1
+test_fuzz_coins_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_coins_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_coins_deserialize_LDADD = \
+ $(LIBUNIVALUE) \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBBITCOIN_CRYPTO_SSE41) \
+ $(LIBBITCOIN_CRYPTO_AVX2) \
+ $(LIBBITCOIN_CRYPTO_SHANI) \
+ $(LIBSECP256K1)
+test_fuzz_coins_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+
+test_fuzz_netaddr_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp
+test_fuzz_netaddr_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DNETADDR_DESERIALIZE=1
+test_fuzz_netaddr_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_netaddr_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_netaddr_deserialize_LDADD = \
+ $(LIBUNIVALUE) \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBBITCOIN_CRYPTO_SSE41) \
+ $(LIBBITCOIN_CRYPTO_AVX2) \
+ $(LIBBITCOIN_CRYPTO_SHANI) \
+ $(LIBSECP256K1)
+test_fuzz_netaddr_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+
+test_fuzz_service_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp
+test_fuzz_service_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DSERVICE_DESERIALIZE=1
+test_fuzz_service_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_service_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_service_deserialize_LDADD = \
+ $(LIBUNIVALUE) \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBBITCOIN_CRYPTO_SSE41) \
+ $(LIBBITCOIN_CRYPTO_AVX2) \
+ $(LIBBITCOIN_CRYPTO_SHANI) \
+ $(LIBSECP256K1)
+test_fuzz_service_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+
+test_fuzz_messageheader_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp
+test_fuzz_messageheader_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGEHEADER_DESERIALIZE=1
+test_fuzz_messageheader_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_messageheader_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_messageheader_deserialize_LDADD = \
+ $(LIBUNIVALUE) \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBBITCOIN_CRYPTO_SSE41) \
+ $(LIBBITCOIN_CRYPTO_AVX2) \
+ $(LIBBITCOIN_CRYPTO_SHANI) \
+ $(LIBSECP256K1)
+test_fuzz_messageheader_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+
+test_fuzz_address_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp
+test_fuzz_address_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DADDRESS_DESERIALIZE=1
+test_fuzz_address_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_address_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_address_deserialize_LDADD = \
+ $(LIBUNIVALUE) \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBBITCOIN_CRYPTO_SSE41) \
+ $(LIBBITCOIN_CRYPTO_AVX2) \
+ $(LIBBITCOIN_CRYPTO_SHANI) \
+ $(LIBSECP256K1)
+test_fuzz_address_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+
+test_fuzz_inv_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp
+test_fuzz_inv_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DINV_DESERIALIZE=1
+test_fuzz_inv_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_inv_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_inv_deserialize_LDADD = \
+ $(LIBUNIVALUE) \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBBITCOIN_CRYPTO_SSE41) \
+ $(LIBBITCOIN_CRYPTO_AVX2) \
+ $(LIBBITCOIN_CRYPTO_SHANI) \
+ $(LIBSECP256K1)
+test_fuzz_inv_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+
+test_fuzz_bloomfilter_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp
+test_fuzz_bloomfilter_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOOMFILTER_DESERIALIZE=1
+test_fuzz_bloomfilter_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_bloomfilter_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_bloomfilter_deserialize_LDADD = \
+ $(LIBUNIVALUE) \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBBITCOIN_CRYPTO_SSE41) \
+ $(LIBBITCOIN_CRYPTO_AVX2) \
+ $(LIBBITCOIN_CRYPTO_SHANI) \
+ $(LIBSECP256K1)
+test_fuzz_bloomfilter_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+
+test_fuzz_diskblockindex_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp
+test_fuzz_diskblockindex_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DDISKBLOCKINDEX_DESERIALIZE=1
+test_fuzz_diskblockindex_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_diskblockindex_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_diskblockindex_deserialize_LDADD = \
+ $(LIBUNIVALUE) \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBBITCOIN_CRYPTO_SSE41) \
+ $(LIBBITCOIN_CRYPTO_AVX2) \
+ $(LIBBITCOIN_CRYPTO_SHANI) \
+ $(LIBSECP256K1)
+test_fuzz_diskblockindex_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+
+test_fuzz_txoutcompressor_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp
+test_fuzz_txoutcompressor_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DTXOUTCOMPRESSOR_DESERIALIZE=1
+test_fuzz_txoutcompressor_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_txoutcompressor_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_txoutcompressor_deserialize_LDADD = \
+ $(LIBUNIVALUE) \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBBITCOIN_CRYPTO_SSE41) \
+ $(LIBBITCOIN_CRYPTO_AVX2) \
+ $(LIBBITCOIN_CRYPTO_SHANI) \
+ $(LIBSECP256K1)
+test_fuzz_txoutcompressor_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+
+test_fuzz_blocktransactions_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp
+test_fuzz_blocktransactions_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKTRANSACTIONS_DESERIALIZE=1
+test_fuzz_blocktransactions_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_blocktransactions_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_blocktransactions_deserialize_LDADD = \
+ $(LIBUNIVALUE) \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBBITCOIN_CRYPTO_SSE41) \
+ $(LIBBITCOIN_CRYPTO_AVX2) \
+ $(LIBBITCOIN_CRYPTO_SHANI) \
+ $(LIBSECP256K1)
+test_fuzz_blocktransactions_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+
+test_fuzz_blocktransactionsrequest_deserialize_SOURCES = $(FUZZ_SUITE) test/test_bitcoin_fuzzy.cpp
+test_fuzz_blocktransactionsrequest_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKTRANSACTIONSREQUEST_DESERIALIZE=1
+test_fuzz_blocktransactionsrequest_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_blocktransactionsrequest_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_blocktransactionsrequest_deserialize_LDADD = \
+ $(LIBUNIVALUE) \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBBITCOIN_CRYPTO_SSE41) \
+ $(LIBBITCOIN_CRYPTO_AVX2) \
+ $(LIBBITCOIN_CRYPTO_SHANI) \
+ $(LIBSECP256K1)
+test_fuzz_blocktransactionsrequest_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+endif # ENABLE_FUZZ
nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES)
diff --git a/src/addrdb.cpp b/src/addrdb.cpp
index 1590bce074..c6083f5554 100644
--- a/src/addrdb.cpp
+++ b/src/addrdb.cpp
@@ -105,19 +105,18 @@ bool DeserializeFileDB(const fs::path& path, Data& data)
}
-CBanDB::CBanDB()
+CBanDB::CBanDB(fs::path ban_list_path) : m_ban_list_path(std::move(ban_list_path))
{
- pathBanlist = GetDataDir() / "banlist.dat";
}
bool CBanDB::Write(const banmap_t& banSet)
{
- return SerializeFileDB("banlist", pathBanlist, banSet);
+ return SerializeFileDB("banlist", m_ban_list_path, banSet);
}
bool CBanDB::Read(banmap_t& banSet)
{
- return DeserializeFileDB(pathBanlist, banSet);
+ return DeserializeFileDB(m_ban_list_path, banSet);
}
CAddrDB::CAddrDB()
diff --git a/src/addrdb.h b/src/addrdb.h
index 90eca44bdb..290b63dd12 100644
--- a/src/addrdb.h
+++ b/src/addrdb.h
@@ -43,6 +43,11 @@ public:
nCreateTime = nCreateTimeIn;
}
+ explicit CBanEntry(int64_t n_create_time_in, BanReason ban_reason_in) : CBanEntry(n_create_time_in)
+ {
+ banReason = ban_reason_in;
+ }
+
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
@@ -92,9 +97,9 @@ public:
class CBanDB
{
private:
- fs::path pathBanlist;
+ const fs::path m_ban_list_path;
public:
- CBanDB();
+ explicit CBanDB(fs::path ban_list_path);
bool Write(const banmap_t& banSet);
bool Read(banmap_t& banSet);
};
diff --git a/src/banman.cpp b/src/banman.cpp
new file mode 100644
index 0000000000..47d64a8f31
--- /dev/null
+++ b/src/banman.cpp
@@ -0,0 +1,220 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2017 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <banman.h>
+
+#include <netaddress.h>
+#include <ui_interface.h>
+#include <util/system.h>
+#include <util/time.h>
+
+
+BanMan::BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time)
+ : m_client_interface(client_interface), m_ban_db(std::move(ban_file)), m_default_ban_time(default_ban_time)
+{
+ if (m_client_interface) m_client_interface->InitMessage(_("Loading banlist..."));
+
+ int64_t n_start = GetTimeMillis();
+ m_is_dirty = false;
+ banmap_t banmap;
+ if (m_ban_db.Read(banmap)) {
+ SetBanned(banmap); // thread save setter
+ SetBannedSetDirty(false); // no need to write down, just read data
+ SweepBanned(); // sweep out unused entries
+
+ LogPrint(BCLog::NET, "Loaded %d banned node ips/subnets from banlist.dat %dms\n",
+ banmap.size(), GetTimeMillis() - n_start);
+ } else {
+ LogPrintf("Invalid or missing banlist.dat; recreating\n");
+ SetBannedSetDirty(true); // force write
+ DumpBanlist();
+ }
+}
+
+BanMan::~BanMan()
+{
+ DumpBanlist();
+}
+
+void BanMan::DumpBanlist()
+{
+ SweepBanned(); // clean unused entries (if bantime has expired)
+
+ if (!BannedSetIsDirty()) return;
+
+ int64_t n_start = GetTimeMillis();
+
+ banmap_t banmap;
+ GetBanned(banmap);
+ if (m_ban_db.Write(banmap)) {
+ SetBannedSetDirty(false);
+ }
+
+ LogPrint(BCLog::NET, "Flushed %d banned node ips/subnets to banlist.dat %dms\n",
+ banmap.size(), GetTimeMillis() - n_start);
+}
+
+void BanMan::ClearBanned()
+{
+ {
+ LOCK(m_cs_banned);
+ m_banned.clear();
+ m_is_dirty = true;
+ }
+ DumpBanlist(); //store banlist to disk
+ if (m_client_interface) m_client_interface->BannedListChanged();
+}
+
+int BanMan::IsBannedLevel(CNetAddr net_addr)
+{
+ // Returns the most severe level of banning that applies to this address.
+ // 0 - Not banned
+ // 1 - Automatic misbehavior ban
+ // 2 - Any other ban
+ int level = 0;
+ auto current_time = GetTime();
+ LOCK(m_cs_banned);
+ for (const auto& it : m_banned) {
+ CSubNet sub_net = it.first;
+ CBanEntry ban_entry = it.second;
+
+ if (current_time < ban_entry.nBanUntil && sub_net.Match(net_addr)) {
+ if (ban_entry.banReason != BanReasonNodeMisbehaving) return 2;
+ level = 1;
+ }
+ }
+ return level;
+}
+
+bool BanMan::IsBanned(CNetAddr net_addr)
+{
+ auto current_time = GetTime();
+ LOCK(m_cs_banned);
+ for (const auto& it : m_banned) {
+ CSubNet sub_net = it.first;
+ CBanEntry ban_entry = it.second;
+
+ if (current_time < ban_entry.nBanUntil && sub_net.Match(net_addr)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool BanMan::IsBanned(CSubNet sub_net)
+{
+ auto current_time = GetTime();
+ LOCK(m_cs_banned);
+ banmap_t::iterator i = m_banned.find(sub_net);
+ if (i != m_banned.end()) {
+ CBanEntry ban_entry = (*i).second;
+ if (current_time < ban_entry.nBanUntil) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void BanMan::Ban(const CNetAddr& net_addr, const BanReason& ban_reason, int64_t ban_time_offset, bool since_unix_epoch)
+{
+ CSubNet sub_net(net_addr);
+ Ban(sub_net, ban_reason, ban_time_offset, since_unix_epoch);
+}
+
+void BanMan::Ban(const CSubNet& sub_net, const BanReason& ban_reason, int64_t ban_time_offset, bool since_unix_epoch)
+{
+ CBanEntry ban_entry(GetTime(), ban_reason);
+
+ int64_t normalized_ban_time_offset = ban_time_offset;
+ bool normalized_since_unix_epoch = since_unix_epoch;
+ if (ban_time_offset <= 0) {
+ normalized_ban_time_offset = m_default_ban_time;
+ normalized_since_unix_epoch = false;
+ }
+ ban_entry.nBanUntil = (normalized_since_unix_epoch ? 0 : GetTime()) + normalized_ban_time_offset;
+
+ {
+ LOCK(m_cs_banned);
+ if (m_banned[sub_net].nBanUntil < ban_entry.nBanUntil) {
+ m_banned[sub_net] = ban_entry;
+ m_is_dirty = true;
+ } else
+ return;
+ }
+ if (m_client_interface) m_client_interface->BannedListChanged();
+
+ //store banlist to disk immediately if user requested ban
+ if (ban_reason == BanReasonManuallyAdded) DumpBanlist();
+}
+
+bool BanMan::Unban(const CNetAddr& net_addr)
+{
+ CSubNet sub_net(net_addr);
+ return Unban(sub_net);
+}
+
+bool BanMan::Unban(const CSubNet& sub_net)
+{
+ {
+ LOCK(m_cs_banned);
+ if (m_banned.erase(sub_net) == 0) return false;
+ m_is_dirty = true;
+ }
+ if (m_client_interface) m_client_interface->BannedListChanged();
+ DumpBanlist(); //store banlist to disk immediately
+ return true;
+}
+
+void BanMan::GetBanned(banmap_t& banmap)
+{
+ LOCK(m_cs_banned);
+ // Sweep the banlist so expired bans are not returned
+ SweepBanned();
+ banmap = m_banned; //create a thread safe copy
+}
+
+void BanMan::SetBanned(const banmap_t& banmap)
+{
+ LOCK(m_cs_banned);
+ m_banned = banmap;
+ m_is_dirty = true;
+}
+
+void BanMan::SweepBanned()
+{
+ int64_t now = GetTime();
+ bool notify_ui = false;
+ {
+ LOCK(m_cs_banned);
+ banmap_t::iterator it = m_banned.begin();
+ while (it != m_banned.end()) {
+ CSubNet sub_net = (*it).first;
+ CBanEntry ban_entry = (*it).second;
+ if (now > ban_entry.nBanUntil) {
+ m_banned.erase(it++);
+ m_is_dirty = true;
+ notify_ui = true;
+ LogPrint(BCLog::NET, "%s: Removed banned node ip/subnet from banlist.dat: %s\n", __func__, sub_net.ToString());
+ } else
+ ++it;
+ }
+ }
+ // update UI
+ if (notify_ui && m_client_interface) {
+ m_client_interface->BannedListChanged();
+ }
+}
+
+bool BanMan::BannedSetIsDirty()
+{
+ LOCK(m_cs_banned);
+ return m_is_dirty;
+}
+
+void BanMan::SetBannedSetDirty(bool dirty)
+{
+ LOCK(m_cs_banned); //reuse m_banned lock for the m_is_dirty flag
+ m_is_dirty = dirty;
+}
diff --git a/src/banman.h b/src/banman.h
new file mode 100644
index 0000000000..a1a00309dd
--- /dev/null
+++ b/src/banman.h
@@ -0,0 +1,70 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2017 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#ifndef BITCOIN_BANMAN_H
+#define BITCOIN_BANMAN_H
+
+#include <cstdint>
+#include <memory>
+
+#include <addrdb.h>
+#include <fs.h>
+#include <sync.h>
+
+// NOTE: When adjusting this, update rpcnet:setban's help ("24h")
+static constexpr unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; // Default 24-hour ban
+
+class CClientUIInterface;
+class CNetAddr;
+class CSubNet;
+
+// Denial-of-service detection/prevention
+// The idea is to detect peers that are behaving
+// badly and disconnect/ban them, but do it in a
+// one-coding-mistake-won't-shatter-the-entire-network
+// way.
+// IMPORTANT: There should be nothing I can give a
+// node that it will forward on that will make that
+// node's peers drop it. If there is, an attacker
+// can isolate a node and/or try to split the network.
+// Dropping a node for sending stuff that is invalid
+// now but might be valid in a later version is also
+// dangerous, because it can cause a network split
+// between nodes running old code and nodes running
+// new code.
+
+class BanMan
+{
+public:
+ ~BanMan();
+ BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time);
+ void Ban(const CNetAddr& net_addr, const BanReason& ban_reason, int64_t ban_time_offset = 0, bool since_unix_epoch = false);
+ void Ban(const CSubNet& sub_net, const BanReason& ban_reason, int64_t ban_time_offset = 0, bool since_unix_epoch = false);
+ void ClearBanned();
+ int IsBannedLevel(CNetAddr net_addr);
+ bool IsBanned(CNetAddr net_addr);
+ bool IsBanned(CSubNet sub_net);
+ bool Unban(const CNetAddr& net_addr);
+ bool Unban(const CSubNet& sub_net);
+ void GetBanned(banmap_t& banmap);
+ void DumpBanlist();
+
+private:
+ void SetBanned(const banmap_t& banmap);
+ bool BannedSetIsDirty();
+ //!set the "dirty" flag for the banlist
+ void SetBannedSetDirty(bool dirty = true);
+ //!clean unused entries (if bantime has expired)
+ void SweepBanned();
+
+ CCriticalSection m_cs_banned;
+ banmap_t m_banned GUARDED_BY(m_cs_banned);
+ bool m_is_dirty GUARDED_BY(m_cs_banned);
+ CClientUIInterface* m_client_interface = nullptr;
+ CBanDB m_ban_db;
+ const int64_t m_default_ban_time;
+};
+
+extern std::unique_ptr<BanMan> g_banman;
+#endif
diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp
index 32faba86b4..d67b2c5bc7 100644
--- a/src/bench/bench_bitcoin.cpp
+++ b/src/bench/bench_bitcoin.cpp
@@ -6,7 +6,6 @@
#include <crypto/sha256.h>
#include <key.h>
-#include <random.h>
#include <util/system.h>
#include <util/strencodings.h>
#include <validation.h>
@@ -25,7 +24,8 @@ static const int64_t DEFAULT_PLOT_HEIGHT = 768;
static void SetupBenchArgs()
{
- gArgs.AddArg("-?", "Print this help message and exit", false, OptionsCategory::OPTIONS);
+ SetupHelpOptions(gArgs);
+
gArgs.AddArg("-list", "List benchmarks without executing them. Can be combined with -scaling and -filter", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-evals=<n>", strprintf("Number of measurement evaluations to perform. (default: %u)", DEFAULT_BENCH_EVALUATIONS), false, OptionsCategory::OPTIONS);
gArgs.AddArg("-filter=<regex>", strprintf("Regular expression filter to select benchmark by name (default: %s)", DEFAULT_BENCH_FILTER), false, OptionsCategory::OPTIONS);
@@ -34,10 +34,6 @@ static void SetupBenchArgs()
gArgs.AddArg("-plot-plotlyurl=<uri>", strprintf("URL to use for plotly.js (default: %s)", DEFAULT_PLOT_PLOTLYURL), false, OptionsCategory::OPTIONS);
gArgs.AddArg("-plot-width=<x>", strprintf("Plot width in pixel (default: %u)", DEFAULT_PLOT_WIDTH), false, OptionsCategory::OPTIONS);
gArgs.AddArg("-plot-height=<x>", strprintf("Plot height in pixel (default: %u)", DEFAULT_PLOT_HEIGHT), false, OptionsCategory::OPTIONS);
-
- // Hidden
- gArgs.AddArg("-h", "", false, OptionsCategory::HIDDEN);
- gArgs.AddArg("-help", "", false, OptionsCategory::HIDDEN);
}
static fs::path SetDataDir()
@@ -67,7 +63,6 @@ int main(int argc, char** argv)
const fs::path bench_datadir{SetDataDir()};
SHA256AutoDetect();
- RandomInit();
ECC_Start();
SetupEnvironment();
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 7cdf61ad35..b0e1f67d93 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -34,11 +34,12 @@ static const int CONTINUE_EXECUTION=-1;
static void SetupCliArgs()
{
+ SetupHelpOptions(gArgs);
+
const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN);
const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET);
const auto regtestBaseParams = CreateBaseChainParams(CBaseChainParams::REGTEST);
- gArgs.AddArg("-?", "This help message", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-version", "Print version and exit", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-conf=<file>", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), false, OptionsCategory::OPTIONS);
gArgs.AddArg("-datadir=<dir>", "Specify data directory", false, OptionsCategory::OPTIONS);
@@ -55,10 +56,6 @@ static void SetupCliArgs()
gArgs.AddArg("-rpcwallet=<walletname>", "Send RPC for non-default wallet on RPC server (needs to exactly match corresponding -wallet option passed to bitcoind). This changes the RPC endpoint used, e.g. http://127.0.0.1:8332/wallet/<walletname>", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-stdin", "Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases). When combined with -stdinrpcpass, the first line from standard input is used for the RPC password.", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-stdinrpcpass", "Read RPC password from standard input as a single line. When combined with -stdin, the first line from standard input is used for the RPC password.", false, OptionsCategory::OPTIONS);
-
- // Hidden
- gArgs.AddArg("-h", "", false, OptionsCategory::HIDDEN);
- gArgs.AddArg("-help", "", false, OptionsCategory::HIDDEN);
}
/** libevent event log callback */
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 2e41adc276..4be89aab6c 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -35,7 +35,8 @@ const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
static void SetupBitcoinTxArgs()
{
- gArgs.AddArg("-?", "This help message", false, OptionsCategory::OPTIONS);
+ SetupHelpOptions(gArgs);
+
gArgs.AddArg("-create", "Create new, empty TX.", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-json", "Select JSON output", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-txid", "Output only the hex-encoded transaction id of the resultant transaction.", false, OptionsCategory::OPTIONS);
@@ -62,14 +63,10 @@ static void SetupBitcoinTxArgs()
"This command requires JSON registers:"
"prevtxs=JSON object, "
"privatekeys=JSON object. "
- "See signrawtransaction docs for format of sighash flags, JSON objects.", false, OptionsCategory::COMMANDS);
+ "See signrawtransactionwithkey docs for format of sighash flags, JSON objects.", false, OptionsCategory::COMMANDS);
gArgs.AddArg("load=NAME:FILENAME", "Load JSON file FILENAME into register NAME", false, OptionsCategory::REGISTER_COMMANDS);
gArgs.AddArg("set=NAME:JSON-STRING", "Set register NAME to given JSON-STRING", false, OptionsCategory::REGISTER_COMMANDS);
-
- // Hidden
- gArgs.AddArg("-h", "", false, OptionsCategory::HIDDEN);
- gArgs.AddArg("-help", "", false, OptionsCategory::HIDDEN);
}
//
@@ -818,7 +815,7 @@ static int CommandLineRawTx(int argc, char* argv[])
MutateTx(tx, key, value);
}
- OutputTx(tx);
+ OutputTx(CTransaction(tx));
}
catch (const std::exception& e) {
strPrint = std::string("error: ") + e.what();
diff --git a/src/bitcoin-wallet-res.rc b/src/bitcoin-wallet-res.rc
new file mode 100644
index 0000000000..e9fa2dbb40
--- /dev/null
+++ b/src/bitcoin-wallet-res.rc
@@ -0,0 +1,35 @@
+#include <windows.h> // needed for VERSIONINFO
+#include "clientversion.h" // holds the needed client version information
+
+#define VER_PRODUCTVERSION CLIENT_VERSION_MAJOR,CLIENT_VERSION_MINOR,CLIENT_VERSION_REVISION,CLIENT_VERSION_BUILD
+#define VER_PRODUCTVERSION_STR STRINGIZE(CLIENT_VERSION_MAJOR) "." STRINGIZE(CLIENT_VERSION_MINOR) "." STRINGIZE(CLIENT_VERSION_REVISION) "." STRINGIZE(CLIENT_VERSION_BUILD)
+#define VER_FILEVERSION VER_PRODUCTVERSION
+#define VER_FILEVERSION_STR VER_PRODUCTVERSION_STR
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION VER_FILEVERSION
+PRODUCTVERSION VER_PRODUCTVERSION
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_APP
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4" // U.S. English - multilingual (hex)
+ BEGIN
+ VALUE "CompanyName", "Bitcoin"
+ VALUE "FileDescription", "bitcoin-wallet (CLI tool for " PACKAGE_NAME " wallets)"
+ VALUE "FileVersion", VER_FILEVERSION_STR
+ VALUE "InternalName", "bitcoin-wallet"
+ VALUE "LegalCopyright", COPYRIGHT_STR
+ VALUE "LegalTrademarks1", "Distributed under the MIT software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php."
+ VALUE "OriginalFilename", "bitcoin-wallet.exe"
+ VALUE "ProductName", "bitcoin-wallet"
+ VALUE "ProductVersion", VER_PRODUCTVERSION_STR
+ END
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0, 1252 // language neutral - multilingual (decimal)
+ END
+END
diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp
new file mode 100644
index 0000000000..32a539aac6
--- /dev/null
+++ b/src/bitcoin-wallet.cpp
@@ -0,0 +1,117 @@
+// Copyright (c) 2016-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.
+
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
+
+#include <chainparams.h>
+#include <chainparamsbase.h>
+#include <consensus/consensus.h>
+#include <logging.h>
+#include <util/system.h>
+#include <util/strencodings.h>
+#include <wallet/wallettool.h>
+
+#include <stdio.h>
+
+const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
+
+static void SetupWalletToolArgs()
+{
+ SetupHelpOptions(gArgs);
+ SetupChainParamsBaseOptions();
+
+ gArgs.AddArg("-datadir=<dir>", "Specify data directory", false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-wallet=<wallet-name>", "Specify wallet name", false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-debug=<category>", "Output debugging information (default: 0).", false, OptionsCategory::DEBUG_TEST);
+ gArgs.AddArg("-printtoconsole", "Send trace/debug info to console (default: 1 when no -debug is true, 0 otherwise.", false, OptionsCategory::DEBUG_TEST);
+
+ gArgs.AddArg("info", "Get wallet info", false, OptionsCategory::COMMANDS);
+ gArgs.AddArg("create", "Create new wallet file", false, OptionsCategory::COMMANDS);
+}
+
+static bool WalletAppInit(int argc, char* argv[])
+{
+ SetupWalletToolArgs();
+ std::string error_message;
+ if (!gArgs.ParseParameters(argc, argv, error_message)) {
+ fprintf(stderr, "Error parsing command line arguments: %s\n", error_message.c_str());
+ return false;
+ }
+ if (argc < 2 || HelpRequested(gArgs)) {
+ std::string usage = strprintf("%s bitcoin-wallet version", PACKAGE_NAME) + " " + FormatFullVersion() + "\n\n" +
+ "wallet-tool is an offline tool for creating and interacting with Bitcoin Core wallet files.\n" +
+ "By default wallet-tool will act on wallets in the default mainnet wallet directory in the datadir.\n" +
+ "To change the target wallet, use the -datadir, -wallet and -testnet/-regtest arguments.\n\n" +
+ "Usage:\n" +
+ " bitcoin-wallet [options] <command>\n\n" +
+ gArgs.GetHelpMessage();
+
+ fprintf(stdout, "%s", usage.c_str());
+ return false;
+ }
+
+ // check for printtoconsole, allow -debug
+ LogInstance().m_print_to_console = gArgs.GetBoolArg("-printtoconsole", gArgs.GetBoolArg("-debug", false));
+
+ if (!fs::is_directory(GetDataDir(false))) {
+ fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
+ return false;
+ }
+ // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
+ SelectParams(gArgs.GetChainName());
+
+ return true;
+}
+
+int main(int argc, char* argv[])
+{
+#ifdef WIN32
+ util::WinCmdLineArgs winArgs;
+ std::tie(argc, argv) = winArgs.get();
+#endif
+ SetupEnvironment();
+ RandomInit();
+ try {
+ if (!WalletAppInit(argc, argv)) return EXIT_FAILURE;
+ } catch (const std::exception& e) {
+ PrintExceptionContinue(&e, "WalletAppInit()");
+ return EXIT_FAILURE;
+ } catch (...) {
+ PrintExceptionContinue(nullptr, "WalletAppInit()");
+ return EXIT_FAILURE;
+ }
+
+ std::string method {};
+ for(int i = 1; i < argc; ++i) {
+ if (!IsSwitchChar(argv[i][0])) {
+ if (!method.empty()) {
+ fprintf(stderr, "Error: two methods provided (%s and %s). Only one method should be provided.\n", method.c_str(), argv[i]);
+ return EXIT_FAILURE;
+ }
+ method = argv[i];
+ }
+ }
+
+ if (method.empty()) {
+ fprintf(stderr, "No method provided. Run `bitcoin-wallet -help` for valid methods.\n");
+ return EXIT_FAILURE;
+ }
+
+ // A name must be provided when creating a file
+ if (method == "create" && !gArgs.IsArgSet("-wallet")) {
+ fprintf(stderr, "Wallet name must be provided when creating a new wallet.\n");
+ return EXIT_FAILURE;
+ }
+
+ std::string name = gArgs.GetArg("-wallet", "");
+
+ ECCVerifyHandle globalVerifyHandle;
+ ECC_Start();
+ if (!WalletTool::ExecuteWalletToolFunc(method, name))
+ return EXIT_FAILURE;
+ ECC_Stop();
+ return EXIT_SUCCESS;
+}
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index da4832dff8..d3972fdb89 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -127,6 +127,7 @@ public:
vSeeds.emplace_back("seed.bitcoin.jonasschnelli.ch"); // Jonas Schnelli, only supports x1, x5, x9, and xd
vSeeds.emplace_back("seed.btc.petertodd.org"); // Peter Todd, only supports x1, x5, x9, and xd
vSeeds.emplace_back("seed.bitcoin.sprovoost.nl"); // Sjors Provoost
+ vSeeds.emplace_back("dnsseed.emzy.de"); // Stephan Oeste
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);
diff --git a/src/coins.h b/src/coins.h
index 94493453f0..d39ebf9062 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -298,17 +298,17 @@ private:
};
//! Utility function to add all of a transaction's outputs to a cache.
-// When check is false, this assumes that overwrites are only possible for coinbase transactions.
-// When check is true, the underlying view may be queried to determine whether an addition is
-// an overwrite.
+//! When check is false, this assumes that overwrites are only possible for coinbase transactions.
+//! When check is true, the underlying view may be queried to determine whether an addition is
+//! an overwrite.
// TODO: pass in a boolean to limit these possible overwrites to known
// (pre-BIP34) cases.
void AddCoins(CCoinsViewCache& cache, const CTransaction& tx, int nHeight, bool check = false);
//! Utility function to find any unspent output with a given txid.
-// This function can be quite expensive because in the event of a transaction
-// which is not found in the cache, it can cause up to MAX_OUTPUTS_PER_BLOCK
-// lookups to database, so it should be used with care.
+//! This function can be quite expensive because in the event of a transaction
+//! which is not found in the cache, it can cause up to MAX_OUTPUTS_PER_BLOCK
+//! lookups to database, so it should be used with care.
const Coin& AccessByTxid(const CCoinsViewCache& cache, const uint256& txid);
#endif // BITCOIN_COINS_H
diff --git a/src/compat.h b/src/compat.h
index 7b164d5630..68f6eb692c 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -11,10 +11,6 @@
#endif
#ifdef WIN32
-#ifdef _WIN32_WINNT
-#undef _WIN32_WINNT
-#endif
-#define _WIN32_WINNT 0x0501
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
diff --git a/src/crypto/sha512.h b/src/crypto/sha512.h
index cd1023bc85..4118ac1b18 100644
--- a/src/crypto/sha512.h
+++ b/src/crypto/sha512.h
@@ -17,7 +17,7 @@ private:
uint64_t bytes;
public:
- static const size_t OUTPUT_SIZE = 64;
+ static constexpr size_t OUTPUT_SIZE = 64;
CSHA512();
CSHA512& Write(const unsigned char* data, size_t len);
diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp
index 9211a7596b..8a76021a5b 100644
--- a/src/dummywallet.cpp
+++ b/src/dummywallet.cpp
@@ -8,6 +8,10 @@
class CWallet;
+namespace interfaces {
+class Chain;
+}
+
class DummyWalletInit : public WalletInitInterface {
public:
@@ -43,6 +47,11 @@ std::vector<std::shared_ptr<CWallet>> GetWallets()
throw std::logic_error("Wallet function called in non-wallet build.");
}
+std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::string& warning)
+{
+ throw std::logic_error("Wallet function called in non-wallet build.");
+}
+
namespace interfaces {
class Wallet;
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index ca60ea43a7..b9ca037c9d 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -364,8 +364,8 @@ bool InitHTTPServer()
// Update libevent's log handling. Returns false if our version of
// libevent doesn't support debug logging, in which case we should
// clear the BCLog::LIBEVENT flag.
- if (!UpdateHTTPServerLogging(g_logger->WillLogCategory(BCLog::LIBEVENT))) {
- g_logger->DisableCategory(BCLog::LIBEVENT);
+ if (!UpdateHTTPServerLogging(LogInstance().WillLogCategory(BCLog::LIBEVENT))) {
+ LogInstance().DisableCategory(BCLog::LIBEVENT);
}
#ifdef WIN32
diff --git a/src/init.cpp b/src/init.cpp
index e495a68d55..0013319ad5 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -11,6 +11,7 @@
#include <addrman.h>
#include <amount.h>
+#include <banman.h>
#include <chain.h>
#include <chainparams.h>
#include <checkpoints.h>
@@ -73,8 +74,12 @@ static const bool DEFAULT_PROXYRANDOMIZE = true;
static const bool DEFAULT_REST_ENABLE = false;
static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false;
+// Dump addresses to banlist.dat every 15 minutes (900s)
+static constexpr int DUMP_BANS_INTERVAL = 60 * 15;
+
std::unique_ptr<CConnman> g_connman;
std::unique_ptr<PeerLogicValidation> peerLogic;
+std::unique_ptr<BanMan> g_banman;
#ifdef WIN32
// Win32 LevelDB doesn't use filedescriptors, and the ones used for
@@ -199,6 +204,7 @@ void Shutdown(InitInterfaces& interfaces)
// destruct and reset all to nullptr.
peerLogic.reset();
g_connman.reset();
+ g_banman.reset();
g_txindex.reset();
if (g_is_mempool_loaded && gArgs.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
@@ -283,7 +289,7 @@ static void HandleSIGTERM(int)
static void HandleSIGHUP(int)
{
- g_logger->m_reopen_file = true;
+ LogInstance().m_reopen_file = true;
}
#else
static BOOL WINAPI consoleCtrlHandler(DWORD dwCtrlType)
@@ -320,6 +326,9 @@ static void OnRPCStopped()
void SetupServerArgs()
{
+ SetupHelpOptions(gArgs);
+ gArgs.AddArg("-help-debug", "Print help message with debugging options and exit", false, OptionsCategory::DEBUG_TEST); // server-only for now
+
const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN);
const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET);
const auto regtestBaseParams = CreateBaseChainParams(CBaseChainParams::REGTEST);
@@ -328,14 +337,11 @@ void SetupServerArgs()
const auto regtestChainParams = CreateChainParams(CBaseChainParams::REGTEST);
// Hidden Options
- std::vector<std::string> hidden_args = {"-h", "-help",
+ std::vector<std::string> hidden_args = {
"-dbcrashratio", "-forcecompactdb",
// GUI args. These will be overwritten by SetupUIArgs for the GUI
"-allowselfsignedrootcertificates", "-choosedatadir", "-lang=<lang>", "-min", "-resetguisettings", "-rootcertificates=<file>", "-splash", "-uiplatform"};
- // Set all of the args and their help
- // When adding new options to the categories, please keep and ensure alphabetical ordering.
- gArgs.AddArg("-?", "Print this help message and exit", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-version", "Print version and exit", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-alertnotify=<cmd>", "Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-assumevalid=<hex>", strprintf("If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)", defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnetChainParams->GetConsensus().defaultAssumeValid.GetHex()), false, OptionsCategory::OPTIONS);
@@ -346,7 +352,7 @@ void SetupServerArgs()
gArgs.AddArg("-conf=<file>", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), false, OptionsCategory::OPTIONS);
gArgs.AddArg("-datadir=<dir>", "Specify data directory", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize), true, OptionsCategory::OPTIONS);
- gArgs.AddArg("-dbcache=<n>", strprintf("Set database cache size in megabytes (%d to %d, default: %d)", nMinDbCache, nMaxDbCache, nDefaultDbCache), false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-dbcache=<n>", strprintf("Set database cache size in MiB (%d to %d, default: %d)", nMinDbCache, nMaxDbCache, nDefaultDbCache), false, OptionsCategory::OPTIONS);
gArgs.AddArg("-debuglogfile=<file>", strprintf("Specify location of debug log file. Relative paths will be prefixed by a net-specific datadir location. (-nodebuglogfile to disable; default: %s)", DEFAULT_DEBUGLOGFILE), false, OptionsCategory::OPTIONS);
gArgs.AddArg("-feefilter", strprintf("Tell other nodes to filter invs to us by our mempool min fee (default: %u)", DEFAULT_FEEFILTER), true, OptionsCategory::OPTIONS);
gArgs.AddArg("-includeconf=<file>", "Specify additional configuration file, relative to the -datadir path (only useable from configuration file, not command line)", false, OptionsCategory::OPTIONS);
@@ -464,7 +470,6 @@ void SetupServerArgs()
gArgs.AddArg("-debug=<category>", "Output debugging information (default: -nodebug, supplying <category> is optional). "
"If <category> is not supplied or if <category> = 1, output all debugging information. <category> can be: " + ListLogCategories() + ".", false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-debugexclude=<category>", strprintf("Exclude debugging information for a category. Can be used in conjunction with -debug=1 to output debug logs for all categories except one or more specified categories."), false, OptionsCategory::DEBUG_TEST);
- gArgs.AddArg("-help-debug", "Print help message with debugging options and exit", false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-logips", strprintf("Include IP addresses in debug output (default: %u)", DEFAULT_LOGIPS), false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-logtimestamps", strprintf("Prepend debug output with timestamp (default: %u)", DEFAULT_LOGTIMESTAMPS), false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-logtimemicros", strprintf("Add microsecond precision to debug timestamps (default: %u)", DEFAULT_LOGTIMEMICROS), true, OptionsCategory::DEBUG_TEST);
@@ -827,17 +832,17 @@ static std::string ResolveErrMsg(const char * const optname, const std::string&
*/
void InitLogging()
{
- g_logger->m_print_to_file = !gArgs.IsArgNegated("-debuglogfile");
- g_logger->m_file_path = AbsPathForConfigVal(gArgs.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE));
+ LogInstance().m_print_to_file = !gArgs.IsArgNegated("-debuglogfile");
+ LogInstance().m_file_path = AbsPathForConfigVal(gArgs.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE));
// Add newlines to the logfile to distinguish this execution from the last
// one; called before console logging is set up, so this is only sent to
// debug.log.
LogPrintf("\n\n\n\n\n");
- g_logger->m_print_to_console = gArgs.GetBoolArg("-printtoconsole", !gArgs.GetBoolArg("-daemon", false));
- g_logger->m_log_timestamps = gArgs.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS);
- g_logger->m_log_time_micros = gArgs.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS);
+ LogInstance().m_print_to_console = gArgs.GetBoolArg("-printtoconsole", !gArgs.GetBoolArg("-daemon", false));
+ LogInstance().m_log_timestamps = gArgs.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS);
+ LogInstance().m_log_time_micros = gArgs.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS);
fLogIPs = gArgs.GetBoolArg("-logips", DEFAULT_LOGIPS);
@@ -885,16 +890,7 @@ bool AppInitBasicSetup()
#endif
#ifdef WIN32
// Enable Data Execution Prevention (DEP)
- // Minimum supported OS versions: WinXP SP3, WinVista >= SP1, Win Server 2008
- // A failure is non-critical and needs no further attention!
-#ifndef PROCESS_DEP_ENABLE
- // We define this here, because GCCs winbase.h limits this to _WIN32_WINNT >= 0x0601 (Windows 7),
- // which is not correct. Can be removed, when GCCs winbase.h is fixed!
-#define PROCESS_DEP_ENABLE 0x00000001
-#endif
- typedef BOOL (WINAPI *PSETPROCDEPPOL)(DWORD);
- PSETPROCDEPPOL setProcDEPPol = (PSETPROCDEPPOL)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "SetProcessDEPPolicy");
- if (setProcDEPPol != nullptr) setProcDEPPol(PROCESS_DEP_ENABLE);
+ SetProcessDEPPolicy(PROCESS_DEP_ENABLE);
#endif
if (!SetupNetworking())
@@ -975,7 +971,7 @@ bool AppInitParameterInteraction()
if (std::none_of(categories.begin(), categories.end(),
[](std::string cat){return cat == "0" || cat == "none";})) {
for (const auto& cat : categories) {
- if (!g_logger->EnableCategory(cat)) {
+ if (!LogInstance().EnableCategory(cat)) {
InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debug", cat));
}
}
@@ -984,7 +980,7 @@ bool AppInitParameterInteraction()
// Now remove the logging categories which were explicitly excluded
for (const std::string& cat : gArgs.GetArgs("-debugexclude")) {
- if (!g_logger->DisableCategory(cat)) {
+ if (!LogInstance().DisableCategory(cat)) {
InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debugexclude", cat));
}
}
@@ -1055,7 +1051,7 @@ bool AppInitParameterInteraction()
if (nPruneTarget < MIN_DISK_SPACE_FOR_BLOCK_FILES) {
return InitError(strprintf(_("Prune configured below the minimum of %d MiB. Please use a higher number."), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024));
}
- LogPrintf("Prune configured to target %uMiB on disk for block and undo files.\n", nPruneTarget / 1024 / 1024);
+ LogPrintf("Prune configured to target %u MiB on disk for block and undo files.\n", nPruneTarget / 1024 / 1024);
fPruneMode = true;
}
@@ -1101,6 +1097,22 @@ bool AppInitParameterInteraction()
dustRelayFee = CFeeRate(n);
}
+ // This is required by both the wallet and node
+ if (gArgs.IsArgSet("-maxtxfee"))
+ {
+ CAmount nMaxFee = 0;
+ if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee))
+ return InitError(AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", "")));
+ if (nMaxFee > HIGH_MAX_TX_FEE)
+ InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
+ maxTxFee = nMaxFee;
+ if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee)
+ {
+ return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
+ gArgs.GetArg("-maxtxfee", ""), ::minRelayTxFee.ToString()));
+ }
+ }
+
fRequireStandard = !gArgs.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard());
if (chainparams.RequireStandard() && !fRequireStandard)
return InitError(strprintf("acceptnonstdtxn is not currently supported for %s chain", chainparams.NetworkIDString()));
@@ -1191,19 +1203,19 @@ bool AppInitMain(InitInterfaces& interfaces)
#ifndef WIN32
CreatePidFile(GetPidFile(), getpid());
#endif
- if (g_logger->m_print_to_file) {
- if (gArgs.GetBoolArg("-shrinkdebugfile", g_logger->DefaultShrinkDebugFile())) {
+ if (LogInstance().m_print_to_file) {
+ if (gArgs.GetBoolArg("-shrinkdebugfile", LogInstance().DefaultShrinkDebugFile())) {
// Do this first since it both loads a bunch of debug.log into memory,
// and because this needs to happen before any other debug.log printing
- g_logger->ShrinkDebugFile();
+ LogInstance().ShrinkDebugFile();
}
- if (!g_logger->OpenDebugLog()) {
+ if (!LogInstance().OpenDebugLog()) {
return InitError(strprintf("Could not open debug log file %s",
- g_logger->m_file_path.string()));
+ LogInstance().m_file_path.string()));
}
}
- if (!g_logger->m_log_timestamps)
+ if (!LogInstance().m_log_timestamps)
LogPrintf("Startup time: %s\n", FormatISO8601DateTime(GetTime()));
LogPrintf("Default data directory %s\n", GetDefaultDataDir().string());
LogPrintf("Using data directory %s\n", GetDataDir().string());
@@ -1290,11 +1302,12 @@ bool AppInitMain(InitInterfaces& interfaces)
// is not yet setup and may end up being set up twice if we
// need to reindex later.
+ assert(!g_banman);
+ g_banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", &uiInterface, gArgs.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME));
assert(!g_connman);
g_connman = std::unique_ptr<CConnman>(new CConnman(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max())));
- CConnman& connman = *g_connman;
- peerLogic.reset(new PeerLogicValidation(&connman, scheduler, gArgs.GetBoolArg("-enablebip61", DEFAULT_ENABLE_BIP61)));
+ peerLogic.reset(new PeerLogicValidation(g_connman.get(), g_banman.get(), scheduler, gArgs.GetBoolArg("-enablebip61", DEFAULT_ENABLE_BIP61)));
RegisterValidationInterface(peerLogic.get());
// sanitize comments per BIP-0014, format user agent and check total size
@@ -1416,12 +1429,12 @@ bool AppInitMain(InitInterfaces& interfaces)
nCoinCacheUsage = nTotalCache; // the rest goes to in-memory cache
int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
LogPrintf("Cache configuration:\n");
- LogPrintf("* Using %.1fMiB for block index database\n", nBlockTreeDBCache * (1.0 / 1024 / 1024));
+ LogPrintf("* Using %.1f MiB for block index database\n", nBlockTreeDBCache * (1.0 / 1024 / 1024));
if (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
- LogPrintf("* Using %.1fMiB for transaction index database\n", nTxIndexCache * (1.0 / 1024 / 1024));
+ LogPrintf("* Using %.1f MiB for transaction index database\n", nTxIndexCache * (1.0 / 1024 / 1024));
}
- LogPrintf("* Using %.1fMiB for chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024));
- LogPrintf("* Using %.1fMiB for in-memory UTXO set (plus up to %.1fMiB of unused mempool space)\n", nCoinCacheUsage * (1.0 / 1024 / 1024), nMempoolSizeMax * (1.0 / 1024 / 1024));
+ LogPrintf("* Using %.1f MiB for chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024));
+ LogPrintf("* Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)\n", nCoinCacheUsage * (1.0 / 1024 / 1024), nMempoolSizeMax * (1.0 / 1024 / 1024));
bool fLoaded = false;
while (!fLoaded && !ShutdownRequested()) {
@@ -1704,6 +1717,7 @@ bool AppInitMain(InitInterfaces& interfaces)
connOptions.nMaxFeeler = 1;
connOptions.nBestHeight = chain_active_height;
connOptions.uiInterface = &uiInterface;
+ connOptions.m_banman = g_banman.get();
connOptions.m_msgproc = peerLogic.get();
connOptions.nSendBufferMaxSize = 1000*gArgs.GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER);
connOptions.nReceiveFloodSize = 1000*gArgs.GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER);
@@ -1749,7 +1763,7 @@ bool AppInitMain(InitInterfaces& interfaces)
connOptions.m_specified_outgoing = connect;
}
}
- if (!connman.Start(scheduler, connOptions)) {
+ if (!g_connman->Start(scheduler, connOptions)) {
return false;
}
@@ -1762,5 +1776,9 @@ bool AppInitMain(InitInterfaces& interfaces)
client->start(scheduler);
}
+ scheduler.scheduleEvery([]{
+ g_banman->DumpBanlist();
+ }, DUMP_BANS_INTERVAL * 1000);
+
return true;
}
diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp
index 2571a91031..da810bc5e6 100644
--- a/src/interfaces/chain.cpp
+++ b/src/interfaces/chain.cpp
@@ -4,7 +4,11 @@
#include <interfaces/chain.h>
+#include <chain.h>
+#include <chainparams.h>
+#include <primitives/block.h>
#include <sync.h>
+#include <uint256.h>
#include <util/system.h>
#include <validation.h>
@@ -16,6 +20,118 @@ namespace {
class LockImpl : public Chain::Lock
{
+ Optional<int> getHeight() override
+ {
+ int height = ::chainActive.Height();
+ if (height >= 0) {
+ return height;
+ }
+ return nullopt;
+ }
+ Optional<int> getBlockHeight(const uint256& hash) override
+ {
+ CBlockIndex* block = LookupBlockIndex(hash);
+ if (block && ::chainActive.Contains(block)) {
+ return block->nHeight;
+ }
+ return nullopt;
+ }
+ int getBlockDepth(const uint256& hash) override
+ {
+ const Optional<int> tip_height = getHeight();
+ const Optional<int> height = getBlockHeight(hash);
+ return tip_height && height ? *tip_height - *height + 1 : 0;
+ }
+ uint256 getBlockHash(int height) override
+ {
+ CBlockIndex* block = ::chainActive[height];
+ assert(block != nullptr);
+ return block->GetBlockHash();
+ }
+ int64_t getBlockTime(int height) override
+ {
+ CBlockIndex* block = ::chainActive[height];
+ assert(block != nullptr);
+ return block->GetBlockTime();
+ }
+ int64_t getBlockMedianTimePast(int height) override
+ {
+ CBlockIndex* block = ::chainActive[height];
+ assert(block != nullptr);
+ return block->GetMedianTimePast();
+ }
+ bool haveBlockOnDisk(int height) override
+ {
+ CBlockIndex* block = ::chainActive[height];
+ return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0;
+ }
+ Optional<int> findFirstBlockWithTime(int64_t time, uint256* hash) override
+ {
+ CBlockIndex* block = ::chainActive.FindEarliestAtLeast(time);
+ if (block) {
+ if (hash) *hash = block->GetBlockHash();
+ return block->nHeight;
+ }
+ return nullopt;
+ }
+ Optional<int> findFirstBlockWithTimeAndHeight(int64_t time, int height) override
+ {
+ // TODO: Could update CChain::FindEarliestAtLeast() to take a height
+ // parameter and use it with std::lower_bound() to make this
+ // implementation more efficient and allow combining
+ // findFirstBlockWithTime and findFirstBlockWithTimeAndHeight into one
+ // method.
+ for (CBlockIndex* block = ::chainActive[height]; block; block = ::chainActive.Next(block)) {
+ if (block->GetBlockTime() >= time) {
+ return block->nHeight;
+ }
+ }
+ return nullopt;
+ }
+ Optional<int> findPruned(int start_height, Optional<int> stop_height) override
+ {
+ if (::fPruneMode) {
+ CBlockIndex* block = stop_height ? ::chainActive[*stop_height] : ::chainActive.Tip();
+ while (block && block->nHeight >= start_height) {
+ if ((block->nStatus & BLOCK_HAVE_DATA) == 0) {
+ return block->nHeight;
+ }
+ block = block->pprev;
+ }
+ }
+ return nullopt;
+ }
+ Optional<int> findFork(const uint256& hash, Optional<int>* height) override
+ {
+ const CBlockIndex* block = LookupBlockIndex(hash);
+ const CBlockIndex* fork = block ? ::chainActive.FindFork(block) : nullptr;
+ if (height) {
+ if (block) {
+ *height = block->nHeight;
+ } else {
+ height->reset();
+ }
+ }
+ if (fork) {
+ return fork->nHeight;
+ }
+ return nullopt;
+ }
+ bool isPotentialTip(const uint256& hash) override
+ {
+ if (::chainActive.Tip()->GetBlockHash() == hash) return true;
+ CBlockIndex* block = LookupBlockIndex(hash);
+ return block && block->GetAncestor(::chainActive.Height()) == ::chainActive.Tip();
+ }
+ CBlockLocator getTipLocator() override { return ::chainActive.GetLocator(); }
+ Optional<int> findLocatorFork(const CBlockLocator& locator) override
+ {
+ LockAnnotation lock(::cs_main);
+ if (CBlockIndex* fork = FindForkInGlobalIndex(::chainActive, locator)) {
+ return fork->nHeight;
+ }
+ return nullopt;
+ }
};
class LockingStateImpl : public LockImpl, public UniqueLock<CCriticalSection>
@@ -35,6 +151,32 @@ public:
return std::move(result);
}
std::unique_ptr<Chain::Lock> assumeLocked() override { return MakeUnique<LockImpl>(); }
+ bool findBlock(const uint256& hash, CBlock* block, int64_t* time, int64_t* time_max) override
+ {
+ CBlockIndex* index;
+ {
+ LOCK(cs_main);
+ index = LookupBlockIndex(hash);
+ if (!index) {
+ return false;
+ }
+ if (time) {
+ *time = index->GetBlockTime();
+ }
+ if (time_max) {
+ *time_max = index->GetBlockTimeMax();
+ }
+ }
+ if (block && !ReadBlockFromDisk(*block, index, Params().GetConsensus())) {
+ block->SetNull();
+ }
+ return true;
+ }
+ double guessVerificationProgress(const uint256& block_hash) override
+ {
+ LOCK(cs_main);
+ return GuessVerificationProgress(Params().TxData(), LookupBlockIndex(block_hash));
+ }
};
} // namespace
diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h
index fe5658de4b..3a54b9164e 100644
--- a/src/interfaces/chain.h
+++ b/src/interfaces/chain.h
@@ -5,11 +5,17 @@
#ifndef BITCOIN_INTERFACES_CHAIN_H
#define BITCOIN_INTERFACES_CHAIN_H
+#include <optional.h>
+
#include <memory>
+#include <stdint.h>
#include <string>
#include <vector>
+class CBlock;
class CScheduler;
+class uint256;
+struct CBlockLocator;
namespace interfaces {
@@ -28,6 +34,74 @@ public:
{
public:
virtual ~Lock() {}
+
+ //! Get current chain height, not including genesis block (returns 0 if
+ //! chain only contains genesis block, nullopt if chain does not contain
+ //! any blocks).
+ virtual Optional<int> getHeight() = 0;
+
+ //! Get block height above genesis block. Returns 0 for genesis block,
+ //! 1 for following block, and so on. Returns nullopt for a block not
+ //! included in the current chain.
+ virtual Optional<int> getBlockHeight(const uint256& hash) = 0;
+
+ //! Get block depth. Returns 1 for chain tip, 2 for preceding block, and
+ //! so on. Returns 0 for a block not included in the current chain.
+ virtual int getBlockDepth(const uint256& hash) = 0;
+
+ //! Get block hash. Height must be valid or this function will abort.
+ virtual uint256 getBlockHash(int height) = 0;
+
+ //! Get block time. Height must be valid or this function will abort.
+ virtual int64_t getBlockTime(int height) = 0;
+
+ //! Get block median time past. Height must be valid or this function
+ //! will abort.
+ virtual int64_t getBlockMedianTimePast(int height) = 0;
+
+ //! Check that the block is available on disk (i.e. has not been
+ //! pruned), and contains transactions.
+ virtual bool haveBlockOnDisk(int height) = 0;
+
+ //! Return height of the first block in the chain with timestamp equal
+ //! or greater than the given time, or nullopt if there is no block with
+ //! a high enough timestamp. Also return the block hash as an optional
+ //! output parameter (to avoid the cost of a second lookup in case this
+ //! information is needed.)
+ virtual Optional<int> findFirstBlockWithTime(int64_t time, uint256* hash) = 0;
+
+ //! Return height of the first block in the chain with timestamp equal
+ //! or greater than the given time and height equal or greater than the
+ //! given height, or nullopt if there is no such block.
+ //!
+ //! Calling this with height 0 is equivalent to calling
+ //! findFirstBlockWithTime, but less efficient because it requires a
+ //! linear instead of a binary search.
+ virtual Optional<int> findFirstBlockWithTimeAndHeight(int64_t time, int height) = 0;
+
+ //! Return height of last block in the specified range which is pruned, or
+ //! nullopt if no block in the range is pruned. Range is inclusive.
+ virtual Optional<int> findPruned(int start_height = 0, Optional<int> stop_height = nullopt) = 0;
+
+ //! Return height of the highest block on the chain that is an ancestor
+ //! of the specified block, or nullopt if no common ancestor is found.
+ //! Also return the height of the specified block as an optional output
+ //! parameter (to avoid the cost of a second hash lookup in case this
+ //! information is desired).
+ virtual Optional<int> findFork(const uint256& hash, Optional<int>* height) = 0;
+
+ //! Return true if block hash points to the current chain tip, or to a
+ //! possible descendant of the current chain tip that isn't currently
+ //! connected.
+ virtual bool isPotentialTip(const uint256& hash) = 0;
+
+ //! Get locator for the current chain tip.
+ virtual CBlockLocator getTipLocator() = 0;
+
+ //! Return height of the latest block common to locator and chain, which
+ //! is guaranteed to be an ancestor of the block used to create the
+ //! locator.
+ virtual Optional<int> findLocatorFork(const CBlockLocator& locator) = 0;
};
//! Return Lock interface. Chain is locked when this is called, and
@@ -38,6 +112,21 @@ public:
//! method is temporary and is only used in a few places to avoid changing
//! behavior while code is transitioned to use the Chain::Lock interface.
virtual std::unique_ptr<Lock> assumeLocked() = 0;
+
+ //! Return whether node has the block and optionally return block metadata
+ //! or contents.
+ //!
+ //! If a block pointer is provided to retrieve the block contents, and the
+ //! block exists but doesn't have data (for example due to pruning), the
+ //! block will be empty and all fields set to null.
+ virtual bool findBlock(const uint256& hash,
+ CBlock* block = nullptr,
+ int64_t* time = nullptr,
+ int64_t* max_time = nullptr) = 0;
+
+ //! Estimate fraction of total transactions verified if blocks up to
+ //! the specified block hash are verified.
+ virtual double guessVerificationProgress(const uint256& block_hash) = 0;
};
//! Interface to let node manage chain clients (wallets, or maybe tools for
diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp
index acba05fd5e..96bde7e9f2 100644
--- a/src/interfaces/node.cpp
+++ b/src/interfaces/node.cpp
@@ -6,6 +6,7 @@
#include <addrdb.h>
#include <amount.h>
+#include <banman.h>
#include <chain.h>
#include <chainparams.h>
#include <init.h>
@@ -41,6 +42,7 @@ class CWallet;
fs::path GetWalletDir();
std::vector<fs::path> ListWalletDir();
std::vector<std::shared_ptr<CWallet>> GetWallets();
+std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::string& warning);
namespace interfaces {
@@ -66,7 +68,7 @@ public:
void initLogging() override { InitLogging(); }
void initParameterInteraction() override { InitParameterInteraction(); }
std::string getWarnings(const std::string& type) override { return GetWarnings(type); }
- uint32_t getLogCategories() override { return g_logger->GetCategoryMask(); }
+ uint32_t getLogCategories() override { return LogInstance().GetCategoryMask(); }
bool baseInitialize() override
{
return AppInitBasicSetup() && AppInitParameterInteraction() && AppInitSanityChecks() &&
@@ -122,28 +124,35 @@ public:
}
bool getBanned(banmap_t& banmap) override
{
- if (g_connman) {
- g_connman->GetBanned(banmap);
+ if (g_banman) {
+ g_banman->GetBanned(banmap);
return true;
}
return false;
}
bool ban(const CNetAddr& net_addr, BanReason reason, int64_t ban_time_offset) override
{
- if (g_connman) {
- g_connman->Ban(net_addr, reason, ban_time_offset);
+ if (g_banman) {
+ g_banman->Ban(net_addr, reason, ban_time_offset);
return true;
}
return false;
}
bool unban(const CSubNet& ip) override
{
- if (g_connman) {
- g_connman->Unban(ip);
+ if (g_banman) {
+ g_banman->Unban(ip);
return true;
}
return false;
}
+ bool disconnect(const CNetAddr& net_addr) override
+ {
+ if (g_connman) {
+ return g_connman->DisconnectNode(net_addr);
+ }
+ return false;
+ }
bool disconnect(NodeId id) override
{
if (g_connman) {
@@ -244,6 +253,10 @@ public:
}
return wallets;
}
+ std::unique_ptr<Wallet> loadWallet(const std::string& name, std::string& error, std::string& warning) override
+ {
+ return MakeWallet(LoadWallet(*m_interfaces.chain, name, error, warning));
+ }
std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) override
{
return MakeHandler(::uiInterface.InitMessage_connect(fn));
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index 7fa5958c51..76b93af234 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -18,6 +18,7 @@
#include <tuple>
#include <vector>
+class BanMan;
class CCoinControl;
class CFeeRate;
class CNodeStats;
@@ -113,7 +114,10 @@ public:
//! Unban node.
virtual bool unban(const CSubNet& ip) = 0;
- //! Disconnect node.
+ //! Disconnect node by address.
+ virtual bool disconnect(const CNetAddr& net_addr) = 0;
+
+ //! Disconnect node by id.
virtual bool disconnect(NodeId id) = 0;
//! Get total bytes recv.
@@ -188,6 +192,11 @@ public:
//! Return interfaces for accessing wallets (if any).
virtual std::vector<std::unique_ptr<Wallet>> getWallets() = 0;
+ //! Attempts to load a wallet from file or directory.
+ //! The loaded wallet is also notified to handlers previously registered
+ //! with handleLoadWallet.
+ virtual std::unique_ptr<Wallet> loadWallet(const std::string& name, std::string& error, std::string& warning) = 0;
+
//! Register handler for init messages.
using InitMessageFn = std::function<void(const std::string& message)>;
virtual std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) = 0;
diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp
index 8db34ed759..206227b101 100644
--- a/src/interfaces/wallet.cpp
+++ b/src/interfaces/wallet.cpp
@@ -212,6 +212,7 @@ public:
}
std::vector<std::string> getDestValues(const std::string& prefix) override
{
+ LOCK(m_wallet.cs_wallet);
return m_wallet.GetDestValues(prefix);
}
void lockCoin(const COutPoint& output) override
@@ -333,8 +334,13 @@ public:
if (mi == m_wallet.mapWallet.end()) {
return false;
}
- num_blocks = ::chainActive.Height();
- block_time = ::chainActive.Tip()->GetBlockTime();
+ if (Optional<int> height = locked_chain->getHeight()) {
+ num_blocks = *height;
+ block_time = locked_chain->getBlockTime(*height);
+ } else {
+ num_blocks = -1;
+ block_time = -1;
+ }
tx_status = MakeWalletTxStatus(*locked_chain, mi->second);
return true;
}
@@ -348,7 +354,7 @@ public:
LOCK(m_wallet.cs_wallet);
auto mi = m_wallet.mapWallet.find(txid);
if (mi != m_wallet.mapWallet.end()) {
- num_blocks = ::chainActive.Height();
+ num_blocks = locked_chain->getHeight().get_value_or(-1);
in_mempool = mi->second.InMempool();
order_form = mi->second.vOrderForm;
tx_status = MakeWalletTxStatus(*locked_chain, mi->second);
@@ -379,7 +385,7 @@ public:
return false;
}
balances = getBalances();
- num_blocks = ::chainActive.Height();
+ num_blocks = locked_chain->getHeight().get_value_or(-1);
return true;
}
CAmount getBalance() override { return m_wallet.GetBalance(); }
@@ -458,6 +464,7 @@ public:
}
unsigned int getConfirmTarget() override { return m_wallet.m_confirm_target; }
bool hdEnabled() override { return m_wallet.IsHDEnabled(); }
+ bool canGetAddresses() override { return m_wallet.CanGetAddresses(); }
bool IsWalletFlagSet(uint64_t flag) override { return m_wallet.IsWalletFlagSet(flag); }
OutputType getDefaultAddressType() override { return m_wallet.m_default_address_type; }
OutputType getDefaultChangeType() override { return m_wallet.m_default_change_type; }
@@ -488,6 +495,10 @@ public:
{
return MakeHandler(m_wallet.NotifyWatchonlyChanged.connect(fn));
}
+ std::unique_ptr<Handler> handleCanGetAddressesChanged(CanGetAddressesChangedFn fn) override
+ {
+ return MakeHandler(m_wallet.NotifyCanGetAddressesChanged.connect(fn));
+ }
std::shared_ptr<CWallet> m_shared_wallet;
CWallet& m_wallet;
@@ -514,7 +525,7 @@ public:
} // namespace
-std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet) { return MakeUnique<WalletImpl>(wallet); }
+std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet) { return wallet ? MakeUnique<WalletImpl>(wallet) : nullptr; }
std::unique_ptr<ChainClient> MakeWalletClient(Chain& chain, std::vector<std::string> wallet_filenames)
{
diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h
index da60684a4f..a86212356c 100644
--- a/src/interfaces/wallet.h
+++ b/src/interfaces/wallet.h
@@ -235,6 +235,9 @@ public:
// Return whether HD enabled.
virtual bool hdEnabled() = 0;
+ // Return whether the wallet is blank.
+ virtual bool canGetAddresses() = 0;
+
// check if a certain wallet flag is set.
virtual bool IsWalletFlagSet(uint64_t flag) = 0;
@@ -271,6 +274,10 @@ public:
//! Register handler for watchonly changed messages.
using WatchOnlyChangedFn = std::function<void(bool have_watch_only)>;
virtual std::unique_ptr<Handler> handleWatchOnlyChanged(WatchOnlyChangedFn fn) = 0;
+
+ //! Register handler for keypool changed messages.
+ using CanGetAddressesChangedFn = std::function<void()>;
+ virtual std::unique_ptr<Handler> handleCanGetAddressesChanged(CanGetAddressesChangedFn fn) = 0;
};
//! Tracking object returned by CreateTransaction and passed to CommitTransaction.
diff --git a/src/key.cpp b/src/key.cpp
index 80d6589a3c..9d982fc44f 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -246,7 +246,7 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig)
secp256k1_ecdsa_recoverable_signature sig;
int ret = secp256k1_ecdsa_sign_recoverable(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, nullptr);
assert(ret);
- secp256k1_ecdsa_recoverable_signature_serialize_compact(secp256k1_context_sign, &vchSig[1], &rec, &sig);
+ ret = secp256k1_ecdsa_recoverable_signature_serialize_compact(secp256k1_context_sign, &vchSig[1], &rec, &sig);
assert(ret);
assert(rec != -1);
vchSig[0] = 27 + rec + (fCompressed ? 4 : 0);
diff --git a/src/key_io.cpp b/src/key_io.cpp
index d998089535..1d53a5e074 100644
--- a/src/key_io.cpp
+++ b/src/key_io.cpp
@@ -142,7 +142,9 @@ CKey DecodeSecret(const std::string& str)
key.Set(data.begin() + privkey_prefix.size(), data.begin() + privkey_prefix.size() + 32, compressed);
}
}
- memory_cleanse(data.data(), data.size());
+ if (!data.empty()) {
+ memory_cleanse(data.data(), data.size());
+ }
return key;
}
diff --git a/src/leveldb/db/c.cc b/src/leveldb/db/c.cc
index 08ff0ad90a..b23e3dcc9d 100644
--- a/src/leveldb/db/c.cc
+++ b/src/leveldb/db/c.cc
@@ -5,7 +5,9 @@
#include "leveldb/c.h"
#include <stdlib.h>
+#ifndef WIN32
#include <unistd.h>
+#endif
#include "leveldb/cache.h"
#include "leveldb/comparator.h"
#include "leveldb/db.h"
diff --git a/src/leveldb/port/port_win.h b/src/leveldb/port/port_win.h
index e8bf46ef27..989c15cd91 100644
--- a/src/leveldb/port/port_win.h
+++ b/src/leveldb/port/port_win.h
@@ -32,9 +32,16 @@
#define STORAGE_LEVELDB_PORT_PORT_WIN_H_
#ifdef _MSC_VER
+#if !(_MSC_VER >= 1900)
#define snprintf _snprintf
+#endif
#define close _close
#define fread_unlocked _fread_nolock
+#ifdef _WIN64
+#define ssize_t int64_t
+#else
+#define ssize_t int32_t
+#endif
#endif
#include <string>
diff --git a/src/leveldb/util/env_win.cc b/src/leveldb/util/env_win.cc
index 81380216bb..830332abe9 100644
--- a/src/leveldb/util/env_win.cc
+++ b/src/leveldb/util/env_win.cc
@@ -203,24 +203,16 @@ public:
void ToWidePath(const std::string& value, std::wstring& target) {
wchar_t buffer[MAX_PATH];
- MultiByteToWideChar(CP_ACP, 0, value.c_str(), -1, buffer, MAX_PATH);
+ MultiByteToWideChar(CP_UTF8, 0, value.c_str(), -1, buffer, MAX_PATH);
target = buffer;
}
void ToNarrowPath(const std::wstring& value, std::string& target) {
char buffer[MAX_PATH];
- WideCharToMultiByte(CP_ACP, 0, value.c_str(), -1, buffer, MAX_PATH, NULL, NULL);
+ WideCharToMultiByte(CP_UTF8, 0, value.c_str(), -1, buffer, MAX_PATH, NULL, NULL);
target = buffer;
}
-std::string GetCurrentDir()
-{
- CHAR path[MAX_PATH];
- ::GetModuleFileNameA(::GetModuleHandleA(NULL),path,MAX_PATH);
- *strrchr(path,'\\') = 0;
- return std::string(path);
-}
-
std::wstring GetCurrentDirW()
{
WCHAR path[MAX_PATH];
@@ -229,6 +221,13 @@ std::wstring GetCurrentDirW()
return std::wstring(path);
}
+std::string GetCurrentDir()
+{
+ std::string path;
+ ToNarrowPath(GetCurrentDirW(), path);
+ return path;
+}
+
std::string& ModifyPath(std::string& path)
{
if(path[0] == '/' || path[0] == '\\'){
@@ -764,14 +763,16 @@ uint64_t Win32Env::NowMicros()
static Status CreateDirInner( const std::string& dirname )
{
Status sRet;
- DWORD attr = ::GetFileAttributes(dirname.c_str());
+ std::wstring dirnameW;
+ ToWidePath(dirname, dirnameW);
+ DWORD attr = ::GetFileAttributesW(dirnameW.c_str());
if (attr == INVALID_FILE_ATTRIBUTES) { // doesn't exist:
std::size_t slash = dirname.find_last_of("\\");
if (slash != std::string::npos){
sRet = CreateDirInner(dirname.substr(0, slash));
if (!sRet.ok()) return sRet;
}
- BOOL result = ::CreateDirectory(dirname.c_str(), NULL);
+ BOOL result = ::CreateDirectoryW(dirnameW.c_str(), NULL);
if (result == FALSE) {
sRet = Status::IOError(dirname, "Could not create directory.");
return sRet;
diff --git a/src/logging.cpp b/src/logging.cpp
index 77dc2d0939..36cad6573a 100644
--- a/src/logging.cpp
+++ b/src/logging.cpp
@@ -8,6 +8,8 @@
const char * const DEFAULT_DEBUGLOGFILE = "debug.log";
+BCLog::Logger& LogInstance()
+{
/**
* NOTE: the logger instances is leaked on exit. This is ugly, but will be
* cleaned up by the OS/libc. Defining a logger as a global object doesn't work
@@ -17,11 +19,15 @@ const char * const DEFAULT_DEBUGLOGFILE = "debug.log";
* access the logger. When the shutdown sequence is fully audited and tested,
* explicit destruction of these objects can be implemented by changing this
* from a raw pointer to a std::unique_ptr.
+ * Since the destructor is never called, the logger and all its members must
+ * have a trivial destructor.
*
* This method of initialization was originally introduced in
* ee3374234c60aba2cc4c5cd5cac1c0aefc2d817c.
*/
-BCLog::Logger* const g_logger = new BCLog::Logger();
+ static BCLog::Logger* g_logger{new BCLog::Logger()};
+ return *g_logger;
+}
bool fLogIPs = DEFAULT_LOGIPS;
diff --git a/src/logging.h b/src/logging.h
index 0c8e7f5291..ac9d0dc0c7 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -108,12 +108,12 @@ namespace BCLog {
} // namespace BCLog
-extern BCLog::Logger* const g_logger;
+BCLog::Logger& LogInstance();
/** Return true if log accepts specified category */
static inline bool LogAcceptCategory(BCLog::LogFlags category)
{
- return g_logger->WillLogCategory(category);
+ return LogInstance().WillLogCategory(category);
}
/** Returns a string with the log categories. */
@@ -132,7 +132,7 @@ bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str);
template <typename... Args>
static inline void LogPrintf(const char* fmt, const Args&... args)
{
- if (g_logger->Enabled()) {
+ if (LogInstance().Enabled()) {
std::string log_msg;
try {
log_msg = tfm::format(fmt, args...);
@@ -140,7 +140,7 @@ static inline void LogPrintf(const char* fmt, const Args&... args)
/* Original format string will have newline so don't add one here */
log_msg = "Error \"" + std::string(fmterr.what()) + "\" while formatting log message: " + fmt;
}
- g_logger->LogPrintStr(log_msg);
+ LogInstance().LogPrintStr(log_msg);
}
}
diff --git a/src/net.cpp b/src/net.cpp
index 98bd518ecc..87f1ef0577 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -9,6 +9,7 @@
#include <net.h>
+#include <banman.h>
#include <chainparams.h>
#include <clientversion.h>
#include <consensus/consensus.h>
@@ -41,8 +42,8 @@
#include <math.h>
-// Dump addresses to peers.dat and banlist.dat every 15 minutes (900s)
-#define DUMP_ADDRESSES_INTERVAL 900
+// Dump addresses to peers.dat every 15 minutes (900s)
+static constexpr int DUMP_PEERS_INTERVAL = 15 * 60;
// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization.
#define FEELER_SLEEP_WINDOW 1
@@ -57,17 +58,6 @@
#define MSG_DONTWAIT 0
#endif
-// Fix for ancient MinGW versions, that don't have defined these in ws2tcpip.h.
-// Todo: Can be removed when our pull-tester is upgraded to a modern MinGW version.
-#ifdef WIN32
-#ifndef PROTECTION_LEVEL_UNRESTRICTED
-#define PROTECTION_LEVEL_UNRESTRICTED 10
-#endif
-#ifndef IPV6_PROTECTION_LEVEL
-#define IPV6_PROTECTION_LEVEL 23
-#endif
-#endif
-
/** Used to pass flags to the Bind() function */
enum BindFlags {
BF_NONE = 0,
@@ -95,8 +85,6 @@ std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(cs_mapLocalHost);
static bool vfLimited[NET_MAX] GUARDED_BY(cs_mapLocalHost) = {};
std::string strSubVersion;
-limitedmap<uint256, int64_t> mapAlreadyAskedFor(MAX_INV_SZ);
-
void CConnman::AddOneShot(const std::string& strDest)
{
LOCK(cs_vOneShots);
@@ -173,8 +161,7 @@ CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices)
static int GetnScore(const CService& addr)
{
LOCK(cs_mapLocalHost);
- if (mapLocalHost.count(addr) == LOCAL_NONE)
- return 0;
+ if (mapLocalHost.count(addr) == 0) return 0;
return mapLocalHost[addr].nScore;
}
@@ -457,26 +444,6 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
return pnode;
}
-void CConnman::DumpBanlist()
-{
- SweepBanned(); // clean unused entries (if bantime has expired)
-
- if (!BannedSetIsDirty())
- return;
-
- int64_t nStart = GetTimeMillis();
-
- CBanDB bandb;
- banmap_t banmap;
- GetBanned(banmap);
- if (bandb.Write(banmap)) {
- SetBannedSetDirty(false);
- }
-
- LogPrint(BCLog::NET, "Flushed %d banned node ips/subnets to banlist.dat %dms\n",
- banmap.size(), GetTimeMillis() - nStart);
-}
-
void CNode::CloseSocketDisconnect()
{
fDisconnect = true;
@@ -488,157 +455,6 @@ void CNode::CloseSocketDisconnect()
}
}
-void CConnman::ClearBanned()
-{
- {
- LOCK(cs_setBanned);
- setBanned.clear();
- setBannedIsDirty = true;
- }
- DumpBanlist(); //store banlist to disk
- if(clientInterface)
- clientInterface->BannedListChanged();
-}
-
-bool CConnman::IsBanned(CNetAddr ip)
-{
- LOCK(cs_setBanned);
- for (const auto& it : setBanned) {
- CSubNet subNet = it.first;
- CBanEntry banEntry = it.second;
-
- if (subNet.Match(ip) && GetTime() < banEntry.nBanUntil) {
- return true;
- }
- }
- return false;
-}
-
-bool CConnman::IsBanned(CSubNet subnet)
-{
- LOCK(cs_setBanned);
- banmap_t::iterator i = setBanned.find(subnet);
- if (i != setBanned.end())
- {
- CBanEntry banEntry = (*i).second;
- if (GetTime() < banEntry.nBanUntil) {
- return true;
- }
- }
- return false;
-}
-
-void CConnman::Ban(const CNetAddr& addr, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {
- CSubNet subNet(addr);
- Ban(subNet, banReason, bantimeoffset, sinceUnixEpoch);
-}
-
-void CConnman::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {
- CBanEntry banEntry(GetTime());
- banEntry.banReason = banReason;
- if (bantimeoffset <= 0)
- {
- bantimeoffset = gArgs.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME);
- sinceUnixEpoch = false;
- }
- banEntry.nBanUntil = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset;
-
- {
- LOCK(cs_setBanned);
- if (setBanned[subNet].nBanUntil < banEntry.nBanUntil) {
- setBanned[subNet] = banEntry;
- setBannedIsDirty = true;
- }
- else
- return;
- }
- if(clientInterface)
- clientInterface->BannedListChanged();
- {
- LOCK(cs_vNodes);
- for (CNode* pnode : vNodes) {
- if (subNet.Match(static_cast<CNetAddr>(pnode->addr)))
- pnode->fDisconnect = true;
- }
- }
- if(banReason == BanReasonManuallyAdded)
- DumpBanlist(); //store banlist to disk immediately if user requested ban
-}
-
-bool CConnman::Unban(const CNetAddr &addr) {
- CSubNet subNet(addr);
- return Unban(subNet);
-}
-
-bool CConnman::Unban(const CSubNet &subNet) {
- {
- LOCK(cs_setBanned);
- if (!setBanned.erase(subNet))
- return false;
- setBannedIsDirty = true;
- }
- if(clientInterface)
- clientInterface->BannedListChanged();
- DumpBanlist(); //store banlist to disk immediately
- return true;
-}
-
-void CConnman::GetBanned(banmap_t &banMap)
-{
- LOCK(cs_setBanned);
- // Sweep the banlist so expired bans are not returned
- SweepBanned();
- banMap = setBanned; //create a thread safe copy
-}
-
-void CConnman::SetBanned(const banmap_t &banMap)
-{
- LOCK(cs_setBanned);
- setBanned = banMap;
- setBannedIsDirty = true;
-}
-
-void CConnman::SweepBanned()
-{
- int64_t now = GetTime();
- bool notifyUI = false;
- {
- LOCK(cs_setBanned);
- banmap_t::iterator it = setBanned.begin();
- while(it != setBanned.end())
- {
- CSubNet subNet = (*it).first;
- CBanEntry banEntry = (*it).second;
- if(now > banEntry.nBanUntil)
- {
- setBanned.erase(it++);
- setBannedIsDirty = true;
- notifyUI = true;
- LogPrint(BCLog::NET, "%s: Removed banned node ip/subnet from banlist.dat: %s\n", __func__, subNet.ToString());
- }
- else
- ++it;
- }
- }
- // update UI
- if(notifyUI && clientInterface) {
- clientInterface->BannedListChanged();
- }
-}
-
-bool CConnman::BannedSetIsDirty()
-{
- LOCK(cs_setBanned);
- return setBannedIsDirty;
-}
-
-void CConnman::SetBannedSetDirty(bool dirty)
-{
- LOCK(cs_setBanned); //reuse setBanned lock for the isDirty flag
- setBannedIsDirty = dirty;
-}
-
-
bool CConnman::IsWhitelistedRange(const CNetAddr &addr) {
for (const CSubNet& subnet : vWhitelistedRange) {
if (subnet.Match(addr))
@@ -934,6 +750,7 @@ struct NodeEvictionCandidate
bool fBloomFilter;
CAddress addr;
uint64_t nKeyedNetGroup;
+ bool prefer_evict;
};
static bool ReverseCompareNodeMinPingTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b)
@@ -1002,7 +819,8 @@ bool CConnman::AttemptToEvictConnection()
NodeEvictionCandidate candidate = {node->GetId(), node->nTimeConnected, node->nMinPingUsecTime,
node->nLastBlockTime, node->nLastTXTime,
HasAllDesirableServiceFlags(node->nServices),
- node->fRelayTxes, node->pfilter != nullptr, node->addr, node->nKeyedNetGroup};
+ node->fRelayTxes, node->pfilter != nullptr, node->addr, node->nKeyedNetGroup,
+ node->m_prefer_evict};
vEvictionCandidates.push_back(candidate);
}
}
@@ -1027,6 +845,14 @@ bool CConnman::AttemptToEvictConnection()
if (vEvictionCandidates.empty()) return false;
+ // If any remaining peers are preferred for eviction consider only them.
+ // This happens after the other preferences since if a peer is really the best by other criteria (esp relaying blocks)
+ // then we probably don't want to evict it no matter what.
+ if (std::any_of(vEvictionCandidates.begin(),vEvictionCandidates.end(),[](NodeEvictionCandidate const &n){return n.prefer_evict;})) {
+ vEvictionCandidates.erase(std::remove_if(vEvictionCandidates.begin(),vEvictionCandidates.end(),
+ [](NodeEvictionCandidate const &n){return !n.prefer_evict;}),vEvictionCandidates.end());
+ }
+
// Identify the network group with the most connections and youngest member.
// (vEvictionCandidates is already sorted by reverse connect time)
uint64_t naMostConnections;
@@ -1107,7 +933,11 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
// on all platforms. Set it again here just to be sure.
SetSocketNoDelay(hSocket);
- if (IsBanned(addr) && !whitelisted)
+ int bannedlevel = m_banman ? m_banman->IsBannedLevel(addr) : 0;
+
+ // Don't accept connections from banned peers, but if our inbound slots aren't almost full, accept
+ // if the only banning reason was an automatic misbehavior ban.
+ if (!whitelisted && bannedlevel > ((nInbound + 1 < nMaxInbound) ? 1 : 0))
{
LogPrint(BCLog::NET, "connection from %s dropped (banned)\n", addr.ToString());
CloseSocket(hSocket);
@@ -1131,6 +961,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", true);
pnode->AddRef();
pnode->fWhitelisted = whitelisted;
+ pnode->m_prefer_evict = bannedlevel > 0;
m_msgproc->InitializeNode(pnode);
LogPrint(BCLog::NET, "connection from %s accepted\n", addr.ToString());
@@ -1775,12 +1606,6 @@ void CConnman::DumpAddresses()
addrman.size(), GetTimeMillis() - nStart);
}
-void CConnman::DumpData()
-{
- DumpAddresses();
- DumpBanlist();
-}
-
void CConnman::ProcessOneShot()
{
std::string strDest;
@@ -2085,7 +1910,7 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
}
if (!pszDest) {
if (IsLocal(addrConnect) ||
- FindNode(static_cast<CNetAddr>(addrConnect)) || IsBanned(addrConnect) ||
+ FindNode(static_cast<CNetAddr>(addrConnect)) || (m_banman && m_banman->IsBanned(addrConnect)) ||
FindNode(addrConnect.ToStringIPPort()))
return;
} else if (FindNode(std::string(pszDest)))
@@ -2386,24 +2211,6 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
DumpAddresses();
}
}
- if (clientInterface)
- clientInterface->InitMessage(_("Loading banlist..."));
- // Load addresses from banlist.dat
- nStart = GetTimeMillis();
- CBanDB bandb;
- banmap_t banmap;
- if (bandb.Read(banmap)) {
- SetBanned(banmap); // thread save setter
- SetBannedSetDirty(false); // no need to write down, just read data
- SweepBanned(); // sweep out unused entries
-
- LogPrint(BCLog::NET, "Loaded %d banned node ips/subnets from banlist.dat %dms\n",
- banmap.size(), GetTimeMillis() - nStart);
- } else {
- LogPrintf("Invalid or missing banlist.dat; recreating\n");
- SetBannedSetDirty(true); // force write
- DumpBanlist();
- }
uiInterface.InitMessage(_("Starting network threads..."));
@@ -2457,7 +2264,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
threadMessageHandler = std::thread(&TraceThread<std::function<void()> >, "msghand", std::function<void()>(std::bind(&CConnman::ThreadMessageHandler, this)));
// Dump network addresses
- scheduler.scheduleEvery(std::bind(&CConnman::DumpData, this), DUMP_ADDRESSES_INTERVAL * 1000);
+ scheduler.scheduleEvery(std::bind(&CConnman::DumpAddresses, this), DUMP_PEERS_INTERVAL * 1000);
return true;
}
@@ -2516,7 +2323,7 @@ void CConnman::Stop()
if (fAddressesInitialized)
{
- DumpData();
+ DumpAddresses();
fAddressesInitialized = false;
}
@@ -2643,6 +2450,25 @@ bool CConnman::DisconnectNode(const std::string& strNode)
}
return false;
}
+
+bool CConnman::DisconnectNode(const CSubNet& subnet)
+{
+ bool disconnected = false;
+ LOCK(cs_vNodes);
+ for (CNode* pnode : vNodes) {
+ if (subnet.Match(pnode->addr)) {
+ pnode->fDisconnect = true;
+ disconnected = true;
+ }
+ }
+ return disconnected;
+}
+
+bool CConnman::DisconnectNode(const CNetAddr& addr)
+{
+ return DisconnectNode(CSubNet(addr));
+}
+
bool CConnman::DisconnectNode(NodeId id)
{
LOCK(cs_vNodes);
@@ -2816,40 +2642,6 @@ CNode::~CNode()
CloseSocket(hSocket);
}
-void CNode::AskFor(const CInv& inv)
-{
- if (mapAskFor.size() > MAPASKFOR_MAX_SZ || setAskFor.size() > SETASKFOR_MAX_SZ)
- return;
- // a peer may not have multiple non-responded queue positions for a single inv item
- if (!setAskFor.insert(inv.hash).second)
- return;
-
- // We're using mapAskFor as a priority queue,
- // the key is the earliest time the request can be sent
- int64_t nRequestTime;
- limitedmap<uint256, int64_t>::const_iterator it = mapAlreadyAskedFor.find(inv.hash);
- if (it != mapAlreadyAskedFor.end())
- nRequestTime = it->second;
- else
- nRequestTime = 0;
- LogPrint(BCLog::NET, "askfor %s %d (%s) peer=%d\n", inv.ToString(), nRequestTime, FormatISO8601Time(nRequestTime/1000000), id);
-
- // Make sure not to reuse time indexes to keep things in the same order
- int64_t nNow = GetTimeMicros() - 1000000;
- static int64_t nLastTime;
- ++nLastTime;
- nNow = std::max(nNow, nLastTime);
- nLastTime = nNow;
-
- // Each retry is 2 minutes after the last
- nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow);
- if (it != mapAlreadyAskedFor.end())
- mapAlreadyAskedFor.update(it, nRequestTime);
- else
- mapAlreadyAskedFor.insert(std::make_pair(inv.hash, nRequestTime));
- mapAskFor.insert(std::make_pair(nRequestTime, inv));
-}
-
bool CConnman::NodeFullyConnected(const CNode* pnode)
{
return pnode && pnode->fSuccessfullyConnected && !pnode->fDisconnect;
diff --git a/src/net.h b/src/net.h
index a6a57821dc..f4a90e01f1 100644
--- a/src/net.h
+++ b/src/net.h
@@ -37,6 +37,7 @@
class CScheduler;
class CNode;
+class BanMan;
/** Time between pings automatically sent out for latency probing and keepalive (in seconds). */
static const int PING_INTERVAL = 2 * 60;
@@ -66,10 +67,6 @@ static const bool DEFAULT_UPNP = USE_UPNP;
#else
static const bool DEFAULT_UPNP = false;
#endif
-/** The maximum number of entries in mapAskFor */
-static const size_t MAPASKFOR_MAX_SZ = MAX_INV_SZ;
-/** The maximum number of entries in setAskFor (larger due to getdata latency)*/
-static const size_t SETASKFOR_MAX_SZ = 2 * MAX_INV_SZ;
/** The maximum number of peer connections to maintain. */
static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125;
/** The default for -maxuploadtarget. 0 = Unlimited */
@@ -85,9 +82,6 @@ static const bool DEFAULT_FORCEDNSSEED = false;
static const size_t DEFAULT_MAXRECEIVEBUFFER = 5 * 1000;
static const size_t DEFAULT_MAXSENDBUFFER = 1 * 1000;
-// NOTE: When adjusting this, update rpcnet:setban's help ("24h")
-static const unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; // Default 24-hour ban
-
typedef int64_t NodeId;
struct AddedNodeInfo
@@ -114,6 +108,7 @@ struct CSerializedNetMsg
std::string command;
};
+
class NetEventsInterface;
class CConnman
{
@@ -136,6 +131,7 @@ public:
int nBestHeight = 0;
CClientUIInterface* uiInterface = nullptr;
NetEventsInterface* m_msgproc = nullptr;
+ BanMan* m_banman = nullptr;
unsigned int nSendBufferMaxSize = 0;
unsigned int nReceiveFloodSize = 0;
uint64_t nMaxOutboundTimeframe = 0;
@@ -158,6 +154,7 @@ public:
nMaxFeeler = connOptions.nMaxFeeler;
nBestHeight = connOptions.nBestHeight;
clientInterface = connOptions.uiInterface;
+ m_banman = connOptions.m_banman;
m_msgproc = connOptions.m_msgproc;
nSendBufferMaxSize = connOptions.nSendBufferMaxSize;
nReceiveFloodSize = connOptions.nReceiveFloodSize;
@@ -177,7 +174,18 @@ public:
CConnman(uint64_t seed0, uint64_t seed1);
~CConnman();
bool Start(CScheduler& scheduler, const Options& options);
- void Stop();
+
+ // TODO: Remove NO_THREAD_SAFETY_ANALYSIS. Lock cs_vNodes before reading the variable vNodes.
+ //
+ // When removing NO_THREAD_SAFETY_ANALYSIS be aware of the following lock order requirements:
+ // * CheckForStaleTipAndEvictPeers locks cs_main before indirectly calling GetExtraOutboundCount
+ // which locks cs_vNodes.
+ // * ProcessMessage locks cs_main and g_cs_orphans before indirectly calling ForEachNode which
+ // locks cs_vNodes.
+ //
+ // Thus the implicit locking order requirement is: (1) cs_main, (2) g_cs_orphans, (3) cs_vNodes.
+ void Stop() NO_THREAD_SAFETY_ANALYSIS;
+
void Interrupt();
bool GetNetworkActive() const { return fNetworkActive; };
bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; };
@@ -238,30 +246,6 @@ public:
void AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0);
std::vector<CAddress> GetAddresses();
- // Denial-of-service detection/prevention
- // The idea is to detect peers that are behaving
- // badly and disconnect/ban them, but do it in a
- // one-coding-mistake-won't-shatter-the-entire-network
- // way.
- // IMPORTANT: There should be nothing I can give a
- // node that it will forward on that will make that
- // node's peers drop it. If there is, an attacker
- // can isolate a node and/or try to split the network.
- // Dropping a node for sending stuff that is invalid
- // now but might be valid in a later version is also
- // dangerous, because it can cause a network split
- // between nodes running old code and nodes running
- // new code.
- void Ban(const CNetAddr& netAddr, const BanReason& reason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
- void Ban(const CSubNet& subNet, const BanReason& reason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
- void ClearBanned(); // needed for unit testing
- bool IsBanned(CNetAddr ip);
- bool IsBanned(CSubNet subnet);
- bool Unban(const CNetAddr &ip);
- bool Unban(const CSubNet &ip);
- void GetBanned(banmap_t &banmap);
- void SetBanned(const banmap_t &banmap);
-
// This allows temporarily exceeding nMaxOutbound, with the goal of finding
// a peer that is better than all our current peers.
void SetTryNewOutboundPeer(bool flag);
@@ -282,6 +266,8 @@ public:
size_t GetNodeCount(NumConnections num);
void GetNodeStats(std::vector<CNodeStats>& vstats);
bool DisconnectNode(const std::string& node);
+ bool DisconnectNode(const CSubNet& subnet);
+ bool DisconnectNode(const CNetAddr& addr);
bool DisconnectNode(NodeId id);
ServiceFlags GetLocalServices() const;
@@ -294,17 +280,17 @@ public:
void SetMaxOutboundTimeframe(uint64_t timeframe);
uint64_t GetMaxOutboundTimeframe();
- //!check if the outbound target is reached
- // if param historicalBlockServingLimit is set true, the function will
- // response true if the limit for serving historical blocks has been reached
+ //! check if the outbound target is reached
+ //! if param historicalBlockServingLimit is set true, the function will
+ //! response true if the limit for serving historical blocks has been reached
bool OutboundTargetReached(bool historicalBlockServingLimit);
- //!response the bytes left in the current max outbound cycle
- // in case of no limit, it will always response 0
+ //! response the bytes left in the current max outbound cycle
+ //! in case of no limit, it will always response 0
uint64_t GetOutboundTargetBytesLeft();
- //!response the time in second left in the current max outbound cycle
- // in case of no limit, it will always response 0
+ //! response the time in second left in the current max outbound cycle
+ //! in case of no limit, it will always response 0
uint64_t GetMaxOutboundTimeLeftInCycle();
uint64_t GetTotalBytesRecv();
@@ -368,15 +354,7 @@ private:
NodeId GetNewNodeId();
size_t SocketSendData(CNode *pnode) const;
- //!check is the banlist has unwritten changes
- bool BannedSetIsDirty();
- //!set the "dirty" flag for the banlist
- void SetBannedSetDirty(bool dirty=true);
- //!clean unused entries (if bantime has expired)
- void SweepBanned();
void DumpAddresses();
- void DumpData();
- void DumpBanlist();
// Network stats
void RecordBytesRecv(uint64_t bytes);
@@ -409,16 +387,13 @@ private:
std::vector<ListenSocket> vhListenSocket;
std::atomic<bool> fNetworkActive{true};
- banmap_t setBanned GUARDED_BY(cs_setBanned);
- CCriticalSection cs_setBanned;
- bool setBannedIsDirty GUARDED_BY(cs_setBanned){false};
bool fAddressesInitialized{false};
CAddrMan addrman;
std::deque<std::string> vOneShots GUARDED_BY(cs_vOneShots);
CCriticalSection cs_vOneShots;
std::vector<std::string> vAddedNodes GUARDED_BY(cs_vAddedNodes);
CCriticalSection cs_vAddedNodes;
- std::vector<CNode*> vNodes;
+ std::vector<CNode*> vNodes GUARDED_BY(cs_vNodes);
std::list<CNode*> vNodesDisconnected;
mutable CCriticalSection cs_vNodes;
std::atomic<NodeId> nLastNodeId{0};
@@ -437,6 +412,7 @@ private:
std::atomic<int> nBestHeight;
CClientUIInterface* clientInterface;
NetEventsInterface* m_msgproc;
+ BanMan* m_banman;
/** SipHasher seeds for deterministic randomness */
const uint64_t nSeed0, nSeed1;
@@ -466,6 +442,7 @@ private:
friend struct CConnmanTest;
};
extern std::unique_ptr<CConnman> g_connman;
+extern std::unique_ptr<BanMan> g_banman;
void Discover();
void StartMapPort();
void InterruptMapPort();
@@ -544,8 +521,6 @@ extern bool fDiscover;
extern bool fListen;
extern bool fRelayTxes;
-extern limitedmap<uint256, int64_t> mapAlreadyAskedFor;
-
/** Subversion as sent to the P2P network in `version` messages */
extern std::string strSubVersion;
@@ -681,6 +656,7 @@ public:
// the network or wire types and the cleaned string used when displayed or logged.
std::string strSubVer GUARDED_BY(cs_SubVer), cleanSubVer GUARDED_BY(cs_SubVer);
CCriticalSection cs_SubVer; // used for both cleanSubVer and strSubVer
+ bool m_prefer_evict{false}; // This peer is preferred for eviction.
bool fWhitelisted{false}; // This peer can bypass DoS banning.
bool fFeeler{false}; // If true this node is being used as a short lived feeler.
bool fOneShot{false};
@@ -733,8 +709,6 @@ public:
// and in the order requested.
std::vector<uint256> vInventoryBlockToSend GUARDED_BY(cs_inventory);
CCriticalSection cs_inventory;
- std::set<uint256> setAskFor;
- std::multimap<int64_t, CInv> mapAskFor;
int64_t nNextInvSend{0};
// Used for headers announcements - unfiltered blocks to relay
std::vector<uint256> vBlockHashesToAnnounce GUARDED_BY(cs_inventory);
@@ -881,8 +855,6 @@ public:
vBlockHashesToAnnounce.push_back(hash);
}
- void AskFor(const CInv& inv);
-
void CloseSocketDisconnect();
void copyStats(CNodeStats &stats);
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 0e222bdfa4..5927a14a6e 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -6,6 +6,7 @@
#include <net_processing.h>
#include <addrman.h>
+#include <banman.h>
#include <arith_uint256.h>
#include <blockencodings.h>
#include <chainparams.h>
@@ -63,6 +64,21 @@ static constexpr int STALE_RELAY_AGE_LIMIT = 30 * 24 * 60 * 60;
/// Age after which a block is considered historical for purposes of rate
/// limiting block relay. Set to one week, denominated in seconds.
static constexpr int HISTORICAL_BLOCK_AGE = 7 * 24 * 60 * 60;
+/** Maximum number of in-flight transactions from a peer */
+static constexpr int32_t MAX_PEER_TX_IN_FLIGHT = 100;
+/** Maximum number of announced transactions from a peer */
+static constexpr int32_t MAX_PEER_TX_ANNOUNCEMENTS = 2 * MAX_INV_SZ;
+/** How many microseconds to delay requesting transactions from inbound peers */
+static constexpr int64_t INBOUND_PEER_TX_DELAY = 2 * 1000000;
+/** How long to wait (in microseconds) before downloading a transaction from an additional peer */
+static constexpr int64_t GETDATA_TX_INTERVAL = 60 * 1000000;
+/** Maximum delay (in microseconds) for transaction requests to avoid biasing some peers over others. */
+static constexpr int64_t MAX_GETDATA_RANDOM_DELAY = 2 * 1000000;
+static_assert(INBOUND_PEER_TX_DELAY >= MAX_GETDATA_RANDOM_DELAY,
+"To preserve security, MAX_GETDATA_RANDOM_DELAY should not exceed INBOUND_PEER_DELAY");
+/** Limit to avoid sending big packets. Not used in processing incoming GETDATA for compatibility */
+static const unsigned int MAX_GETDATA_SZ = 1000;
+
struct COrphanTx {
// When modifying, adapt the copy of this definition in tests/DoS_tests.
@@ -273,6 +289,66 @@ struct CNodeState {
//! Time of last new block announcement
int64_t m_last_block_announcement;
+ /*
+ * State associated with transaction download.
+ *
+ * Tx download algorithm:
+ *
+ * When inv comes in, queue up (process_time, txid) inside the peer's
+ * CNodeState (m_tx_process_time) as long as m_tx_announced for the peer
+ * isn't too big (MAX_PEER_TX_ANNOUNCEMENTS).
+ *
+ * The process_time for a transaction is set to nNow for outbound peers,
+ * nNow + 2 seconds for inbound peers. This is the time at which we'll
+ * consider trying to request the transaction from the peer in
+ * SendMessages(). The delay for inbound peers is to allow outbound peers
+ * a chance to announce before we request from inbound peers, to prevent
+ * an adversary from using inbound connections to blind us to a
+ * transaction (InvBlock).
+ *
+ * When we call SendMessages() for a given peer,
+ * we will loop over the transactions in m_tx_process_time, looking
+ * at the transactions whose process_time <= nNow. We'll request each
+ * such transaction that we don't have already and that hasn't been
+ * requested from another peer recently, up until we hit the
+ * MAX_PEER_TX_IN_FLIGHT limit for the peer. Then we'll update
+ * g_already_asked_for for each requested txid, storing the time of the
+ * GETDATA request. We use g_already_asked_for to coordinate transaction
+ * requests amongst our peers.
+ *
+ * For transactions that we still need but we have already recently
+ * requested from some other peer, we'll reinsert (process_time, txid)
+ * back into the peer's m_tx_process_time at the point in the future at
+ * which the most recent GETDATA request would time out (ie
+ * GETDATA_TX_INTERVAL + the request time stored in g_already_asked_for).
+ * We add an additional delay for inbound peers, again to prefer
+ * attempting download from outbound peers first.
+ * We also add an extra small random delay up to 2 seconds
+ * to avoid biasing some peers over others. (e.g., due to fixed ordering
+ * of peer processing in ThreadMessageHandler).
+ *
+ * When we receive a transaction from a peer, we remove the txid from the
+ * peer's m_tx_in_flight set and from their recently announced set
+ * (m_tx_announced). We also clear g_already_asked_for for that entry, so
+ * that if somehow the transaction is not accepted but also not added to
+ * the reject filter, then we will eventually redownload from other
+ * peers.
+ */
+ struct TxDownloadState {
+ /* Track when to attempt download of announced transactions (process
+ * time in micros -> txid)
+ */
+ std::multimap<int64_t, uint256> m_tx_process_time;
+
+ //! Store all the transactions a peer has recently announced
+ std::set<uint256> m_tx_announced;
+
+ //! Store transactions which were requested by us
+ std::set<uint256> m_tx_in_flight;
+ };
+
+ TxDownloadState m_tx_download;
+
CNodeState(CAddress addrIn, std::string addrNameIn) : address(addrIn), name(addrNameIn) {
fCurrentlyConnected = false;
nMisbehavior = 0;
@@ -300,6 +376,9 @@ struct CNodeState {
}
};
+// Keeps track of the time (in microseconds) when transactions were requested last time
+limitedmap<uint256, int64_t> g_already_asked_for GUARDED_BY(cs_main)(MAX_INV_SZ);
+
/** Map maintaining per-node state. */
static std::map<NodeId, CNodeState> mapNodeState GUARDED_BY(cs_main);
@@ -590,6 +669,58 @@ static void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vec
}
}
+void EraseTxRequest(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+{
+ g_already_asked_for.erase(txid);
+}
+
+int64_t GetTxRequestTime(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+{
+ auto it = g_already_asked_for.find(txid);
+ if (it != g_already_asked_for.end()) {
+ return it->second;
+ }
+ return 0;
+}
+
+void UpdateTxRequestTime(const uint256& txid, int64_t request_time) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+{
+ auto it = g_already_asked_for.find(txid);
+ if (it == g_already_asked_for.end()) {
+ g_already_asked_for.insert(std::make_pair(txid, request_time));
+ } else {
+ g_already_asked_for.update(it, request_time);
+ }
+}
+
+
+void RequestTx(CNodeState* state, const uint256& txid, int64_t nNow) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+{
+ CNodeState::TxDownloadState& peer_download_state = state->m_tx_download;
+ if (peer_download_state.m_tx_announced.size() >= MAX_PEER_TX_ANNOUNCEMENTS || peer_download_state.m_tx_announced.count(txid)) {
+ // Too many queued announcements from this peer, or we already have
+ // this announcement
+ return;
+ }
+ peer_download_state.m_tx_announced.insert(txid);
+
+ int64_t process_time;
+ int64_t last_request_time = GetTxRequestTime(txid);
+ // First time requesting this tx
+ if (last_request_time == 0) {
+ process_time = nNow;
+ } else {
+ // Randomize the delay to avoid biasing some peers over others (such as due to
+ // fixed ordering of peer processing in ThreadMessageHandler)
+ process_time = last_request_time + GETDATA_TX_INTERVAL + GetRand(MAX_GETDATA_RANDOM_DELAY);
+ }
+
+ // We delay processing announcements from non-preferred (eg inbound) peers
+ if (!state->fPreferredDownload) process_time += INBOUND_PEER_TX_DELAY;
+
+ peer_download_state.m_tx_process_time.emplace(process_time, txid);
+}
+
} // namespace
// This function is used for testing the stale tip eviction logic, see
@@ -841,9 +972,8 @@ static bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Para
(GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, consensusParams) < STALE_RELAY_AGE_LIMIT);
}
-PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn, CScheduler &scheduler, bool enable_bip61)
- : connman(connmanIn), m_stale_tip_check_time(0), m_enable_bip61(enable_bip61) {
-
+PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn, BanMan* banman, CScheduler &scheduler, bool enable_bip61)
+ : connman(connmanIn), m_banman(banman), m_stale_tip_check_time(0), m_enable_bip61(enable_bip61) {
// Initialize global variables that cannot be constructed at startup.
recentRejects.reset(new CRollingBloomFilter(120000, 0.000001));
@@ -1945,6 +2075,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
LOCK(cs_main);
uint32_t nFetchFlags = GetFetchFlags(pfrom);
+ int64_t nNow = GetTimeMicros();
for (CInv &inv : vInv)
{
@@ -1976,7 +2107,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (fBlocksOnly) {
LogPrint(BCLog::NET, "transaction (%s) inv sent in violation of protocol peer=%d\n", inv.hash.ToString(), pfrom->GetId());
} else if (!fAlreadyHave && !fImporting && !fReindex && !IsInitialBlockDownload()) {
- pfrom->AskFor(inv);
+ RequestTx(State(pfrom->GetId()), inv.hash, nNow);
}
}
}
@@ -2211,8 +2342,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
bool fMissingInputs = false;
CValidationState state;
- pfrom->setAskFor.erase(inv.hash);
- mapAlreadyAskedFor.erase(inv.hash);
+ CNodeState* nodestate = State(pfrom->GetId());
+ nodestate->m_tx_download.m_tx_announced.erase(inv.hash);
+ nodestate->m_tx_download.m_tx_in_flight.erase(inv.hash);
+ EraseTxRequest(inv.hash);
std::list<CTransactionRef> lRemovedTxn;
@@ -2303,10 +2436,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
}
if (!fRejectedParents) {
uint32_t nFetchFlags = GetFetchFlags(pfrom);
+ int64_t nNow = GetTimeMicros();
+
for (const CTxIn& txin : tx.vin) {
CInv _inv(MSG_TX | nFetchFlags, txin.prevout.hash);
pfrom->AddInventoryKnown(_inv);
- if (!AlreadyHave(_inv)) pfrom->AskFor(_inv);
+ if (!AlreadyHave(_inv)) RequestTx(State(pfrom->GetId()), _inv.hash, nNow);
}
AddOrphanTx(ptx, pfrom->GetId());
@@ -2943,7 +3078,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return true;
}
-static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman* connman, bool enable_bip61) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+bool PeerLogicValidation::SendRejectsAndCheckIfBanned(CNode* pnode, bool enable_bip61) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(cs_main);
CNodeState &state = *State(pnode->GetId());
@@ -2961,14 +3096,16 @@ static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman* connman, bool en
LogPrintf("Warning: not punishing whitelisted peer %s!\n", pnode->addr.ToString());
else if (pnode->m_manual_connection)
LogPrintf("Warning: not punishing manually-connected peer %s!\n", pnode->addr.ToString());
- else {
+ else if (pnode->addr.IsLocal()) {
+ // Disconnect but don't ban _this_ local node
+ LogPrintf("Warning: disconnecting but not banning local peer %s!\n", pnode->addr.ToString());
pnode->fDisconnect = true;
- if (pnode->addr.IsLocal())
- LogPrintf("Warning: not banning local peer %s!\n", pnode->addr.ToString());
- else
- {
- connman->Ban(pnode->addr, BanReasonNodeMisbehaving);
+ } else {
+ // Disconnect and ban all nodes sharing the address
+ if (m_banman) {
+ m_banman->Ban(pnode->addr, BanReasonNodeMisbehaving);
}
+ connman->DisconnectNode(pnode->addr);
}
return true;
}
@@ -3092,7 +3229,7 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
}
LOCK(cs_main);
- SendRejectsAndCheckIfBanned(pfrom, connman, m_enable_bip61);
+ SendRejectsAndCheckIfBanned(pfrom, m_enable_bip61);
return fMoreWork;
}
@@ -3293,8 +3430,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
if (!lockMain)
return true;
- if (SendRejectsAndCheckIfBanned(pto, connman, m_enable_bip61))
- return true;
+ if (SendRejectsAndCheckIfBanned(pto, m_enable_bip61)) return true;
CNodeState &state = *State(pto->GetId());
// Address refresh broadcast
@@ -3730,24 +3866,39 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
//
// Message: getdata (non-blocks)
//
- while (!pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow)
- {
- const CInv& inv = (*pto->mapAskFor.begin()).second;
- if (!AlreadyHave(inv))
- {
- LogPrint(BCLog::NET, "Requesting %s peer=%d\n", inv.ToString(), pto->GetId());
- vGetData.push_back(inv);
- if (vGetData.size() >= 1000)
- {
- connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
- vGetData.clear();
+ auto& tx_process_time = state.m_tx_download.m_tx_process_time;
+ while (!tx_process_time.empty() && tx_process_time.begin()->first <= nNow && state.m_tx_download.m_tx_in_flight.size() < MAX_PEER_TX_IN_FLIGHT) {
+ const uint256& txid = tx_process_time.begin()->second;
+ CInv inv(MSG_TX | GetFetchFlags(pto), txid);
+ if (!AlreadyHave(inv)) {
+ // If this transaction was last requested more than 1 minute ago,
+ // then request.
+ int64_t last_request_time = GetTxRequestTime(inv.hash);
+ if (last_request_time <= nNow - GETDATA_TX_INTERVAL) {
+ LogPrint(BCLog::NET, "Requesting %s peer=%d\n", inv.ToString(), pto->GetId());
+ vGetData.push_back(inv);
+ if (vGetData.size() >= MAX_GETDATA_SZ) {
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
+ vGetData.clear();
+ }
+ UpdateTxRequestTime(inv.hash, nNow);
+ state.m_tx_download.m_tx_in_flight.insert(inv.hash);
+ } else {
+ // This transaction is in flight from someone else; queue
+ // up processing to happen after the download times out
+ // (with a slight delay for inbound peers, to prefer
+ // requests to outbound peers).
+ RequestTx(&state, txid, nNow);
}
} else {
- //If we're not going to ask, don't expect a response.
- pto->setAskFor.erase(inv.hash);
+ // We have already seen this transaction, no need to download.
+ state.m_tx_download.m_tx_announced.erase(inv.hash);
+ state.m_tx_download.m_tx_in_flight.erase(inv.hash);
}
- pto->mapAskFor.erase(pto->mapAskFor.begin());
+ tx_process_time.erase(tx_process_time.begin());
}
+
+
if (!vGetData.empty())
connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
diff --git a/src/net_processing.h b/src/net_processing.h
index 0113e25f7e..39c22d7118 100644
--- a/src/net_processing.h
+++ b/src/net_processing.h
@@ -23,9 +23,11 @@ static constexpr bool DEFAULT_ENABLE_BIP61{false};
class PeerLogicValidation final : public CValidationInterface, public NetEventsInterface {
private:
CConnman* const connman;
+ BanMan* const m_banman;
+ bool SendRejectsAndCheckIfBanned(CNode* pnode, bool enable_bip61) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
public:
- explicit PeerLogicValidation(CConnman* connman, CScheduler &scheduler, bool enable_bip61);
+ PeerLogicValidation(CConnman* connman, BanMan* banman, CScheduler &scheduler, bool enable_bip61);
/**
* Overridden from CValidationInterface.
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index a0c7f8e3c2..58e45c2c02 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -182,16 +182,16 @@ bool CNetAddr::IsTor() const
bool CNetAddr::IsLocal() const
{
- // IPv4 loopback
- if (IsIPv4() && (GetByte(3) == 127 || GetByte(3) == 0))
- return true;
+ // IPv4 loopback (127.0.0.0/8 or 0.0.0.0/8)
+ if (IsIPv4() && (GetByte(3) == 127 || GetByte(3) == 0))
+ return true;
- // IPv6 loopback (::1/128)
- static const unsigned char pchLocal[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
- if (memcmp(ip, pchLocal, 16) == 0)
- return true;
+ // IPv6 loopback (::1/128)
+ static const unsigned char pchLocal[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
+ if (memcmp(ip, pchLocal, 16) == 0)
+ return true;
- return false;
+ return false;
}
bool CNetAddr::IsValid() const
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 355e21d4e6..6c386a9ade 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -80,11 +80,7 @@ bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsign
aiHint.ai_socktype = SOCK_STREAM;
aiHint.ai_protocol = IPPROTO_TCP;
aiHint.ai_family = AF_UNSPEC;
-#ifdef WIN32
- aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST;
-#else
aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
-#endif
struct addrinfo *aiRes = nullptr;
int nErr = getaddrinfo(pszName, nullptr, &aiHint, &aiRes);
if (nErr)
diff --git a/src/optional.h b/src/optional.h
new file mode 100644
index 0000000000..95a3b24d0a
--- /dev/null
+++ b/src/optional.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2017 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_OPTIONAL_H
+#define BITCOIN_OPTIONAL_H
+
+#include <utility>
+
+#include <boost/optional.hpp>
+
+//! Substitute for C++17 std::optional
+template <typename T>
+using Optional = boost::optional<T>;
+
+//! Substitute for C++17 std::make_optional
+template <typename T>
+Optional<T> MakeOptional(bool condition, T&& value)
+{
+ return boost::make_optional(condition, std::forward<T>(value));
+}
+
+//! Substitute for C++17 std::nullopt
+static auto& nullopt = boost::none;
+
+#endif // BITCOIN_OPTIONAL_H
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index c88d5b1ad3..f6f8e31363 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -298,7 +298,7 @@ public:
CTransaction();
/** Convert a CMutableTransaction into a CTransaction. */
- CTransaction(const CMutableTransaction &tx);
+ explicit CTransaction(const CMutableTransaction &tx);
CTransaction(CMutableTransaction &&tx);
template <typename Stream>
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index ca26131b95..d6c6fd6e98 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -218,6 +218,8 @@ BitcoinApplication::~BitcoinApplication()
#ifdef ENABLE_WALLET
delete paymentServer;
paymentServer = nullptr;
+ delete m_wallet_controller;
+ m_wallet_controller = nullptr;
#endif
delete optionsModel;
optionsModel = nullptr;
@@ -307,18 +309,20 @@ void BitcoinApplication::requestShutdown()
qDebug() << __func__ << ": Requesting shutdown";
startThread();
window->hide();
+ // Must disconnect node signals otherwise current thread can deadlock since
+ // no event loop is running.
+ window->unsubscribeFromCoreSignals();
+ // Request node shutdown, which can interrupt long operations, like
+ // rescanning a wallet.
+ m_node.startShutdown();
+ // Unsetting the client model can cause the current thread to wait for node
+ // to complete an operation, like wait for a RPC execution to complate.
window->setClientModel(nullptr);
pollShutdownTimer->stop();
-#ifdef ENABLE_WALLET
- delete m_wallet_controller;
- m_wallet_controller = nullptr;
-#endif
delete clientModel;
clientModel = nullptr;
- m_node.startShutdown();
-
// Request shutdown from core thread
Q_EMIT requestedShutdown();
}
@@ -452,7 +456,7 @@ int GuiMain(int argc, char* argv[])
// IMPORTANT if it is no longer a typedef use the normal variant above
qRegisterMetaType< CAmount >("CAmount");
qRegisterMetaType< std::function<void()> >("std::function<void()>");
-
+ qRegisterMetaType<QMessageBox::Icon>("QMessageBox::Icon");
/// 2. Parse command-line options. We do this after qt in order to show an error if there are problems parsing these
// Command-line options take precedence:
node->setupServerArgs();
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index d424c1ef2d..f7a4bad916 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -334,6 +334,10 @@ void BitcoinGUI::createActions()
openAction = new QAction(platformStyle->TextColorIcon(":/icons/open"), tr("Open &URI..."), this);
openAction->setStatusTip(tr("Open a bitcoin: URI or payment request"));
+ m_open_wallet_action = new QAction(tr("Open Wallet"), this);
+ m_open_wallet_action->setMenu(new QMenu(this));
+ m_open_wallet_action->setStatusTip(tr("Open a wallet"));
+
showHelpMessageAction = new QAction(platformStyle->TextColorIcon(":/icons/info"), 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(tr(PACKAGE_NAME)));
@@ -361,6 +365,37 @@ void BitcoinGUI::createActions()
connect(usedSendingAddressesAction, &QAction::triggered, walletFrame, &WalletFrame::usedSendingAddresses);
connect(usedReceivingAddressesAction, &QAction::triggered, walletFrame, &WalletFrame::usedReceivingAddresses);
connect(openAction, &QAction::triggered, this, &BitcoinGUI::openClicked);
+ connect(m_open_wallet_action->menu(), &QMenu::aboutToShow, [this] {
+ m_open_wallet_action->menu()->clear();
+ for (std::string path : m_wallet_controller->getWalletsAvailableToOpen()) {
+ QString name = path.empty() ? QString("["+tr("default wallet")+"]") : QString::fromStdString(path);
+ QAction* action = m_open_wallet_action->menu()->addAction(name);
+ connect(action, &QAction::triggered, [this, name, path] {
+ OpenWalletActivity* activity = m_wallet_controller->openWallet(path);
+
+ QProgressDialog* dialog = new QProgressDialog(this);
+ dialog->setLabelText(tr("Opening Wallet <b>%1</b>...").arg(name.toHtmlEscaped()));
+ dialog->setRange(0, 0);
+ dialog->setCancelButton(nullptr);
+ dialog->setWindowModality(Qt::ApplicationModal);
+ dialog->show();
+
+ connect(activity, &OpenWalletActivity::message, this, [this] (QMessageBox::Icon icon, QString text) {
+ QMessageBox box;
+ box.setIcon(icon);
+ box.setText(tr("Open Wallet Failed"));
+ box.setInformativeText(text);
+ box.setStandardButtons(QMessageBox::Ok);
+ box.setDefaultButton(QMessageBox::Ok);
+ connect(this, &QObject::destroyed, &box, &QDialog::accept);
+ box.exec();
+ });
+ connect(activity, &OpenWalletActivity::opened, this, &BitcoinGUI::setCurrentWallet);
+ connect(activity, &OpenWalletActivity::finished, activity, &QObject::deleteLater);
+ connect(activity, &OpenWalletActivity::finished, dialog, &QObject::deleteLater);
+ });
+ }
+ });
}
#endif // ENABLE_WALLET
@@ -382,6 +417,8 @@ void BitcoinGUI::createMenuBar()
QMenu *file = appMenuBar->addMenu(tr("&File"));
if(walletFrame)
{
+ file->addAction(m_open_wallet_action);
+ file->addSeparator();
file->addAction(openAction);
file->addAction(backupWalletAction);
file->addAction(signMessageAction);
@@ -484,6 +521,7 @@ void BitcoinGUI::createToolBars()
toolbar->addWidget(spacer);
m_wallet_selector = new QComboBox();
+ m_wallet_selector->setSizeAdjustPolicy(QComboBox::AdjustToContents);
connect(m_wallet_selector, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &BitcoinGUI::setCurrentWalletBySelectorIndex);
m_wallet_selector_label = new QLabel();
@@ -1225,16 +1263,18 @@ void BitcoinGUI::updateProxyIcon()
void BitcoinGUI::updateWindowTitle()
{
- QString window_title = tr(PACKAGE_NAME) + " - ";
+ QString window_title = tr(PACKAGE_NAME);
#ifdef ENABLE_WALLET
if (walletFrame) {
WalletModel* const wallet_model = walletFrame->currentWalletModel();
if (wallet_model && !wallet_model->getWalletName().isEmpty()) {
- window_title += wallet_model->getDisplayName() + " - ";
+ window_title += " - " + wallet_model->getDisplayName();
}
}
#endif
- window_title += m_network_style->getTitleAddText();
+ if (!m_network_style->getTitleAddText().isEmpty()) {
+ window_title += " - " + m_network_style->getTitleAddText();
+ }
setWindowTitle(window_title);
}
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index f1b76a6b64..c226494020 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -95,6 +95,9 @@ public:
*/
bool hasTrayIcon() const { return trayIcon; }
+ /** Disconnect core signals from GUI client */
+ void unsubscribeFromCoreSignals();
+
protected:
void changeEvent(QEvent *e);
void closeEvent(QCloseEvent *event);
@@ -144,6 +147,7 @@ private:
QAction* openRPCConsoleAction = nullptr;
QAction* openAction = nullptr;
QAction* showHelpMessageAction = nullptr;
+ QAction* m_open_wallet_action{nullptr};
QAction* m_wallet_selector_label_action = nullptr;
QAction* m_wallet_selector_action = nullptr;
@@ -184,8 +188,6 @@ private:
/** Connect core signals to GUI client */
void subscribeToCoreSignals();
- /** Disconnect core signals from GUI client */
- void unsubscribeFromCoreSignals();
/** Update UI with latest network info from model. */
void updateNetworkState();
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index de60b30dfe..dc997e96cc 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -30,8 +30,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Distributed under the MIT software license, see the accompanying file %s or "
"%s"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Error loading %s: You can't enable HD on an already existing non-HD wallet"),
-QT_TRANSLATE_NOOP("bitcoin-core", ""
"Error reading %s! All keys read correctly, but transaction data or address "
"book entries might be missing or incorrect."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -40,12 +38,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -"
"fallbackfee."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Group outputs by address, selecting all or none, instead of selecting on a "
-"per-output basis. Privacy is improved as an address is only used once "
-"(unless someone sends to it after spending from it), but may result in "
-"slightly higher fees as suboptimal coin selection may result due to the "
-"added limitation (default: %u)"),
-QT_TRANSLATE_NOOP("bitcoin-core", ""
"Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay "
"fee of %s to prevent stuck transactions)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -91,12 +83,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Unable to rewind the database to a pre-fork state. You will need to "
"redownload the blockchain"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Unsupported argument -socks found. Setting SOCKS version isn't possible "
-"anymore, only SOCKS5 proxies are supported."),
-QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/"
-"or -whitelistforcerelay."),
-QT_TRANSLATE_NOOP("bitcoin-core", ""
"Warning: Private keys detected in wallet {%s} with disabled private keys"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Warning: The network does not appear to fully agree! Some miners appear to "
@@ -122,18 +108,17 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Cannot downgrade wallet"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -%s address: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Cannot write to data directory '%s'; check permissions."),
QT_TRANSLATE_NOOP("bitcoin-core", "Change index out of range"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Config setting for %s only applied on %s network when in [%s] section."),
QT_TRANSLATE_NOOP("bitcoin-core", "Copyright (C) %i-%i"),
QT_TRANSLATE_NOOP("bitcoin-core", "Corrupted block database detected"),
QT_TRANSLATE_NOOP("bitcoin-core", "Do you want to rebuild the block database now?"),
QT_TRANSLATE_NOOP("bitcoin-core", "Done loading"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Error creating %s: You can't create non-HD wallets with this version."),
QT_TRANSLATE_NOOP("bitcoin-core", "Error initializing block database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error initializing wallet database environment %s!"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s: Private keys can only be disabled during creation"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s: Wallet corrupted"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s: Wallet requires newer version of %s"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s: You can't disable HD on an already existing HD wallet"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading block database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet %s. Duplicate -wallet filename specified."),
QT_TRANSLATE_NOOP("bitcoin-core", "Error opening block database"),
@@ -141,6 +126,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Error reading from database, shutting down.")
QT_TRANSLATE_NOOP("bitcoin-core", "Error upgrading chainstate database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: A fatal internal error occurred, see debug.log for details"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is low for %s"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is low!"),
QT_TRANSLATE_NOOP("bitcoin-core", "Failed to listen on any port. Use -listen=0 if you want this."),
QT_TRANSLATE_NOOP("bitcoin-core", "Failed to rescan the wallet during initialization"),
@@ -170,6 +156,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Reducing -maxconnections from %d to %d, becau
QT_TRANSLATE_NOOP("bitcoin-core", "Replaying blocks..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Rescanning..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Rewinding blocks..."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Section [%s] is not recognized."),
QT_TRANSLATE_NOOP("bitcoin-core", "Signing transaction failed"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specified -walletdir \"%s\" does not exist"),
QT_TRANSLATE_NOOP("bitcoin-core", "Specified -walletdir \"%s\" is a relative path"),
@@ -177,6 +164,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Specified -walletdir \"%s\" is not a director
QT_TRANSLATE_NOOP("bitcoin-core", "Specified blocks directory \"%s\" does not exist."),
QT_TRANSLATE_NOOP("bitcoin-core", "Starting network threads..."),
QT_TRANSLATE_NOOP("bitcoin-core", "The source code is available from %s."),
+QT_TRANSLATE_NOOP("bitcoin-core", "The specified config file %s does not exist\n"),
QT_TRANSLATE_NOOP("bitcoin-core", "The transaction amount is too small to pay the fee"),
QT_TRANSLATE_NOOP("bitcoin-core", "The wallet will avoid paying less than the minimum relay fee."),
QT_TRANSLATE_NOOP("bitcoin-core", "This is experimental software."),
@@ -195,9 +183,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Unable to generate initial keys"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to generate keys"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to start HTTP server. See debug log for details."),
QT_TRANSLATE_NOOP("bitcoin-core", "Unknown network specified in -onlynet: '%s'"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported argument -benchmark ignored, use -debug=bench."),
-QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported argument -debugnet ignored, use -debug=net."),
-QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported argument -tor found, use -onion."),
QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported logging category %s=%s."),
QT_TRANSLATE_NOOP("bitcoin-core", "Upgrading UTXO database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Upgrading txindex database"),
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 30d9e977b8..27b4c182f9 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -237,8 +237,8 @@ static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, int heig
clientmodel->cachedBestHeaderHeight = height;
clientmodel->cachedBestHeaderTime = blockTime;
}
- // if we are in-sync, update the UI regardless of last update time
- if (!initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) {
+ // if we are in-sync or if we notify a header update, update the UI regardless of last update time
+ if (fHeader || !initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) {
//pass an async signal to the UI thread
QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection,
Q_ARG(int, height),
diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui
index 8e8d436ce2..f0b976001e 100644
--- a/src/qt/forms/debugwindow.ui
+++ b/src/qt/forms/debugwindow.ui
@@ -453,6 +453,9 @@
</item>
<item>
<widget class="QComboBox" name="WalletSelector">
+ <property name="sizeAdjustPolicy">
+ <enum>QComboBox::AdjustToContents</enum>
+ </property>
<item>
<property name="text">
<string>(none)</string>
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index 507d195b72..240a7a7e92 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -121,7 +121,7 @@
<item>
<widget class="QLabel" name="databaseCacheUnitLabel">
<property name="text">
- <string>MB</string>
+ <string>MiB</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h
index 4d6006c582..736ff13a4a 100644
--- a/src/qt/guiconstants.h
+++ b/src/qt/guiconstants.h
@@ -52,4 +52,7 @@ static const int MAX_URI_LENGTH = 255;
#define QAPP_APP_NAME_TESTNET "Bitcoin-Qt-testnet"
#define QAPP_APP_NAME_REGTEST "Bitcoin-Qt-regtest"
+/* One gigabyte (GB) in bytes */
+static constexpr uint64_t GB_BYTES{1000000000};
+
#endif // BITCOIN_QT_GUICONSTANTS_H
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index b84c07d51a..ba0a5abdf3 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -21,10 +21,6 @@
#include <util/system.h>
#ifdef WIN32
-#ifdef _WIN32_WINNT
-#undef _WIN32_WINNT
-#endif
-#define _WIN32_WINNT 0x0501
#ifdef _WIN32_IE
#undef _WIN32_IE
#endif
@@ -683,13 +679,11 @@ bool SetStartOnSystemStartup(bool fAutoStart)
}
-#elif defined(Q_OS_MAC)
+#elif defined(Q_OS_MAC) && defined(MAC_OS_X_VERSION_MIN_REQUIRED) && MAC_OS_X_VERSION_MIN_REQUIRED <= 101100
// based on: https://github.com/Mozketo/LaunchAtLoginController/blob/master/LaunchAtLoginController.m
-LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl);
-LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl)
+LSSharedFileListItemRef findStartupItemInList(CFArrayRef listSnapshot, LSSharedFileListRef list, CFURLRef findUrl)
{
- CFArrayRef listSnapshot = LSSharedFileListCopySnapshot(list, nullptr);
if (listSnapshot == nullptr) {
return nullptr;
}
@@ -714,15 +708,12 @@ LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef
if(currentItemURL) {
if (CFEqual(currentItemURL, findUrl)) {
// found
- CFRelease(listSnapshot);
CFRelease(currentItemURL);
return item;
}
CFRelease(currentItemURL);
}
}
-
- CFRelease(listSnapshot);
return nullptr;
}
@@ -734,10 +725,12 @@ bool GetStartOnSystemStartup()
}
LSSharedFileListRef loginItems = LSSharedFileListCreate(nullptr, kLSSharedFileListSessionLoginItems, nullptr);
- LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, bitcoinAppUrl);
-
+ CFArrayRef listSnapshot = LSSharedFileListCopySnapshot(loginItems, nullptr);
+ bool res = (findStartupItemInList(listSnapshot, loginItems, bitcoinAppUrl) != nullptr);
CFRelease(bitcoinAppUrl);
- return !!foundItem; // return boolified object
+ CFRelease(loginItems);
+ CFRelease(listSnapshot);
+ return res;
}
bool SetStartOnSystemStartup(bool fAutoStart)
@@ -748,7 +741,8 @@ bool SetStartOnSystemStartup(bool fAutoStart)
}
LSSharedFileListRef loginItems = LSSharedFileListCreate(nullptr, kLSSharedFileListSessionLoginItems, nullptr);
- LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, bitcoinAppUrl);
+ CFArrayRef listSnapshot = LSSharedFileListCopySnapshot(loginItems, nullptr);
+ LSSharedFileListItemRef foundItem = findStartupItemInList(listSnapshot, loginItems, bitcoinAppUrl);
if(fAutoStart && !foundItem) {
// add bitcoin app to startup item list
@@ -760,6 +754,8 @@ bool SetStartOnSystemStartup(bool fAutoStart)
}
CFRelease(bitcoinAppUrl);
+ CFRelease(loginItems);
+ CFRelease(listSnapshot);
return true;
}
#pragma GCC diagnostic pop
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index 69972fce3b..499af9fa07 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -10,6 +10,7 @@
#include <qt/intro.h>
#include <qt/forms/ui_intro.h>
+#include <qt/guiconstants.h>
#include <qt/guiutil.h>
#include <interfaces/node.h>
@@ -21,7 +22,6 @@
#include <cmath>
-static const uint64_t GB_BYTES = 1000000000LL;
/* Total required space (in GB) depending on user choice (prune, not prune) */
static uint64_t requiredSpace;
diff --git a/src/qt/locale/bitcoin_af.ts b/src/qt/locale/bitcoin_af.ts
index bff2db1d6a..c7e7fdd56a 100644
--- a/src/qt/locale/bitcoin_af.ts
+++ b/src/qt/locale/bitcoin_af.ts
@@ -1205,6 +1205,10 @@
</context>
<context>
<name>QRImageWidget</name>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;Stoor beeld</translation>
+ </message>
</context>
<context>
<name>RPCConsole</name>
@@ -1364,6 +1368,10 @@
<translation>&amp;Boodslap:</translation>
</message>
<message>
+ <source>Clear all fields of the form.</source>
+ <translation>Vee alle velde op die vorm skoon</translation>
+ </message>
+ <message>
<source>Clear</source>
<translation>Skoonmaak</translation>
</message>
@@ -1399,10 +1407,18 @@
<translation>QR Kode</translation>
</message>
<message>
+ <source>Copy &amp;URI</source>
+ <translation>Kopieer &amp;URI</translation>
+ </message>
+ <message>
<source>Copy &amp;Address</source>
<translation>Kopieer &amp;Address</translation>
</message>
<message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;Stoor beeld</translation>
+ </message>
+ <message>
<source>Request payment to %1</source>
<translation>Versoek betaling van %1</translation>
</message>
@@ -1434,7 +1450,15 @@
<source>Wallet</source>
<translation>Beursie</translation>
</message>
- </context>
+ <message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation>Gevolglike URI te lank, probeer teks verkort vir etiket/boodskap</translation>
+ </message>
+ <message>
+ <source>Error encoding URI into QR Code.</source>
+ <translation>Fout met enkodering van URI na QR kode</translation>
+ </message>
+</context>
<context>
<name>RecentRequestsTableModel</name>
<message>
@@ -1521,6 +1545,20 @@
<translation>Kies...</translation>
</message>
<message>
+ <source>Using the fallbackfee can result in sending a transaction that will take several hours or days (or never) to confirm. Consider choosing your fee manually or wait until you have validated the complete chain.</source>
+ <translation>Die verstekfooi kan veroorsaak dat 'n transaksie gestuur word wat
+etlike ure of dae (of nooit) sal neem om te bevestig. Oorweeg om
+'n fooi met die hand te kies, of wag tot jy die hele ketting bevestig het.</translation>
+ </message>
+ <message>
+ <source>Warning: Fee estimation is currently not possible.</source>
+ <translation>Waarskuwing: fooiskatting is tans onbeskikbaar</translation>
+ </message>
+ <message>
+ <source>collapse fee-settings</source>
+ <translation>Vou fooi-nistellings in</translation>
+ </message>
+ <message>
<source>per kilobyte</source>
<translation>per kilogreep</translation>
</message>
@@ -1529,6 +1567,13 @@
<translation>Versteek</translation>
</message>
<message>
+ <source>Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks. But be aware that this can end up in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source>
+ <translation>Om die minimumfooi te betaal is in die haak, mits daar minder transaksievolume
+as ruimte in die blok is. Wees bewus dat de gevolg kan wees dat 'n transaksie nooit
+bevestig nie indien daar meer aanvraag vir bitcoin transaksies is as wat die netwerk kan
+verwerk.</translation>
+ </message>
+ <message>
<source>Recommended:</source>
<translation>Aanbeveel:</translation>
</message>
@@ -1537,14 +1582,40 @@
<translation>Aangepaste:</translation>
</message>
<message>
+ <source>(Smart fee not initialized yet. This usually takes a few blocks...)</source>
+ <translation>(Slimfooi nog nie opgestel nie. Dit neem gewoonlik 'n paar blokke...)</translation>
+ </message>
+ <message>
+ <source>Send to multiple recipients at once</source>
+ <translation>Stuur aan veelvuldige ontvangers tegelyk</translation>
+ </message>
+ <message>
<source>Add &amp;Recipient</source>
<translation>Voeg by &amp;Ontvanger</translation>
</message>
<message>
+ <source>Clear all fields of the form.</source>
+ <translation>Vee alle velde op die vorm skoon</translation>
+ </message>
+ <message>
<source>Dust:</source>
<translation>Stof:</translation>
</message>
<message>
+ <source>Confirmation time target:</source>
+ <translation>Bevestigingstyd teiken:</translation>
+ </message>
+ <message>
+ <source>Enable Replace-By-Fee</source>
+ <translation>Bemontlik vervang-deur-fooi</translation>
+ </message>
+ <message>
+ <source>With Replace-By-Fee (BIP-125) you can increase a transaction's fee after it is sent. Without this, a higher fee may be recommended to compensate for increased transaction delay risk.</source>
+ <translation>Met Vervang-Met-Fooi (BIP-125) kan jy 'n transaskiefooi verhoog nadat dit gestuur is.
+Daarsonder mag 'n hoër fooi dalk aanbeveel word om te kompenseer vir 'n verhoogde
+transaksievertragingsrisiko.</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>Maak skoon &amp;Alles</translation>
</message>
@@ -1553,6 +1624,10 @@
<translation>Balans:</translation>
</message>
<message>
+ <source>Confirm the send action</source>
+ <translation>Bevestig stuuraksie</translation>
+ </message>
+ <message>
<source>S&amp;end</source>
<translation>S&amp;tuur</translation>
</message>
@@ -1593,14 +1668,80 @@
<translation>%1 tot %2</translation>
</message>
<message>
+ <source>Are you sure you want to send?</source>
+ <translation>Is u seker u wil verstuur?</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>of</translation>
+ </message>
+ <message>
+ <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source>
+ <translation>U kan die fooi later verhoog (sein Vervang-met-Fooi, BIP-125)</translation>
+ </message>
+ <message>
<source>Transaction fee</source>
<translation>Transaksie fooi</translation>
</message>
<message>
+ <source>Not signalling Replace-By-Fee, BIP-125.</source>
+ <translation>Sein nie Vervang-Met-Fooi nie, BIP-25</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>Bevestig versending van munte</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>Die ontvangeradres is ongeldig. Kyk asseblief weer mooi.</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation>Bedrag moet groter as nul wees</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation>Die bedrag oorskry jou saldo</translation>
+ </message>
+ <message>
+ <source>The total exceeds your balance when the %1 transaction fee is included.</source>
+ <translation>Die somtotaal oorskry jou saldo as die %1 transaksiefooi ingereken word</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>Duplikaatadres: adresse behoort slegs eenkeer gebruik te word</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <translation>Transaksieopstelling het gefaal</translation>
+ </message>
+ <message>
+ <source>The transaction was rejected with the following reason: %1</source>
+ <translation>Die transaksie is afgekeur met die volgende rede: %1</translation>
+ </message>
+ <message>
+ <source>A fee higher than %1 is considered an absurdly high fee.</source>
+ <translation>'n Fooi hoër as %1 word as buitensporig beskou</translation>
+ </message>
+ <message>
<source>Payment request expired.</source>
<translation>Betalings versoek verstryk.</translation>
</message>
<message>
+ <source>Pay only the required fee of %1</source>
+ <translation>Betaal slegs die verlangde fooi van %1</translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>Waarskuwing: Ongeldige Bitcoinadres</translation>
+ </message>
+ <message>
+ <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
+ <translation>Die adres wat u gekies het vir verandering is nie deel van hierdie
+beursie nie. Enige of alle fondse mag dalk daarheen gestuur word.
+Is u seker?</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(geen etiket)</translation>
</message>
@@ -1616,14 +1757,57 @@
<translation>&amp;Etiket:</translation>
</message>
<message>
+ <source>Choose previously used address</source>
+ <translation>Kies voorhen gebruikte adres</translation>
+ </message>
+ <message>
+ <source>This is a normal payment.</source>
+ <translation>Hierdie is 'n gewone betaling</translation>
+ </message>
+ <message>
+ <source>The Bitcoin address to send the payment to</source>
+ <translation>Die Bitcoinadres waarheen die betaling gestuur word</translation>
+ </message>
+ <message>
<source>Alt+A</source>
<translation>Alt+A</translation>
</message>
<message>
+ <source>Paste address from clipboard</source>
+ <translation>Plak adres van aanknipbord af</translation>
+ </message>
+ <message>
+ <source>Remove this entry</source>
+ <translation>Verwyder hierdie inskrywing</translation>
+ </message>
+ <message>
+ <source>The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally.</source>
+ <translation>De fooi word afgetrek van die gestuurde bedrag.
+Die ontvanger sal minder ontvang as wat u in die
+bedrag opgee. As daar meer as een ontvanger is,
+word die fooi eweredig verdeel.</translation>
+ </message>
+ <message>
+ <source>S&amp;ubtract fee from amount</source>
+ <translation>Bedrag &amp;Sonder fooi </translation>
+ </message>
+ <message>
+ <source>Use available balance</source>
+ <translation>Gebruik beskikbare saldo</translation>
+ </message>
+ <message>
<source>Message:</source>
<translation>Boodskap:</translation>
</message>
<message>
+ <source>This is an unauthenticated payment request.</source>
+ <translation>Hierdie is 'n ongemagtigde uitbetalingsversoek</translation>
+ </message>
+ <message>
+ <source>This is an authenticated payment request.</source>
+ <translation>Hierdie is 'n gemagtigde uitbetalingsversoek</translation>
+ </message>
+ <message>
<source>Pay To:</source>
<translation>Betaal Vir:</translation>
</message>
@@ -1645,10 +1829,18 @@
<translation>&amp;Teken Boodskap</translation>
</message>
<message>
+ <source>Choose previously used address</source>
+ <translation>Kies voorhen gebruikte adres</translation>
+ </message>
+ <message>
<source>Alt+A</source>
<translation>Alt+A</translation>
</message>
<message>
+ <source>Paste address from clipboard</source>
+ <translation>Plak adres van aanknipbord af</translation>
+ </message>
+ <message>
<source>Signature</source>
<translation>Handtekening</translation>
</message>
@@ -1978,4 +2170,4 @@
<translation>Fout</translation>
</message>
</context>
-</TS> \ No newline at end of file
+</TS>
diff --git a/src/qt/locale/bitcoin_af_ZA.ts b/src/qt/locale/bitcoin_af_ZA.ts
index b3e9acca9d..4f31d4cd62 100644
--- a/src/qt/locale/bitcoin_af_ZA.ts
+++ b/src/qt/locale/bitcoin_af_ZA.ts
@@ -227,6 +227,10 @@
<context>
<name>BanTableModel</name>
<message>
+ <source>IP/Netmask</source>
+ <translation>IP/Netmasker</translation>
+ </message>
+ <message>
<source>Banned Until</source>
<translation>Verban Tot</translation>
</message>
@@ -330,6 +334,14 @@
<translation>Klik om netwerk aktiwiteit weer aan te skakel.</translation>
</message>
<message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Sinkroniseer tans Hoofde (%1%)...</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk...</source>
+ <translation>Herindekseer blokke op skyf...</translation>
+ </message>
+ <message>
<source>Send coins to a Bitcoin address</source>
<translation>Stuur muntstukke na 'n Bitcoin adres</translation>
</message>
@@ -346,6 +358,10 @@
<translation>&amp;Ontfoutvenster</translation>
</message>
<message>
+ <source>Open debugging and diagnostic console</source>
+ <translation>Open ontfouting en diagnostiese konsole</translation>
+ </message>
+ <message>
<source>&amp;Verify message...</source>
<translation>&amp;Verifieer boodskap...</translation>
</message>
@@ -414,10 +430,22 @@
<translation>Wys die lys van gebruikte ontvangsadresse en etikette</translation>
</message>
<message>
+ <source>Open a bitcoin: URI or payment request</source>
+ <translation>Open 'n bitcoin: URI of betalingsversoek</translation>
+ </message>
+ <message>
<source>&amp;Command-line options</source>
<translation>&amp;Opdrag lys opsies</translation>
</message>
<message>
+ <source>Indexing blocks on disk...</source>
+ <translation>Indekseer tans blokke op skyf...</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk...</source>
+ <translation>Prosesseer tans blokke op skyf...</translation>
+ </message>
+ <message>
<source>%1 behind</source>
<translation>%1 agter</translation>
</message>
@@ -426,6 +454,10 @@
<translation>Ontvangs van laaste blok is %1 terug.</translation>
</message>
<message>
+ <source>Transactions after this will not yet be visible.</source>
+ <translation>Opvolgende transaksies sal nog nie sigbaar wees nie.</translation>
+ </message>
+ <message>
<source>Error</source>
<translation>Fout</translation>
</message>
@@ -442,10 +474,18 @@
<translation>Op datum</translation>
</message>
<message>
+ <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <translation>Wys die %1 hulpboodskap om 'n lys met moontlike Bitcoin bevel-lyn opsies te verkry</translation>
+ </message>
+ <message>
<source>%1 client</source>
<translation>%1 klient</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>Verbind tans aan eweknieë...</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Besig om op te vang...</translation>
</message>
@@ -468,12 +508,22 @@
</translation>
</message>
<message>
+ <source>Label: %1
+</source>
+ <translation>Etiket: %1
+</translation>
+ </message>
+ <message>
<source>Address: %1
</source>
<translation>Adres: %1
</translation>
</message>
<message>
+ <source>Sent transaction</source>
+ <translation>Gestuurde transaksie</translation>
+ </message>
+ <message>
<source>Incoming transaction</source>
<translation>Inkomende transaksie</translation>
</message>
@@ -493,7 +543,11 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Beursie is &lt;b&gt;versleutel&lt;/b&gt; en is tans &lt;b&gt;gesluit&lt;/b&gt;</translation>
</message>
- </context>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>'n Noodlottige fout het voorgekom. Bitcoin kan nie langer voortgaan nie en sal afsluit.</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -521,10 +575,18 @@
<translation>Stof:</translation>
</message>
<message>
+ <source>After Fee:</source>
+ <translation>Na Fooi:</translation>
+ </message>
+ <message>
<source>Change:</source>
<translation>Verander:</translation>
</message>
<message>
+ <source>(un)select all</source>
+ <translation>(on)selekteer alles</translation>
+ </message>
+ <message>
<source>Tree mode</source>
<translation>Boom wyse</translation>
</message>
@@ -617,6 +679,14 @@
<translation>nee</translation>
</message>
<message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation>Hierdie etiket verander na rooi as enige ontvanger 'n bedrag kleiner as die huidige stof drempelwaarde ontvang.</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Kan wissel met +/- %1 satoshi(s) per inset.</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(geen etiket)</translation>
</message>
@@ -640,6 +710,14 @@
<translation>&amp;Etiket</translation>
</message>
<message>
+ <source>The label associated with this address list entry</source>
+ <translation>Die etiket geassosieer met hierdie adreslys inskrywing</translation>
+ </message>
+ <message>
+ <source>The address associated with this address list entry. This can only be modified for sending addresses.</source>
+ <translation>Die adres geassosieer met hierdie adreslys inskrywing. Dié kan slegs gewysig word vir stuur-adresse.</translation>
+ </message>
+ <message>
<source>&amp;Address</source>
<translation>&amp;Adres</translation>
</message>
@@ -656,6 +734,10 @@
<translation>Wysig stuurende adres</translation>
</message>
<message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>Die ingeskrewe adres "%1" is nie 'n geldige Bitcoin adres nie.</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation>Kon nie die beursie oopsluit nie.</translation>
</message>
@@ -679,6 +761,10 @@
<translation>Lêer bestaan reeds. Voeg %1 indien u van plan is om n nuwe lêer hier te skep.</translation>
</message>
<message>
+ <source>Path already exists, and is not a directory.</source>
+ <translation>Pad bestaan reeds en is nie 'n lêergids nie.</translation>
+ </message>
+ <message>
<source>Cannot create data directory here.</source>
<translation>Kan nie data gids hier skep nie.</translation>
</message>
@@ -971,6 +1057,10 @@
<translation>Fooi:</translation>
</message>
<message>
+ <source>After Fee:</source>
+ <translation>Na Fooi:</translation>
+ </message>
+ <message>
<source>Change:</source>
<translation>Verander:</translation>
</message>
diff --git a/src/qt/locale/bitcoin_am.ts b/src/qt/locale/bitcoin_am.ts
new file mode 100644
index 0000000000..46942066e2
--- /dev/null
+++ b/src/qt/locale/bitcoin_am.ts
@@ -0,0 +1,451 @@
+<TS language="am" version="2.1">
+<context>
+ <name>AddressBookPage</name>
+ <message>
+ <source>Right-click to edit address or label</source>
+ <translation>አድራሻ ወይም መለያ ስም ለመቀየር ቀኙን ጠቅ ያድርጉ</translation>
+ </message>
+ <message>
+ <source>Create a new address</source>
+ <translation>አዲስ አድራሻ ፍጠር</translation>
+ </message>
+ <message>
+ <source>&amp;New</source>
+ <translation>&amp;አዲስ</translation>
+ </message>
+ <message>
+ <source>Copy the currently selected address to the system clipboard</source>
+ <translation>አሁን የተመረጠውን አድራሻ ወደ ሲስተሙ ቅንጥብ ሰሌዳ ቅዳ</translation>
+ </message>
+ <message>
+ <source>&amp;Copy</source>
+ <translation>&amp;ቅዳ</translation>
+ </message>
+ <message>
+ <source>C&amp;lose</source>
+ <translation>ዝጋ</translation>
+ </message>
+ <message>
+ <source>Delete the currently selected address from the list</source>
+ <translation>አሁን የተመረጠውን አድራሻ ከዝርዝሩ ውስጥ ሰርዝ</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>በአሁኑ ማውጫ ውስጥ ያለውን መረጃ ወደ አንድ ፋይል ላክ</translation>
+ </message>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;ላክ</translation>
+ </message>
+ <message>
+ <source>&amp;Delete</source>
+ <translation>&amp;ሰርዝ</translation>
+ </message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>ገንዘብ/ኮይኖች የሚልኩለትን አድራሻ ይምረጡ</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>ገንዘብ/ኮይኖች የሚቀበሉበትን አድራሻ ይምረጡ</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>ምረጥ</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>የመላኪያ አድራሻዎች</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>የመቀበያ አድራሻዎች</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
+ <translation>እነኚ የቢትኮይን ክፍያ የመላኪያ አድራሻዎችዎ ናቸው:: ገንዘብ/ኮይኖች ከመላክዎ በፊት መጠኑን እና የመቀበያ አድራሻውን ሁልጊዜ ያረጋግጡ::</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source>
+ <translation>እነኚ የቢትኮይን ክፍያ የመቀበያ አድራሻዎችዎ ናቸው:: ለእያንዳንዱ ግብይት አዲስ የመቀበያ አድራሻ እንዲጠቀሙ ይመከራል:: </translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;አድራሻ ቅዳ</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>ቅዳ &amp;መለያ ስም</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation> &amp;ቀይር</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>የአድራሻ ዝርዝር ላክ</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>ኮማ ሴፓሬትድ ፋይል (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>ወደ ውጪ መላክ አልተሳካም</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>የአድራሻ ዝርዝሩን ወደ %1 ለማስቀመጥ ሲሞከር ስህተት አጋጥሟል:: እባክዎ መልሰው ይሞክሩ::</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>መለያ ስም</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>አድራሻ</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(መለያ ስም የለም)</translation>
+ </message>
+</context>
+<context>
+ <name>AskPassphraseDialog</name>
+ <message>
+ <source>Passphrase Dialog</source>
+ <translation>የይለፍ-ሐረግ ንግግር</translation>
+ </message>
+ <message>
+ <source>Enter passphrase</source>
+ <translation>የይለፍ-ሐረግዎን ያስገቡ</translation>
+ </message>
+ <message>
+ <source>New passphrase</source>
+ <translation>አዲስ የይለፍ-ሐረግ</translation>
+ </message>
+ <message>
+ <source>Repeat new passphrase</source>
+ <translation>አዲስ የይለፍ-ሐረጉን ይድገሙት</translation>
+ </message>
+ <message>
+ <source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;ten or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
+ <translation>አዲስ የይለፍ ሐረግዎን ወደ ቢትኮይን ቦርሳዎ ያስገቡ:: &lt;br/&gt;እባክዎ ለየይለፍ ሐረግዎ&lt;b&gt;አስር ወይም ከዚያ በላይ የዘፈቀደ ዓይነተ-ፊደላት&lt;/b&gt;, ወይም&lt;b&gt;ስምንት ወይም ከዚያ በላይ ቃላት&lt;/b&gt; ይጠቀሙ ::</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>የቢትኮይን ቦርሳውን አመስጥር</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>ይህ ክንዋኔ የቢትኮይን ቦርሳዎን ለመክፈት የቦርሳዎ ይለፍ-ሐረግ ያስፈልገዋል::</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>የቢትኮይን ቦርሳውን ክፈት</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>ይህ ክንዋኔ የቢትኮይን ቦርሳዎን ለመፍታት የቦርሳዎ ይለፍ-ሐረግ ያስፈልገዋል::</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>የቢትኮይን ቦርሳውን ፍታ</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>ይለፍ-ሐረግ ለውጥ</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>የድሮውን የይለፍ-ሐረግ እና አዲሱን የይለፍ-ሐረግ ወደ ቢትኮይን ቦርሳዎ ያስገቡ::</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>የቢትኮይን ቦርሳዎን ማመስጠር ያረጋግጡ</translation>
+ </message>
+ <message>
+ <source>Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
+ <translation>ማስጠንቀቂያ: የቢትኮይን ቦርሳዎን አመስጥረው የይለፍ-ሐረግዎን ካጡት&lt;b&gt;ቢትኮይኖቾን በሙሉ ያጣሉ&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>እርግጠኛ ነዎት ቦርሳዎን ማመስጠር ይፈልጋሉ?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>ቦርሳዎ ምስጢር ተደርጓል</translation>
+ </message>
+ <message>
+ <source>%1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
+ <translation>%1 የማመስጠር ሂደቱን ለመጨረስ አሁን ይዘጋል:: ያስታውሱ፣ ኮምፒተርዎ በተንኮል አዘል ሶፍትዌር ከተበከለ ቦርሳዎን ማመስጠር ቢትኮይኖቾን ሙሉበሙሉ እንዳይሰረቁ ሊከላከል አይችልም::</translation>
+ </message>
+ <message>
+ <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
+ <translation>አስፈላጊ: ከ ቦርሳ ፋይልዎ ያከናወኗቸው ቀደም ያሉ ምትኬዎች በአዲስ በተፈጠረ የማመስጠሪያ ፋይል ውስጥ መተካት አለባቸው. ለደህንነት ሲባል, አዲሱን የተመሰጠ የቦርሳ ፋይል መጠቀም ሲጀመሩ ወዲያውኑ ቀደም ሲል ያልተመሰጠሩ የቦርሳ ፋይል ቅጂዎች ዋጋ ቢስ ይሆናሉ::</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>የቦርሳ ማመስጠር አልተሳካም</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>የቦርሳ ማመስጠር በውስጣዊ ስህተት ምክንያት አልተሳካም:: ቦርሳዎ አልተመሰጠረም::</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>የተሰጡት የይለፍ-ሐረግዎች አይዛመዱም::</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>ቦርሳ መክፈት አልተሳካም</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>ቦርሳ ለመፍታት ያስገቡት የይለፍ-ሐረግ ትክክል አልነበረም::</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>ቦርሳ መፍታት አልተሳካም </translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>የቦርሳ የይለፍ-ሐረግ በተሳካ ሁኔታ ተቀይሯል.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>ማስጠንቀቂያ: የ "Caps Lock" ቁልፍ በርቷል!</translation>
+ </message>
+</context>
+<context>
+ <name>BanTableModel</name>
+ <message>
+ <source>IP/Netmask</source>
+ <translation>አይፒ/ኔትማስክ IP/Netmask</translation>
+ </message>
+ <message>
+ <source>Banned Until</source>
+ <translation>ታግደዋል እስከ</translation>
+ </message>
+</context>
+<context>
+ <name>BitcoinGUI</name>
+ <message>
+ <source>Sign &amp;message...</source>
+ <translation>ምልክትና መልእክት...</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network...</source>
+ <translation>ከኔትወርክ ጋራ በማመሳሰል ላይ ነው...</translation>
+ </message>
+ <message>
+ <source>&amp;Overview</source>
+ <translation>&amp;አጠቃላይ እይታ</translation>
+ </message>
+ <message>
+ <source>Node</source>
+ <translation>እትር</translation>
+ </message>
+ <message>
+ <source>Show general overview of wallet</source>
+ <translation>የቦርሳ አጠቃላይ እይታ ኣሳይ</translation>
+ </message>
+ <message>
+ <source>&amp;Transactions</source>
+ <translation>&amp;ግብይቶች</translation>
+ </message>
+ <message>
+ <source>Browse transaction history</source>
+ <translation>የግብይት ታሪክ ያስሱ</translation>
+ </message>
+ <message>
+ <source>E&amp;xit</source>
+ <translation>ውጣ</translation>
+ </message>
+ <message>
+ <source>Quit application</source>
+ <translation>አፕሊኬሽኑን አቁም</translation>
+ </message>
+ <message>
+ <source>&amp;About %1</source>
+ <translation>&amp;ስለ %1</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation>ስለ %1 መረጃ አሳይ</translation>
+ </message>
+ <message>
+ <source>About &amp;Qt</source>
+ <translation>ስለ &amp;Qt</translation>
+ </message>
+ <message>
+ <source>Show information about Qt</source>
+ <translation>ስለ Qt መረጃ አሳይ</translation>
+ </message>
+ <message>
+ <source>&amp;Options...</source>
+ <translation>&amp;አማራጮች...</translation>
+ </message>
+ </context>
+<context>
+ <name>CoinControlDialog</name>
+ <message>
+ <source>(no label)</source>
+ <translation>(መለያ ስም የለም)</translation>
+ </message>
+ </context>
+<context>
+ <name>EditAddressDialog</name>
+ </context>
+<context>
+ <name>FreespaceChecker</name>
+ </context>
+<context>
+ <name>HelpMessageDialog</name>
+ </context>
+<context>
+ <name>Intro</name>
+ </context>
+<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
+ <name>OpenURIDialog</name>
+ </context>
+<context>
+ <name>OptionsDialog</name>
+ </context>
+<context>
+ <name>OverviewPage</name>
+ </context>
+<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
+ <name>PeerTableModel</name>
+ </context>
+<context>
+ <name>QObject</name>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
+ <name>RPCConsole</name>
+ </context>
+<context>
+ <name>ReceiveCoinsDialog</name>
+ </context>
+<context>
+ <name>ReceiveRequestDialog</name>
+ <message>
+ <source>Address</source>
+ <translation>አድራሻ</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>መለያ ስም</translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>መለያ ስም</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(መለያ ስም የለም)</translation>
+ </message>
+ </context>
+<context>
+ <name>SendCoinsDialog</name>
+ <message>
+ <source>(no label)</source>
+ <translation>(መለያ ስም የለም)</translation>
+ </message>
+</context>
+<context>
+ <name>SendCoinsEntry</name>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
+ <name>ShutdownWindow</name>
+ </context>
+<context>
+ <name>SignVerifyMessageDialog</name>
+ </context>
+<context>
+ <name>SplashScreen</name>
+ </context>
+<context>
+ <name>TrafficGraphWidget</name>
+ </context>
+<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
+ <name>TransactionDescDialog</name>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>መለያ ስም</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(መለያ ስም የለም)</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>ኮማ ሴፓሬትድ ፋይል (*.csv)</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>መለያ ስም</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>አድራሻ</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>ወደ ውጪ መላክ አልተሳካም</translation>
+ </message>
+ </context>
+<context>
+ <name>UnitDisplayStatusBarControl</name>
+ </context>
+<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;ላክ</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>በአሁኑ ማውጫ ውስጥ ያለውን መረጃ ወደ አንድ ፋይል ላክ</translation>
+ </message>
+ </context>
+<context>
+ <name>bitcoin-core</name>
+ </context>
+</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_ar.ts b/src/qt/locale/bitcoin_ar.ts
index 481e02c60e..d176505ac3 100644
--- a/src/qt/locale/bitcoin_ar.ts
+++ b/src/qt/locale/bitcoin_ar.ts
@@ -2936,6 +2936,11 @@
<translation>يرجى المساهمة إذا وجدت %s مفيداً. تفضل بزيارة %s لمزيد من المعلومات حول البرنامج.</translation>
</message>
<message>
+ <source>%s corrupt, salvage failed</source>
+ <translation>
+%s تالف, فشل الانقاذ.</translation>
+ </message>
+ <message>
<source>Change index out of range</source>
<translation>فهرس الفكة خارج النطاق</translation>
</message>
@@ -2960,6 +2965,18 @@
<translation>خطأ في تحميل %s</translation>
</message>
<message>
+ <source>Error loading %s: Private keys can only be disabled during creation</source>
+ <translation>خطأ في تحميل %s: لا يمكن تعطيل المفاتيح الخاصة إلا أثناء الإنشاء.</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet corrupted</source>
+ <translation>خطأ في التحميل %s: المحفظة تالفة.</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet requires newer version of %s</source>
+ <translation>خطا تحميل %s: المحفظة تتطلب النسخة الجديدة من %s.</translation>
+ </message>
+ <message>
<source>Error loading block database</source>
<translation>خطأ في تحميل قاعدة بيانات الكتل</translation>
</message>
@@ -2976,6 +2993,10 @@
<translation>فشل في الاستماع على أي منفذ. استخدام الاستماع = 0 إذا كنت تريد هذا.</translation>
</message>
<message>
+ <source>Failed to rescan the wallet during initialization</source>
+ <translation>فشل في اعادة مسح المحفظة خلال عملية التهيئة.</translation>
+ </message>
+ <message>
<source>Importing...</source>
<translation>استيراد...</translation>
</message>
@@ -3020,6 +3041,10 @@
<translation>شفرة المصدر متاحة من %s.</translation>
</message>
<message>
+ <source>Unable to generate keys</source>
+ <translation> غير قادر على توليد مفاتيح.</translation>
+ </message>
+ <message>
<source>Unsupported argument -tor found, use -onion.</source>
<translation>تم العثور على وسيطة غير مدعومة -tor ، استخدم -onion.</translation>
</message>
@@ -3128,6 +3153,10 @@
<translation>يجب ألا تكون قيمة المعاملة سلبية</translation>
</message>
<message>
+ <source>Transaction has too long of a mempool chain</source>
+ <translation>المعاملات طويلة جداً على حجم سلسلة الذاكرة </translation>
+ </message>
+ <message>
<source>Transaction must have at least one recipient</source>
<translation>يجب أن تحتوي المعاملة على مستلم واحد على الأقل</translation>
</message>
@@ -3136,6 +3165,10 @@
<translation>اموال غير كافية</translation>
</message>
<message>
+ <source>Cannot write to data directory '%s'; check permissions.</source>
+ <translation>لايمكن الكتابة على دليل البيانات '%s'؛ تحقق من السماحيات.</translation>
+ </message>
+ <message>
<source>Loading block index...</source>
<translation>تحميل مؤشر الكتلة</translation>
</message>
diff --git a/src/qt/locale/bitcoin_bg.ts b/src/qt/locale/bitcoin_bg.ts
index be7fed59a1..c9d33ed6bb 100644
--- a/src/qt/locale/bitcoin_bg.ts
+++ b/src/qt/locale/bitcoin_bg.ts
@@ -136,6 +136,10 @@
<translation>Въведете новата парола повторно</translation>
</message>
<message>
+ <source>Show password</source>
+ <translation>Покажи парола</translation>
+ </message>
+ <message>
<source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;ten or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
<translation>Въведете новата парола към портфейла.&lt;br/&gt;Моля ползвайте парола съставена от &lt;b&gt;десет или повече произволни символа&lt;/b&gt;, или &lt;b&gt;осем или повече думи&lt;/b&gt;.</translation>
</message>
@@ -318,6 +322,14 @@
<translation>Отвори &amp;URI...</translation>
</message>
<message>
+ <source>Wallet:</source>
+ <translation>Портфейл</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation>Портфейл по подразбиране</translation>
+ </message>
+ <message>
<source>Click to disable network activity.</source>
<translation>Натиснете за деактивиране на мрежата</translation>
</message>
@@ -330,6 +342,10 @@
<translation>Натиснете за повторно активиране на мрежата.</translation>
</message>
<message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Синхронизиране на хедъри (%1%)</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>Повторно индексиране на блоковете на диска...</translation>
</message>
@@ -876,6 +892,10 @@
<translation>&amp;Мрежа</translation>
</message>
<message>
+ <source>GB</source>
+ <translation>ГБ</translation>
+ </message>
+ <message>
<source>W&amp;allet</source>
<translation>По&amp;ртфейл</translation>
</message>
@@ -900,6 +920,14 @@
<translation>Отваряне на входящия порт чрез &amp;UPnP</translation>
</message>
<message>
+ <source>Accept connections from outside.</source>
+ <translation>Позволи външни връзки</translation>
+ </message>
+ <message>
+ <source>Allow incomin&amp;g connections</source>
+ <translation>Позволи входящи връзки</translation>
+ </message>
+ <message>
<source>Connect to the Bitcoin network through a SOCKS5 proxy.</source>
<translation>Свързване с Биткойн мрежата чрез SOCKS5 прокси.</translation>
</message>
@@ -920,6 +948,10 @@
<translation>Порт на прокси сървъра (пр. 9050)</translation>
</message>
<message>
+ <source>Tor</source>
+ <translation>Тор</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation>&amp;Прозорец</translation>
</message>
@@ -980,6 +1012,10 @@
<translation>Изисква се рестартиране на клиента за активиране на извършените промени.</translation>
</message>
<message>
+ <source>Client will be shut down. Do you want to proceed?</source>
+ <translation>Клиентът ще бъде изключен. Искате ли да продължите?</translation>
+ </message>
+ <message>
<source>Error</source>
<translation>Грешка</translation>
</message>
@@ -1349,6 +1385,10 @@
<translation>Изчисти конзолата</translation>
</message>
<message>
+ <source>default wallet</source>
+ <translation>Портфейл по подразбиране</translation>
+ </message>
+ <message>
<source>via %1</source>
<translation>посредством %1</translation>
</message>
diff --git a/src/qt/locale/bitcoin_cs.ts b/src/qt/locale/bitcoin_cs.ts
index 260d79b766..a08cc960da 100644
--- a/src/qt/locale/bitcoin_cs.ts
+++ b/src/qt/locale/bitcoin_cs.ts
@@ -354,6 +354,10 @@
<translation>Vytvářím nový index bloků na disku...</translation>
</message>
<message>
+ <source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
+ <translation>Proxy je &lt;b&gt;zapnutá&lt;/b&gt;: %1</translation>
+ </message>
+ <message>
<source>Send coins to a Bitcoin address</source>
<translation>Pošli mince na bitcoinovou adresu</translation>
</message>
@@ -522,6 +526,12 @@
</translation>
</message>
<message>
+ <source>Wallet: %1
+</source>
+ <translation>Peněženka: %1
+</translation>
+ </message>
+ <message>
<source>Type: %1
</source>
<translation>Typ: %1
@@ -758,6 +768,14 @@
<translation>Zadaná adresa „%1“ není platná bitcoinová adresa.</translation>
</message>
<message>
+ <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source>
+ <translation>Adresa "%1" již existuje jako přijímací adresa s označením "%2" a proto nemůže být přidána jako odesílací adresa.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book with label "%2".</source>
+ <translation>Zadaná adresa „%1“ už v adresáři je s označením "%2".</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation>Nemohu odemknout peněženku.</translation>
</message>
@@ -1036,6 +1054,22 @@
<translation>&amp;Síť</translation>
</message>
<message>
+ <source>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</source>
+ <translation>Zakáže některé pokročilé funkce, ale všechny bloky budou stále plně otevřené. Obnovení tohoto nastavení vyžaduje opětovné převzetí celého blockchainu. Skutečné využít disku může být o něco vyšší.</translation>
+ </message>
+ <message>
+ <source>Prune &amp;block storage to</source>
+ <translation>Redukovat prostor pro &amp;bloky na</translation>
+ </message>
+ <message>
+ <source>GB</source>
+ <translation>GB</translation>
+ </message>
+ <message>
+ <source>Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation>Obnovení tohoto nastavení vyžaduje opětovné převzetí celého blockchainu.</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation>(0 = automaticky, &lt;0 = nechat daný počet jader volný, výchozí: 0)</translation>
</message>
@@ -1503,10 +1537,18 @@
<context>
<name>QObject::QObject</name>
<message>
+ <source>Error parsing command line arguments: %1.</source>
+ <translation>Chyba při zpracování argumentů příkazového řádku: %1.</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
<translation>Chyba: Zadaný adresář pro data „%1“ neexistuje.</translation>
</message>
<message>
+ <source>Error: Cannot parse configuration file: %1.</source>
+ <translation>Chyba: Konfigurační soubor se nedá zpracovat: %1.</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation>Chyba: %1</translation>
</message>
@@ -1597,6 +1639,14 @@
<translation>Obsazenost paměti</translation>
</message>
<message>
+ <source>Wallet: </source>
+ <translation>Peněženka:</translation>
+ </message>
+ <message>
+ <source>(none)</source>
+ <translation>(žádné)</translation>
+ </message>
+ <message>
<source>&amp;Reset</source>
<translation>&amp;Vynulovat</translation>
</message>
@@ -1777,6 +1827,14 @@
<translation>V historii se pohybuješ šipkami nahoru a dolů a pomocí %1 čistíš obrazovku.</translation>
</message>
<message>
+ <source>Type %1 for an overview of available commands.</source>
+ <translation>Napiš %1 pro přehled dostupných příkazů.</translation>
+ </message>
+ <message>
+ <source>For more information on using this console type %1.</source>
+ <translation>Pro více informací jak používat tuto konzoli napište %1.</translation>
+ </message>
+ <message>
<source>WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.</source>
<translation>UPOZORNĚNÍ: Podvodníci jsou aktivní a říkají uživatelům, aby sem zadávali příkazy, kterými jim pak ale vykradou jejich peněženky. Nepoužívej tuhle konzoli, pokud úplně neznáš důsledky jednotlivých příkazů.</translation>
</message>
@@ -1785,6 +1843,14 @@
<translation>Síť je vypnutá</translation>
</message>
<message>
+ <source>Executing command without any wallet</source>
+ <translation>Spouštění příkazu bez jakékoliv peněženky</translation>
+ </message>
+ <message>
+ <source>Executing command using "%1" wallet</source>
+ <translation>Příkaz se vykonává s použitím peněženky "%1"</translation>
+ </message>
+ <message>
<source>(node id: %1)</source>
<translation>(id uzlu: %1)</translation>
</message>
@@ -1856,6 +1922,14 @@
<translation>Vyčistit</translation>
</message>
<message>
+ <source>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</source>
+ <translation>Nativní segwit adresy (Bech32 nebo BIP-173) snižují Vaše budoucí transakční poplatky a nabízejí lepší ochranu před překlepy, avšak staré peněženky je nepodporují. Pokud je toto pole nezaškrtnuté, bude vytvořena adresa kompatibilní se staršími peněženkami.</translation>
+ </message>
+ <message>
+ <source>Generate native segwit (Bech32) address</source>
+ <translation>Generovat nativní segwit adresu (Bench32)</translation>
+ </message>
+ <message>
<source>Requested payments history</source>
<translation>Historie vyžádaných plateb</translation>
</message>
@@ -2061,6 +2135,14 @@
<translation>sbal nastavení poplatků</translation>
</message>
<message>
+ <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size.
+
+Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis per kB" for a transaction size of 500 bytes (half of 1 kB) would ultimately yield a fee of only 50 satoshis.</source>
+ <translation>Specifikujte vlastní poplatek za kB (1000 bajtů) virtuální velikosti transakce.
+
+Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 satoshi za kB" a velikost transakce 500 bajtů (polovina z 1 kB) by stál jen 50 satoshi.</translation>
+ </message>
+ <message>
<source>per kilobyte</source>
<translation>za kilobajt</translation>
</message>
@@ -2113,6 +2195,10 @@
<translation>Povolit možnost dodatečně transakci navýšit poplatek (tzv. „replace-by-fee“)</translation>
</message>
<message>
+ <source>With Replace-By-Fee (BIP-125) you can increase a transaction's fee after it is sent. Without this, a higher fee may be recommended to compensate for increased transaction delay risk.</source>
+ <translation>S dodatečným navýšením poplatku (BIP-125, tzv. „Replace-By-Fee“) můžete zvýšit poplatek i po odeslání. Bez dodatečného navýšení bude navrhnut vyšší transakční poplatek, tak aby kompenzoval zvýšené riziko prodlení transakce.</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>Všechno s&amp;maž</translation>
</message>
@@ -2173,10 +2259,30 @@
<translation>nebo</translation>
</message>
<message>
+ <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source>
+ <translation>Poplatek můžete navýšit později (vysílá se "Replace-By-Fee" - nahrazení poplatkem, BIP-125).</translation>
+ </message>
+ <message>
+ <source>from wallet %1</source>
+ <translation>z peněženky %1</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction.</source>
+ <translation>Prosím, zkontrolujte vaši transakci.</translation>
+ </message>
+ <message>
<source>Transaction fee</source>
<translation>Transakční poplatek</translation>
</message>
<message>
+ <source>Not signalling Replace-By-Fee, BIP-125.</source>
+ <translation>Nevysílá se "Replace-By-Fee" - nahrazení poplatkem, BIP-125.</translation>
+ </message>
+ <message>
+ <source>Total Amount</source>
+ <translation>Celková částka</translation>
+ </message>
+ <message>
<source>Confirm send coins</source>
<translation>Potvrď odeslání mincí</translation>
</message>
@@ -2296,6 +2402,10 @@
<translation>Od&amp;ečíst poplatek od částky</translation>
</message>
<message>
+ <source>Use available balance</source>
+ <translation>Použít dostupný zůstatek</translation>
+ </message>
+ <message>
<source>Message:</source>
<translation>Zpráva:</translation>
</message>
@@ -2626,6 +2736,10 @@
<translation>Celková velikost transakce</translation>
</message>
<message>
+ <source>Transaction virtual size</source>
+ <translation>Virtuální velikost transakce</translation>
+ </message>
+ <message>
<source>Output index</source>
<translation>Pořadí výstupu</translation>
</message>
@@ -3030,7 +3144,11 @@
<source>The wallet data was successfully saved to %1.</source>
<translation>Data z peněženky byla v pořádku uložena do %1.</translation>
</message>
- </context>
+ <message>
+ <source>Cancel</source>
+ <translation>Zrušit</translation>
+ </message>
+</context>
<context>
<name>bitcoin-core</name>
<message>
@@ -3082,6 +3200,10 @@
<translation>Nastala chyba při čtení souboru %s! Všechny klíče se přečetly správně, ale data o transakcích nebo záznamy v adresáři mohou chybět či být nesprávné.</translation>
</message>
<message>
+ <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source>
+ <translation>Seskupení výstupů podle adresy, při výběru všech nebo žádných, namísto výběru báze za výstup. Zvýšena ochrana soukromí, protože je adresa použita pouze jednou (pokud nikdo na tuto adresu již nic po minutě nepošle). Může být spojeno s vyššími poplatky, jelikož neoptimalizovaný výběr mincí může vyústit v přidané omezení (předvolené: %u)</translation>
+ </message>
+ <message>
<source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source>
<translation>Zkontroluj, že máš v počítači správně nastavený datum a čas! Pokud jsou nastaveny špatně, %s nebude fungovat správně.</translation>
</message>
@@ -3166,6 +3288,10 @@
<translation>Chyba při načítání %s</translation>
</message>
<message>
+ <source>Error loading %s: Private keys can only be disabled during creation</source>
+ <translation>Chyba při načítání %s: Soukromé klíče můžou být zakázané jen v průběhu vytváření.</translation>
+ </message>
+ <message>
<source>Error loading %s: Wallet corrupted</source>
<translation>Chyba při načítání %s: peněženka je poškozená</translation>
</message>
@@ -3190,6 +3316,10 @@
<translation>Nepodařilo se naslouchat na žádném portu. Použij -listen=0, pokud to byl tvůj záměr.</translation>
</message>
<message>
+ <source>Failed to rescan the wallet during initialization</source>
+ <translation>Během inicializace se nepodařilo proskenovat peněženku</translation>
+ </message>
+ <message>
<source>Importing...</source>
<translation>Importuji...</translation>
</message>
@@ -3214,6 +3344,14 @@
<translation>Neplatná částka pro -fallbackfee=&lt;částka&gt;: '%s'</translation>
</message>
<message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation>Zadaný adresář bloků "%s" neexistuje.</translation>
+ </message>
+ <message>
+ <source>Upgrading txindex database</source>
+ <translation>Aktualizuje se txindex databáze</translation>
+ </message>
+ <message>
<source>Loading P2P addresses...</source>
<translation>Načítám P2P adresy…</translation>
</message>
@@ -3254,6 +3392,10 @@
<translation>Nedaří se mi připojit na %s na tomhle počítači. %s už pravděpodobně jednou běží.</translation>
</message>
<message>
+ <source>Unable to generate keys</source>
+ <translation>Nepodařilo se vygenerovat klíče</translation>
+ </message>
+ <message>
<source>Unsupported argument -benchmark ignored, use -debug=bench.</source>
<translation>Nepodporovaný argument -benchmark se ignoruje, použij -debug=bench.</translation>
</message>
@@ -3346,6 +3488,18 @@
<translation>Nepodařilo se podepsat transakci</translation>
</message>
<message>
+ <source>Specified -walletdir "%s" does not exist</source>
+ <translation>Uvedená -walletdir "%s" neexistuje</translation>
+ </message>
+ <message>
+ <source>Specified -walletdir "%s" is a relative path</source>
+ <translation>Uvedená -walletdir "%s" je relatívna cesta</translation>
+ </message>
+ <message>
+ <source>Specified -walletdir "%s" is not a directory</source>
+ <translation>Uvedená -walletdir "%s" není složkou</translation>
+ </message>
+ <message>
<source>The transaction amount is too small to pay the fee</source>
<translation>Částka v transakci je příliš malá na pokrytí poplatku</translation>
</message>
@@ -3378,6 +3532,10 @@
<translation>Kontroluji peněženku/y…</translation>
</message>
<message>
+ <source>Wallet %s resides outside wallet directory %s</source>
+ <translation>Peněženka %s se nachází mimo adresář pro peněženky %s</translation>
+ </message>
+ <message>
<source>Warning</source>
<translation>Upozornění</translation>
</message>
@@ -3474,6 +3632,22 @@
<translation>Nedostatek prostředků</translation>
</message>
<message>
+ <source>Can't generate a change-address key. Private keys are disabled for this wallet.</source>
+ <translation>Není možné vygenerovat klíč na změnu adresy. Soukromé klíče jsou pro tuto peněženku zakázané.</translation>
+ </message>
+ <message>
+ <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use -upgradewallet=169900 or -upgradewallet with no version specified.</source>
+ <translation>Není možné vylepšit peněženku bez HD bez aktualizace, která podporuje dělení keypoolu. Použijte prosím -upgradewallet=169900 nebo -upgradewallet bez specifikované verze.</translation>
+ </message>
+ <message>
+ <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
+ <translation>Odhad poplatku se nepodařil. Fallbackfee je zakázaný. Počkejte několik bloků nebo povolte -fallbackfee.</translation>
+ </message>
+ <message>
+ <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source>
+ <translation>Upozornění: Byly zjištěné soukromé klíče v peněžence {%s} se zakázanými soukromými klíči.</translation>
+ </message>
+ <message>
<source>Loading block index...</source>
<translation>Načítám index bloků...</translation>
</message>
diff --git a/src/qt/locale/bitcoin_da.ts b/src/qt/locale/bitcoin_da.ts
index 21dc7831c3..c7a2422c8a 100644
--- a/src/qt/locale/bitcoin_da.ts
+++ b/src/qt/locale/bitcoin_da.ts
@@ -3200,6 +3200,10 @@ Note: Siden gebyret er kalkuleret på en per-byte basis, et gebyr på "100 satos
<translation>Fejl under læsning af %s! Alle nøgler blev læst korrekt, men transaktionsdata eller indgange i adressebogen kan mangle eller være ukorrekte.</translation>
</message>
<message>
+ <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source>
+ <translation>Gruppér output efter adresse og vælg alle eller ingen, i stedet for at vælge på per-output-basis. Højere sikring af privatliv, da en adresse kun bruges én gang (med mindre nogen sender til en adresse efter den er brugt), men kan resultere i en anelse højere gebyrer, da ikke-optimal valg af output-adresser kan forekomme på grund af den tilføjede begrænsning (standard: %u)</translation>
+ </message>
+ <message>
<source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source>
<translation>Undersøg venligst at din computers dato og klokkeslet er korrekt indstillet! Hvis der er fejl i disse, vil %s ikke fungere korrekt.</translation>
</message>
@@ -3340,6 +3344,10 @@ Note: Siden gebyret er kalkuleret på en per-byte basis, et gebyr på "100 satos
<translation>Ugyldigt beløb for -fallbackfee=&lt;beløb&gt;: “%s”</translation>
</message>
<message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation>Angivet blokmappe “%s” eksisterer ikke.</translation>
+ </message>
+ <message>
<source>Upgrading txindex database</source>
<translation>Opgraderer txindex database</translation>
</message>
@@ -3480,12 +3488,6 @@ Note: Siden gebyret er kalkuleret på en per-byte basis, et gebyr på "100 satos
<translation>Signering af transaktion mislykkedes</translation>
</message>
<message>
- <source>Specified blocks directory "%s" does not exist.
-</source>
- <translation>Specificeret blokke mappe "%s" eksisterer ikke.
-</translation>
- </message>
- <message>
<source>The transaction amount is too small to pay the fee</source>
<translation>Transaktionsbeløbet er for lille til at betale gebyret</translation>
</message>
diff --git a/src/qt/locale/bitcoin_de.ts b/src/qt/locale/bitcoin_de.ts
index 45d09655c4..31feaf114f 100644
--- a/src/qt/locale/bitcoin_de.ts
+++ b/src/qt/locale/bitcoin_de.ts
@@ -145,7 +145,7 @@
</message>
<message>
<source>Encrypt wallet</source>
- <translation>Wallet verschlüsseln</translation>
+ <translation>Brieftasche verschlüsseln</translation>
</message>
<message>
<source>This operation needs your wallet passphrase to unlock the wallet.</source>
@@ -161,7 +161,7 @@
</message>
<message>
<source>Decrypt wallet</source>
- <translation>Brieftasche entschlüsseln</translation>
+ <translation>Wallet entschlüsseln</translation>
</message>
<message>
<source>Change passphrase</source>
@@ -3196,6 +3196,10 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio
<translation>Lesen von %s fehlgeschlagen! Alle Schlüssel wurden korrekt gelesen, Transaktionsdaten bzw. Adressbucheinträge fehlen aber möglicherweise oder sind inkorrekt.</translation>
</message>
<message>
+ <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source>
+ <translation>Gruppiere Outputs mit der Auswahl von allen oder keinen Adressen, anstatt alle pro Output auszuwählen. Die Privatsphäre wurde verbessert, da eine Adresse nur einmal verwendet wird (ausser jemand sendet Coins nachdem von der Adresse ausgegeben wurde). Durch diese hinzugefügte Limitierung kann es allerdings zu leicht erhöhten Transaktionskosten kommen, da eine suboptimale Coinselektierung bei Transaktionen stattfinden kann. (Standardeinstellung: %u)</translation>
+ </message>
+ <message>
<source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source>
<translation>Bitte korrigieren Sie die Datums- und Uhrzeiteinstellungen Ihres Computers, da %s ansonsten nicht ordnungsgemäß funktionieren wird.</translation>
</message>
@@ -3337,6 +3341,10 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio
<translation>Ungültiger Betrag für -fallbackfee=&lt;amount&gt;: '%s'</translation>
</message>
<message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation>Angegebener Blöcke-Ordner "%s" existiert nicht.</translation>
+ </message>
+ <message>
<source>Upgrading txindex database</source>
<translation>Erneuern der txindex Datenbank</translation>
</message>
@@ -3485,12 +3493,6 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio
<translation>Angegebenes Verzeichniss "%s" ist kein Verzeichniss</translation>
</message>
<message>
- <source>Specified blocks directory "%s" does not exist.
-</source>
- <translation>Angegebenes 'blocks'-Verzeichnis "%s" existiert nicht.
-</translation>
- </message>
- <message>
<source>The transaction amount is too small to pay the fee</source>
<translation>Der Transaktionsbetrag ist zu niedrig, um die Gebühr zu bezahlen.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_el_GR.ts b/src/qt/locale/bitcoin_el_GR.ts
index 4557fd85aa..85d5c62c91 100644
--- a/src/qt/locale/bitcoin_el_GR.ts
+++ b/src/qt/locale/bitcoin_el_GR.ts
@@ -234,7 +234,11 @@
<source>IP/Netmask</source>
<translation>IP/Netmask</translation>
</message>
- </context>
+ <message>
+ <source>Banned Until</source>
+ <translation>Απαγορευμένο έως</translation>
+ </message>
+</context>
<context>
<name>BitcoinGUI</name>
<message>
@@ -326,6 +330,10 @@
<translation>Πορτοφόλι</translation>
</message>
<message>
+ <source>default wallet</source>
+ <translation>Προεπιλεγμένο πορτοφόλι</translation>
+ </message>
+ <message>
<source>Click to disable network activity.</source>
<translation>Κάντε κλικ για να απενεργοποιήσετε το δίκτυο.</translation>
</message>
@@ -338,6 +346,10 @@
<translation>Κάντε κλικ για να ενεργοποιήσετε τo δίκτυο ξανά.</translation>
</message>
<message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Συγχρονισμός Επικεφαλίδων (%1%)...</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>Φόρτωση ευρετηρίου μπλοκ στον σκληρό δίσκο...</translation>
</message>
@@ -490,6 +502,12 @@
</translation>
</message>
<message>
+ <source>Wallet: %1
+</source>
+ <translation>Πορτοφόλι: %1
+</translation>
+ </message>
+ <message>
<source>Type: %1
</source>
<translation>Τύπος: %1
@@ -611,6 +629,14 @@
<translation>Αντιγραφή ταυτότητας συναλλαγής</translation>
</message>
<message>
+ <source>Copy quantity</source>
+ <translation>Αντιγραφή ποσότητας</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Αντιγραφή τελών</translation>
+ </message>
+ <message>
<source>yes</source>
<translation>ναι</translation>
</message>
@@ -661,7 +687,27 @@
<source>Edit sending address</source>
<translation> Επεξεργασία διεύθυνσης αποστολής</translation>
</message>
- </context>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>Η διεύθυνση "%1" δεν είναι έγκυρη Bitcoin διεύθυνση.</translation>
+ </message>
+ <message>
+ <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source>
+ <translation>Η διεύθυνση "%1" υπάρχει ήδη ως διεύθυνσης λήψης με ετικέτα "%2" και γιαυτό τον λόγο δεν μπορεί να προστεθεί ως διεύθυνση αποστολής.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book with label "%2".</source>
+ <translation>Η διεύθυνση "%1" βρίσκεται ήδη στο βιβλίο διευθύνσεων με ετικέτα "%2".</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Δεν είναι δυνατό το ξεκλείδωμα του πορτοφολιού.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Η δημιουργία νέου κλειδιού απέτυχε.</translation>
+ </message>
+</context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -696,6 +742,10 @@
<translation>(%1-bit)</translation>
</message>
<message>
+ <source>About %1</source>
+ <translation>Σχετικά %1</translation>
+ </message>
+ <message>
<source>Command-line options</source>
<translation>Επιλογές γραμμής εντολών</translation>
</message>
@@ -828,6 +878,10 @@
<translation>&amp;Δίκτυο</translation>
</message>
<message>
+ <source>GB</source>
+ <translation>GB</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation>(0 = αυτόματο, &lt;0 = ελεύθεροι πυρήνες)</translation>
</message>
@@ -880,6 +934,18 @@
<translation>Θύρα διαμεσολαβητή</translation>
</message>
<message>
+ <source>IPv4</source>
+ <translation>IPv4</translation>
+ </message>
+ <message>
+ <source>IPv6</source>
+ <translation>IPv6</translation>
+ </message>
+ <message>
+ <source>Tor</source>
+ <translation>Tor</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation>&amp;Παράθυρο</translation>
</message>
@@ -1181,6 +1247,10 @@
<translation>Τρέχον αριθμός μπλοκ</translation>
</message>
<message>
+ <source>Memory usage</source>
+ <translation>χρήση Μνήμης</translation>
+ </message>
+ <message>
<source>Received</source>
<translation>Παραλήφθησαν</translation>
</message>
@@ -1201,6 +1271,14 @@
<translation>Έκδοση</translation>
</message>
<message>
+ <source>Decrease font size</source>
+ <translation>Μείωση μεγέθους γραμματοσειράς</translation>
+ </message>
+ <message>
+ <source>Increase font size</source>
+ <translation>Αύξηση μεγέθους γραμματοσειράς</translation>
+ </message>
+ <message>
<source>Services</source>
<translation>Υπηρεσίες</translation>
</message>
@@ -1261,6 +1339,26 @@
<translation>Καθαρισμός κονσόλας</translation>
</message>
<message>
+ <source>1 &amp;hour</source>
+ <translation>1 &amp;ώρα</translation>
+ </message>
+ <message>
+ <source>1 &amp;day</source>
+ <translation>1 &amp;μέρα</translation>
+ </message>
+ <message>
+ <source>1 &amp;week</source>
+ <translation>1 &amp;εβδομάδα</translation>
+ </message>
+ <message>
+ <source>1 &amp;year</source>
+ <translation>1 &amp;χρόνος</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation>Προεπιλεγμένο πορτοφόλι</translation>
+ </message>
+ <message>
<source>via %1</source>
<translation>μέσω %1</translation>
</message>
@@ -1277,6 +1375,14 @@
<translation>Εξερχόμενα</translation>
</message>
<message>
+ <source>Yes</source>
+ <translation>Ναι</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Όχι</translation>
+ </message>
+ <message>
<source>Unknown</source>
<translation>Άγνωστο(α)</translation>
</message>
@@ -1328,6 +1434,10 @@
<translation>Αντιγραφή ετικέτας</translation>
</message>
<message>
+ <source>Copy message</source>
+ <translation>Αντιγραφή μηνύματος</translation>
+ </message>
+ <message>
<source>Copy amount</source>
<translation>Αντιγραφή ποσού</translation>
</message>
@@ -1351,14 +1461,26 @@
<translation>&amp;Αποθήκευση εικόνας...</translation>
</message>
<message>
+ <source>Payment information</source>
+ <translation>Πληροφορίες πληρωμής</translation>
+ </message>
+ <message>
<source>Address</source>
<translation>Διεύθυνση</translation>
</message>
<message>
+ <source>Amount</source>
+ <translation>Ποσό</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>Ετικέτα</translation>
</message>
<message>
+ <source>Message</source>
+ <translation>Μήνυμα</translation>
+ </message>
+ <message>
<source>Wallet</source>
<translation>Πορτοφόλι</translation>
</message>
@@ -1374,6 +1496,10 @@
<translation>Ετικέτα</translation>
</message>
<message>
+ <source>Message</source>
+ <translation>Μήνυμα</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(χωρίς ετικέτα)</translation>
</message>
@@ -1489,10 +1615,22 @@
<translation>Αποστολή</translation>
</message>
<message>
+ <source>Copy quantity</source>
+ <translation>Αντιγραφή ποσότητας</translation>
+ </message>
+ <message>
<source>Copy amount</source>
<translation>Αντιγραφή ποσού</translation>
</message>
<message>
+ <source>Copy fee</source>
+ <translation>Αντιγραφή τελών</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>ή</translation>
+ </message>
+ <message>
<source>Transaction fee</source>
<translation>Κόστος συναλλαγής</translation>
</message>
@@ -1562,7 +1700,11 @@
</context>
<context>
<name>SendConfirmationDialog</name>
- </context>
+ <message>
+ <source>Yes</source>
+ <translation>Ναι</translation>
+ </message>
+</context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1725,6 +1867,14 @@
<source>Transaction fee</source>
<translation>Κόστος συναλλαγής</translation>
</message>
+ <message>
+ <source>Message</source>
+ <translation>Μήνυμα</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Ποσό</translation>
+ </message>
</context>
<context>
<name>TransactionDescDialog</name>
@@ -1815,10 +1965,18 @@
</context>
<context>
<name>WalletModel</name>
+ <message>
+ <source>Increase:</source>
+ <translation>Αύξηση:</translation>
+ </message>
</context>
<context>
<name>WalletView</name>
- </context>
+ <message>
+ <source>Cancel</source>
+ <translation>Ακύρωση</translation>
+ </message>
+</context>
<context>
<name>bitcoin-core</name>
<message>
diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index fbff2d36a0..c6ecbc3f87 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -237,7 +237,7 @@
</message>
<message>
<location line="-56"/>
- <source>%1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
+ <source>Your wallet is now encrypted. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -246,32 +246,33 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+9"/>
+ <location line="+8"/>
<location line="+7"/>
- <location line="+42"/>
+ <location line="+43"/>
<location line="+6"/>
<source>Wallet encryption failed</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-54"/>
+ <location line="-55"/>
<source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+7"/>
- <location line="+48"/>
+ <location line="+49"/>
<source>The supplied passphrases do not match.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-37"/>
+ <location line="-38"/>
+ <location line="+6"/>
<source>Wallet unlock failed</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
- <location line="+11"/>
+ <location line="-5"/>
+ <location line="+12"/>
<location line="+19"/>
<source>The passphrase entered for the wallet decryption was incorrect.</source>
<translation type="unfinished"></translation>
@@ -309,27 +310,22 @@
<context>
<name>BitcoinGUI</name>
<message>
- <location filename="../bitcoingui.cpp" line="+307"/>
+ <location filename="../bitcoingui.cpp" line="+318"/>
<source>Sign &amp;message...</source>
<translation>Sign &amp;message...</translation>
</message>
<message>
- <location line="+483"/>
+ <location line="+574"/>
<source>Synchronizing with network...</source>
<translation>Synchronizing with network...</translation>
</message>
<message>
- <location line="-561"/>
+ <location line="-652"/>
<source>&amp;Overview</source>
<translation>&amp;Overview</translation>
</message>
<message>
- <location line="-140"/>
- <source>Node</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+141"/>
+ <location line="+1"/>
<source>Show general overview of wallet</source>
<translation>Show general overview of wallet</translation>
</message>
@@ -399,32 +395,17 @@
<translation>&amp;Change Passphrase...</translation>
</message>
<message>
- <location line="+12"/>
- <source>&amp;Sending addresses...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+2"/>
- <source>&amp;Receiving addresses...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+3"/>
+ <location line="+18"/>
<source>Open &amp;URI...</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+104"/>
+ <location line="+157"/>
<source>Wallet:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+83"/>
- <source>default wallet</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+226"/>
+ <location line="+330"/>
<source>Click to disable network activity.</source>
<translation type="unfinished"></translation>
</message>
@@ -444,17 +425,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+37"/>
+ <location line="+53"/>
<source>Reindexing blocks on disk...</source>
<translation>Reindexing blocks on disk...</translation>
</message>
<message>
- <location line="+316"/>
+ <location line="+315"/>
<source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-880"/>
+ <location line="-970"/>
<source>Send coins to a Bitcoin address</source>
<translation>Send coins to a Bitcoin address</translation>
</message>
@@ -484,17 +465,12 @@
<translation>&amp;Verify message...</translation>
</message>
<message>
- <location line="+570"/>
+ <location line="+660"/>
<source>Bitcoin</source>
<translation>Bitcoin</translation>
</message>
<message>
- <location line="-792"/>
- <source>Wallet</source>
- <translation>Wallet</translation>
- </message>
- <message>
- <location line="+149"/>
+ <location line="-733"/>
<source>&amp;Send</source>
<translation>&amp;Send</translation>
</message>
@@ -529,32 +505,32 @@
<translation>Verify messages to ensure they were signed with specified Bitcoin addresses</translation>
</message>
<message>
- <location line="+58"/>
+ <location line="+61"/>
<source>&amp;File</source>
<translation>&amp;File</translation>
</message>
<message>
- <location line="+14"/>
+ <location line="+11"/>
<source>&amp;Settings</source>
<translation>&amp;Settings</translation>
</message>
<message>
- <location line="+9"/>
+ <location line="+66"/>
<source>&amp;Help</source>
<translation>&amp;Help</translation>
</message>
<message>
- <location line="+15"/>
+ <location line="+11"/>
<source>Tabs toolbar</source>
<translation>Tabs toolbar</translation>
</message>
<message>
- <location line="-158"/>
+ <location line="-211"/>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+70"/>
+ <location line="+71"/>
<source>Show the list of used sending addresses and labels</source>
<translation type="unfinished"></translation>
</message>
@@ -574,7 +550,7 @@
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
- <location line="+410"/>
+ <location line="+484"/>
<source>%n active connection(s) to Bitcoin network</source>
<translation>
<numerusform>%n active connection to Bitcoin network</numerusform>
@@ -582,7 +558,7 @@
</translation>
</message>
<message>
- <location line="+60"/>
+ <location line="+76"/>
<source>Indexing blocks on disk...</source>
<translation type="unfinished"></translation>
</message>
@@ -600,7 +576,7 @@
</translation>
</message>
<message>
- <location line="+24"/>
+ <location line="+23"/>
<source>%1 behind</source>
<translation>%1 behind</translation>
</message>
@@ -635,22 +611,57 @@
<translation>Up to date</translation>
</message>
<message>
- <location line="-494"/>
+ <location line="-593"/>
+ <source>&amp;Sending addresses</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>&amp;Receiving addresses</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+8"/>
<source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+253"/>
+ <location line="+63"/>
+ <source>&amp;Window</source>
+ <translation type="unfinished">&amp;Window</translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Minimize</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+10"/>
+ <source>Zoom</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+14"/>
+ <source>Restore</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+12"/>
+ <source>Main Window</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+228"/>
<source>%1 client</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+227"/>
+ <location line="+241"/>
<source>Connecting to peers...</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+38"/>
+ <location line="+37"/>
<source>Catching up...</source>
<translation>Catching up...</translation>
</message>
@@ -711,6 +722,11 @@
<translation type="unfinished"></translation>
</message>
<message>
+ <location line="+0"/>
+ <source>Private key &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
<location line="+19"/>
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
<translation>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</translation>
@@ -721,7 +737,7 @@
<translation>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</translation>
</message>
<message>
- <location filename="../bitcoin.cpp" line="+529"/>
+ <location filename="../bitcoin.cpp" line="+395"/>
<source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
<translation type="unfinished"></translation>
</message>
@@ -814,7 +830,7 @@
<translation type="unfinished">Confirmed</translation>
</message>
<message>
- <location filename="../coincontroldialog.cpp" line="+53"/>
+ <location filename="../coincontroldialog.cpp" line="+58"/>
<source>Copy address</source>
<translation type="unfinished"></translation>
</message>
@@ -875,7 +891,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+315"/>
+ <location line="+313"/>
<source>(%1 locked)</source>
<translation type="unfinished"></translation>
</message>
@@ -987,7 +1003,7 @@
<context>
<name>FreespaceChecker</name>
<message>
- <location filename="../intro.cpp" line="+77"/>
+ <location filename="../intro.cpp" line="+73"/>
<source>A new data directory will be created.</source>
<translation>A new data directory will be created.</translation>
</message>
@@ -1015,7 +1031,7 @@
<context>
<name>HelpMessageDialog</name>
<message>
- <location filename="../utilitydialog.cpp" line="+41"/>
+ <location filename="../utilitydialog.cpp" line="+44"/>
<source>version</source>
<translation type="unfinished">version</translation>
</message>
@@ -1079,7 +1095,7 @@
<translation>Use a custom data directory:</translation>
</message>
<message>
- <location filename="../intro.cpp" line="+20"/>
+ <location filename="../intro.cpp" line="+22"/>
<source>Bitcoin</source>
<translation type="unfinished">Bitcoin</translation>
</message>
@@ -1104,7 +1120,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+73"/>
+ <location line="+80"/>
<source>Error: Specified data directory &quot;%1&quot; cannot be created.</source>
<translation type="unfinished"></translation>
</message>
@@ -1252,12 +1268,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+16"/>
- <source>MB</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+27"/>
+ <location line="+43"/>
<source>Number of script &amp;verification threads</source>
<translation type="unfinished"></translation>
</message>
@@ -1301,12 +1312,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+31"/>
- <source>Active command-line options that override above options:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+45"/>
+ <location line="+76"/>
<source>Open the %1 configuration file from the working directory.</source>
<translation type="unfinished"></translation>
</message>
@@ -1351,7 +1357,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+68"/>
+ <location line="+28"/>
+ <source>MiB</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+40"/>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation type="unfinished"></translation>
</message>
@@ -1509,7 +1520,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+182"/>
+ <location line="+41"/>
+ <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+141"/>
<source>&amp;OK</source>
<translation>&amp;OK</translation>
</message>
@@ -1519,17 +1535,17 @@
<translation>&amp;Cancel</translation>
</message>
<message>
- <location filename="../optionsdialog.cpp" line="+92"/>
+ <location filename="../optionsdialog.cpp" line="+96"/>
<source>default</source>
<translation>default</translation>
</message>
<message>
- <location line="+56"/>
+ <location line="+63"/>
<source>none</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+77"/>
+ <location line="+93"/>
<source>Confirm options reset</source>
<translation>Confirm options reset</translation>
</message>
@@ -1672,8 +1688,8 @@
<context>
<name>PaymentServer</name>
<message>
- <location filename="../paymentserver.cpp" line="+317"/>
- <location line="+215"/>
+ <location filename="../paymentserver.cpp" line="+226"/>
+ <location line="+338"/>
<location line="+42"/>
<location line="+110"/>
<location line="+14"/>
@@ -1682,30 +1698,42 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-398"/>
+ <location line="-521"/>
<source>Cannot start bitcoin: click-to-pay handler</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+82"/>
- <location line="+21"/>
- <location line="+13"/>
+ <location line="+62"/>
+ <location line="+9"/>
+ <location line="+16"/>
+ <location line="+5"/>
+ <location line="+12"/>
<location line="+7"/>
<source>URI handling</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-41"/>
+ <location line="-49"/>
<source>&apos;bitcoin://&apos; is not a valid URI. Use &apos;bitcoin:&apos; instead.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+22"/>
+ <location line="+10"/>
+ <source>You are using a BIP70 URL which will be unsupported in the future.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+16"/>
<source>Payment request fetch URL is invalid: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+12"/>
+ <location line="+5"/>
+ <source>Cannot process payment request because BIP70 support was not compiled in.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+11"/>
<source>Invalid payment address %1</source>
<translation type="unfinished"></translation>
</message>
@@ -1715,7 +1743,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+13"/>
+ <location line="+14"/>
<source>Payment request file handling</source>
<translation type="unfinished"></translation>
</message>
@@ -1725,7 +1753,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+61"/>
+ <location line="+195"/>
<location line="+9"/>
<location line="+31"/>
<location line="+10"/>
@@ -1796,7 +1824,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+11"/>
+ <location line="+6"/>
<source>Payment acknowledged</source>
<translation type="unfinished"></translation>
</message>
@@ -1842,12 +1870,12 @@
<translation type="unfinished">Amount</translation>
</message>
<message>
- <location filename="../guiutil.cpp" line="+115"/>
+ <location filename="../guiutil.cpp" line="+111"/>
<source>Enter a Bitcoin address (e.g. %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+686"/>
+ <location line="+687"/>
<source>%1 d</source>
<translation type="unfinished"></translation>
</message>
@@ -1957,7 +1985,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoin.cpp" line="+192"/>
+ <location filename="../bitcoin.cpp" line="+185"/>
<source>%1 didn&apos;t yet exit safely...</source>
<translation type="unfinished"></translation>
</message>
@@ -1970,12 +1998,12 @@
<context>
<name>QObject::QObject</name>
<message>
- <location filename="../bitcoin.cpp" line="-117"/>
+ <location filename="../bitcoin.cpp" line="-113"/>
<source>Error parsing command line arguments: %1.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+38"/>
+ <location line="+37"/>
<source>Error: Specified data directory &quot;%1&quot; does not exist.</source>
<translation type="unfinished"></translation>
</message>
@@ -2019,7 +2047,8 @@
<location filename="../forms/debugwindow.ui" line="+56"/>
<location line="+26"/>
<location line="+26"/>
- <location line="+23"/>
+ <location line="+26"/>
+ <location line="+29"/>
<location line="+26"/>
<location line="+36"/>
<location line="+23"/>
@@ -2027,7 +2056,7 @@
<location line="+23"/>
<location line="+36"/>
<location line="+23"/>
- <location line="+679"/>
+ <location line="+713"/>
<location line="+23"/>
<location line="+23"/>
<location line="+23"/>
@@ -2049,7 +2078,7 @@
<translation>N/A</translation>
</message>
<message>
- <location line="-1361"/>
+ <location line="-1427"/>
<source>Client version</source>
<translation>Client version</translation>
</message>
@@ -2079,7 +2108,22 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+26"/>
+ <location line="+10"/>
+ <source>To specify a non-default location of the data directory use the &apos;%1&apos; option.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+19"/>
+ <source>Blocksdir</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+10"/>
+ <source>To specify a non-default location of the blocks directory use the &apos;%1&apos; option.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+19"/>
<source>Startup time</source>
<translation>Startup time</translation>
</message>
@@ -2129,7 +2173,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+8"/>
+ <location line="+11"/>
<source>(none)</source>
<translation type="unfinished"></translation>
</message>
@@ -2140,35 +2184,35 @@
</message>
<message>
<location line="+80"/>
- <location line="+558"/>
+ <location line="+589"/>
<source>Received</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-478"/>
- <location line="+455"/>
+ <location line="-509"/>
+ <location line="+486"/>
<source>Sent</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-414"/>
+ <location line="-445"/>
<source>&amp;Peers</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+53"/>
+ <location line="+67"/>
<source>Banned peers</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+60"/>
- <location filename="../rpcconsole.cpp" line="+502"/>
- <location line="+760"/>
+ <location line="+65"/>
+ <location filename="../rpcconsole.cpp" line="+501"/>
+ <location line="+754"/>
<source>Select a peer to view detailed information.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+25"/>
+ <location line="+37"/>
<source>Whitelisted</source>
<translation type="unfinished"></translation>
</message>
@@ -2198,18 +2242,18 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-1095"/>
- <location line="+1003"/>
+ <location line="-1161"/>
+ <location line="+1069"/>
<source>User Agent</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-700"/>
+ <location line="-734"/>
<source>Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+84"/>
+ <location line="+87"/>
<source>Decrease font size</source>
<translation type="unfinished"></translation>
</message>
@@ -2219,7 +2263,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+610"/>
+ <location line="+641"/>
<source>Services</source>
<translation type="unfinished"></translation>
</message>
@@ -2269,7 +2313,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-1132"/>
+ <location line="-1166"/>
<source>Last block time</source>
<translation>Last block time</translation>
</message>
@@ -2284,7 +2328,7 @@
<translation>&amp;Console</translation>
</message>
<message>
- <location line="+211"/>
+ <location line="+214"/>
<source>&amp;Network Traffic</source>
<translation type="unfinished"></translation>
</message>
@@ -2294,7 +2338,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../rpcconsole.cpp" line="-414"/>
+ <location filename="../rpcconsole.cpp" line="-411"/>
<source>In:</source>
<translation type="unfinished"></translation>
</message>
@@ -2304,17 +2348,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../forms/debugwindow.ui" line="-315"/>
+ <location filename="../forms/debugwindow.ui" line="-318"/>
<source>Debug log file</source>
<translation>Debug log file</translation>
</message>
<message>
- <location line="+152"/>
+ <location line="+155"/>
<source>Clear console</source>
<translation>Clear console</translation>
</message>
<message>
- <location filename="../rpcconsole.cpp" line="-253"/>
+ <location filename="../rpcconsole.cpp" line="-249"/>
<source>1 &amp;hour</source>
<translation type="unfinished"></translation>
</message>
@@ -2347,17 +2391,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+48"/>
+ <location line="+47"/>
<source>&amp;Unban</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+54"/>
- <source>default wallet</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+110"/>
+ <location line="+161"/>
<source>Welcome to the %1 RPC console.</source>
<translation type="unfinished"></translation>
</message>
@@ -2387,17 +2426,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+68"/>
+ <location line="+70"/>
<source>Executing command without any wallet</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
+ <location line="-2"/>
<source>Executing command using &quot;%1&quot; wallet</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+190"/>
+ <location line="+189"/>
<source>(node id: %1)</source>
<translation type="unfinished"></translation>
</message>
@@ -2626,7 +2665,7 @@
<context>
<name>RecentRequestsTableModel</name>
<message>
- <location filename="../recentrequeststablemodel.cpp" line="+27"/>
+ <location filename="../recentrequeststablemodel.cpp" line="+25"/>
<source>Date</source>
<translation type="unfinished">Date</translation>
</message>
@@ -2665,7 +2704,7 @@
<name>SendCoinsDialog</name>
<message>
<location filename="../forms/sendcoinsdialog.ui" line="+14"/>
- <location filename="../sendcoinsdialog.cpp" line="+588"/>
+ <location filename="../sendcoinsdialog.cpp" line="+593"/>
<source>Send Coins</source>
<translation>Send Coins</translation>
</message>
@@ -2772,18 +2811,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+80"/>
- <location line="+13"/>
- <source>Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks. But be aware that this can end up in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+3"/>
- <source>(read the tooltip)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+29"/>
+ <location line="+112"/>
<source>Recommended:</source>
<translation type="unfinished"></translation>
</message>
@@ -2793,12 +2821,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+52"/>
+ <location line="+49"/>
<source>(Smart fee not initialized yet. This usually takes a few blocks...)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+185"/>
+ <location line="+166"/>
<source>Send to multiple recipients at once</source>
<translation>Send to multiple recipients at once</translation>
</message>
@@ -2813,17 +2841,27 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-835"/>
+ <location line="-800"/>
<source>Dust:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+696"/>
+ <location line="+543"/>
+ <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>A too low fee might result in a never confirming transaction (read the tooltip)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+131"/>
<source>Confirmation time target:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+74"/>
+ <location line="+58"/>
<source>Enable Replace-By-Fee</source>
<translation type="unfinished"></translation>
</message>
@@ -2853,7 +2891,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation>S&amp;end</translation>
</message>
<message>
- <location filename="../sendcoinsdialog.cpp" line="-504"/>
+ <location filename="../sendcoinsdialog.cpp" line="-505"/>
<source>Copy quantity</source>
<translation type="unfinished"></translation>
</message>
@@ -2888,20 +2926,20 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+76"/>
+ <location line="+74"/>
<source>%1 (%2 blocks)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+131"/>
- <location line="+5"/>
+ <location line="+133"/>
<location line="+5"/>
+ <location line="+6"/>
<location line="+4"/>
<source>%1 to %2</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
+ <location line="+7"/>
<source>Are you sure you want to send?</source>
<translation type="unfinished"></translation>
</message>
@@ -2916,12 +2954,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-57"/>
+ <location line="-61"/>
<source>from wallet %1</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+36"/>
+ <location line="+40"/>
<source>Please, review your transaction.</source>
<translation type="unfinished"></translation>
</message>
@@ -2946,7 +2984,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+192"/>
+ <location line="+191"/>
<source>The recipient address is not valid. Please recheck.</source>
<translation type="unfinished"></translation>
</message>
@@ -2990,13 +3028,8 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<source>Payment request expired.</source>
<translation type="unfinished"></translation>
</message>
- <message>
- <location line="+91"/>
- <source>Pay only the required fee of %1</source>
- <translation type="unfinished"></translation>
- </message>
<message numerus="yes">
- <location line="+43"/>
+ <location line="+120"/>
<source>Estimated to begin confirmation within %n block(s).</source>
<translation>
<numerusform>Estimated to begin confirmation within %n block.</numerusform>
@@ -3138,7 +3171,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../sendcoinsentry.cpp" line="+35"/>
+ <location filename="../sendcoinsentry.cpp" line="+39"/>
<source>Enter a label for this address to add it to your address book</source>
<translation type="unfinished"></translation>
</message>
@@ -3366,7 +3399,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<context>
<name>TransactionDesc</name>
<message numerus="yes">
- <location filename="../transactiondesc.cpp" line="+31"/>
+ <location filename="../transactiondesc.cpp" line="+35"/>
<source>Open for %n more block(s)</source>
<translation>
<numerusform>Open for %n more block</numerusform>
@@ -3414,7 +3447,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+23"/>
+ <location line="+22"/>
<source>Status</source>
<translation type="unfinished"></translation>
</message>
@@ -3473,12 +3506,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<location line="+12"/>
<location line="+54"/>
<location line="+30"/>
- <location line="+58"/>
+ <location line="+60"/>
<source>Credit</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
- <location line="-152"/>
+ <location line="-154"/>
<source>matures in %n more block(s)</source>
<translation>
<numerusform>matures in %n more block</numerusform>
@@ -3493,12 +3526,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<message>
<location line="+60"/>
<location line="+26"/>
- <location line="+61"/>
+ <location line="+63"/>
<source>Debit</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-77"/>
+ <location line="-79"/>
<source>Total debit</source>
<translation type="unfinished"></translation>
</message>
@@ -3549,12 +3582,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+18"/>
+ <location line="+19"/>
<source>Merchant</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+7"/>
+ <location line="+8"/>
<source>Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to &quot;not accepted&quot; and it won&apos;t be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source>
<translation type="unfinished"></translation>
</message>
@@ -3607,7 +3640,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<context>
<name>TransactionTableModel</name>
<message>
- <location filename="../transactiontablemodel.cpp" line="+226"/>
+ <location filename="../transactiontablemodel.cpp" line="+227"/>
<source>Date</source>
<translation type="unfinished">Date</translation>
</message>
@@ -3743,7 +3776,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<context>
<name>TransactionView</name>
<message>
- <location filename="../transactionview.cpp" line="+70"/>
+ <location filename="../transactionview.cpp" line="+71"/>
<location line="+16"/>
<source>All</source>
<translation type="unfinished"></translation>
@@ -3814,7 +3847,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+47"/>
+ <location line="+51"/>
<source>Abandon transaction</source>
<translation type="unfinished"></translation>
</message>
@@ -3864,7 +3897,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+193"/>
+ <location line="+199"/>
<source>Export Transaction History</source>
<translation type="unfinished"></translation>
</message>
@@ -3929,7 +3962,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+166"/>
+ <location line="+171"/>
<source>Range:</source>
<translation type="unfinished"></translation>
</message>
@@ -3942,7 +3975,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
- <location filename="../bitcoingui.cpp" line="+159"/>
+ <location filename="../bitcoingui.cpp" line="+154"/>
<source>Unit to show amounts in. Click to select another unit.</source>
<translation type="unfinished"></translation>
</message>
@@ -3958,19 +3991,19 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<context>
<name>WalletModel</name>
<message>
- <location filename="../walletmodel.cpp" line="+215"/>
+ <location filename="../walletmodel.cpp" line="+219"/>
<source>Send Coins</source>
<translation type="unfinished">Send Coins</translation>
</message>
<message>
- <location line="+289"/>
+ <location line="+301"/>
<location line="+39"/>
- <location line="+6"/>
+ <location line="+5"/>
<source>Fee bump error</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-45"/>
+ <location line="-44"/>
<source>Increasing transaction fee failed</source>
<translation type="unfinished"></translation>
</message>
@@ -4005,10 +4038,15 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
+ <location line="+5"/>
<source>Could not commit transaction</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <location line="+35"/>
+ <source>default wallet</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>WalletView</name>
@@ -4023,7 +4061,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished">Export the data in the current tab to a file</translation>
</message>
<message>
- <location line="+207"/>
+ <location line="+206"/>
<source>Backup Wallet</source>
<translation type="unfinished"></translation>
</message>
@@ -4053,7 +4091,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+54"/>
+ <location line="+44"/>
<source>Cancel</source>
<translation type="unfinished"></translation>
</message>
@@ -4066,7 +4104,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+28"/>
+ <location line="+20"/>
<source>Prune configured below the minimum of %d MiB. Please use a higher number.</source>
<translation type="unfinished"></translation>
</message>
@@ -4081,22 +4119,22 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+81"/>
+ <location line="+74"/>
<source>Error: A fatal internal error occurred, see debug.log for details</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+25"/>
+ <location line="+26"/>
<source>Pruning blockstore...</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+28"/>
+ <location line="+30"/>
<source>Unable to start HTTP server. See debug log for details.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-184"/>
+ <location line="-172"/>
<source>Bitcoin Core</source>
<translation type="unfinished">Bitcoin Core</translation>
</message>
@@ -4116,17 +4154,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+12"/>
+ <location line="+10"/>
<source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+8"/>
- <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+9"/>
+ <location line="+11"/>
<source>Please check that your computer&apos;s date and time are correct! If your clock is wrong, %s will not work properly.</source>
<translation type="unfinished"></translation>
</message>
@@ -4161,7 +4194,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+11"/>
+ <location line="+5"/>
<source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
<translation type="unfinished"></translation>
</message>
@@ -4197,6 +4230,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
</message>
<message>
<location line="+1"/>
+ <source>Config setting for %s only applied on %s network when in [%s] section.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Copyright (C) %i-%i</source>
<translation type="unfinished"></translation>
</message>
@@ -4212,11 +4250,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
</message>
<message>
<location line="+2"/>
- <source>Error creating %s: You can&apos;t create non-HD wallets with this version.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+1"/>
<source>Error initializing block database</source>
<translation>Error initializing block database</translation>
</message>
@@ -4246,7 +4279,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
+ <location line="+1"/>
<source>Error loading block database</source>
<translation>Error loading block database</translation>
</message>
@@ -4256,7 +4289,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation>Error opening block database</translation>
</message>
<message>
- <location line="+5"/>
+ <location line="+6"/>
<source>Error: Disk space is low!</source>
<translation>Error: Disk space is low!</translation>
</message>
@@ -4301,17 +4334,17 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+21"/>
+ <location line="+22"/>
<source>Specified blocks directory &quot;%s&quot; does not exist.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+26"/>
+ <location line="+24"/>
<source>Upgrading txindex database</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-43"/>
+ <location line="-42"/>
<source>Loading P2P addresses...</source>
<translation type="unfinished"></translation>
</message>
@@ -4346,12 +4379,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+7"/>
+ <location line="+8"/>
<source>The source code is available from %s.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+8"/>
+ <location line="+9"/>
<source>Transaction fee and change calculation failed</source>
<translation type="unfinished"></translation>
</message>
@@ -4367,21 +4400,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
</message>
<message>
<location line="+3"/>
- <source>Unsupported argument -benchmark ignored, use -debug=bench.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+1"/>
- <source>Unsupported argument -debugnet ignored, use -debug=net.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+1"/>
- <source>Unsupported argument -tor found, use -onion.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+1"/>
<source>Unsupported logging category %s=%s.</source>
<translation type="unfinished"></translation>
</message>
@@ -4406,12 +4424,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-171"/>
+ <location line="-158"/>
<source>Error: Listening for incoming connections failed (listen returned error %s)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+11"/>
+ <location line="+5"/>
<source>Invalid amount for -maxtxfee=&lt;amount&gt;: &apos;%s&apos; (must be at least the minrelay fee of %s to prevent stuck transactions)</source>
<translation type="unfinished"></translation>
</message>
@@ -4421,17 +4439,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+44"/>
+ <location line="+38"/>
<source>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+22"/>
- <source>Error loading %s: You can&apos;t disable HD on an already existing HD wallet</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+4"/>
+ <location line="+25"/>
<source>Error reading from database, shutting down.</source>
<translation type="unfinished"></translation>
</message>
@@ -4441,7 +4454,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+8"/>
+ <location line="+3"/>
+ <source>Error: Disk space is low for %s</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
<source>Information</source>
<translation>Information</translation>
</message>
@@ -4477,6 +4495,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
</message>
<message>
<location line="+4"/>
+ <source>Section [%s] is not recognized.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Signing transaction failed</source>
<translation>Signing transaction failed</translation>
</message>
@@ -4497,6 +4520,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
</message>
<message>
<location line="+4"/>
+ <source>The specified config file %s does not exist
+</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>The transaction amount is too small to pay the fee</source>
<translation type="unfinished"></translation>
</message>
@@ -4531,7 +4560,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+12"/>
+ <location line="+9"/>
<source>Verifying wallet(s)...</source>
<translation type="unfinished"></translation>
</message>
@@ -4556,17 +4585,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-197"/>
+ <location line="-182"/>
<source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+18"/>
- <source>Error loading %s: You can&apos;t enable HD on an already existing non-HD wallet</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+46"/>
+ <location line="+56"/>
<source>This is the transaction fee you may pay when fee estimates are not available.</source>
<translation type="unfinished"></translation>
</message>
@@ -4581,17 +4605,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+9"/>
- <source>Unsupported argument -socks found. Setting SOCKS version isn&apos;t possible anymore, only SOCKS5 proxies are supported.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+3"/>
- <source>Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+8"/>
+ <location line="+14"/>
<source>Warning: Unknown block versions being mined! It&apos;s possible unknown rules are in effect</source>
<translation type="unfinished"></translation>
</message>
@@ -4606,22 +4620,22 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+19"/>
+ <location line="+18"/>
<source>Error loading wallet %s. Duplicate -wallet filename specified.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+21"/>
+ <location line="+22"/>
<source>Keypool ran out, please call keypoolrefill first</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+19"/>
+ <location line="+20"/>
<source>Starting network threads...</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+4"/>
<source>The wallet will avoid paying less than the minimum relay fee.</source>
<translation type="unfinished"></translation>
</message>
@@ -4656,12 +4670,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation>Unknown network specified in -onlynet: &apos;%s&apos;</translation>
</message>
<message>
- <location line="-46"/>
+ <location line="-48"/>
<source>Insufficient funds</source>
<translation>Insufficient funds</translation>
</message>
<message>
- <location line="-134"/>
+ <location line="-120"/>
<source>Can&apos;t generate a change-address key. Private keys are disabled for this wallet.</source>
<translation type="unfinished"></translation>
</message>
@@ -4671,12 +4685,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+14"/>
+ <location line="+12"/>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+60"/>
+ <location line="+48"/>
<source>Warning: Private keys detected in wallet {%s} with disabled private keys</source>
<translation type="unfinished"></translation>
</message>
@@ -4706,12 +4720,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation>Rescanning...</translation>
</message>
<message>
- <location line="-43"/>
+ <location line="-42"/>
<source>Done loading</source>
<translation>Done loading</translation>
</message>
<message>
- <location line="+14"/>
+ <location line="+12"/>
<source>Error</source>
<translation>Error</translation>
</message>
diff --git a/src/qt/locale/bitcoin_en_GB.ts b/src/qt/locale/bitcoin_en_GB.ts
index 7da223f52e..92a08280d7 100644
--- a/src/qt/locale/bitcoin_en_GB.ts
+++ b/src/qt/locale/bitcoin_en_GB.ts
@@ -330,6 +330,10 @@
<translation>Wallet:</translation>
</message>
<message>
+ <source>default wallet</source>
+ <translation>default wallet</translation>
+ </message>
+ <message>
<source>Click to disable network activity.</source>
<translation>Click to disable network activity.</translation>
</message>
@@ -350,6 +354,10 @@
<translation>Reindexing blocks on disk...</translation>
</message>
<message>
+ <source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
+ <translation>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</translation>
+ </message>
+ <message>
<source>Send coins to a Bitcoin address</source>
<translation>Send coins to a Bitcoin address</translation>
</message>
@@ -760,6 +768,14 @@
<translation>The entered address "%1" is not a valid Bitcoin address.</translation>
</message>
<message>
+ <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source>
+ <translation>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book with label "%2".</source>
+ <translation>The entered address "%1" is already in the address book with label "%2".</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation>Could not unlock wallet.</translation>
</message>
@@ -834,7 +850,7 @@
</message>
<message>
<source>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</source>
- <translation>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</translation>
+ <translation>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterwards to keep your disk usage low.</translation>
</message>
<message>
<source>Use the default data directory</source>
@@ -1038,10 +1054,22 @@
<translation>&amp;Network</translation>
</message>
<message>
+ <source>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</source>
+ <translation>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</translation>
+ </message>
+ <message>
+ <source>Prune &amp;block storage to</source>
+ <translation>Prune &amp;block storage to</translation>
+ </message>
+ <message>
<source>GB</source>
<translation>GB</translation>
</message>
<message>
+ <source>Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation>Reverting this setting requires re-downloading the entire blockchain.</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation>(0 = auto, &lt;0 = leave that many cores free)</translation>
</message>
@@ -1308,6 +1336,10 @@
<translation>URI handling</translation>
</message>
<message>
+ <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source>
+ <translation>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</translation>
+ </message>
+ <message>
<source>Payment request fetch URL is invalid: %1</source>
<translation>Payment request fetch URL is invalid: %1</translation>
</message>
@@ -1505,10 +1537,18 @@
<context>
<name>QObject::QObject</name>
<message>
+ <source>Error parsing command line arguments: %1.</source>
+ <translation>Error parsing command line arguments: %1.</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
<translation>Error: Specified data directory "%1" does not exist.</translation>
</message>
<message>
+ <source>Error: Cannot parse configuration file: %1.</source>
+ <translation>Error: Cannot parse configuration file: %1.</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation>Error: %1</translation>
</message>
@@ -1564,7 +1604,7 @@
</message>
<message>
<source>Startup time</source>
- <translation>Startup time</translation>
+ <translation>Start up time</translation>
</message>
<message>
<source>Network</source>
@@ -1775,6 +1815,10 @@
<translation>&amp;Unban</translation>
</message>
<message>
+ <source>default wallet</source>
+ <translation>default wallet</translation>
+ </message>
+ <message>
<source>Welcome to the %1 RPC console.</source>
<translation>Welcome to the %1 RPC console.</translation>
</message>
@@ -1799,6 +1843,14 @@
<translation>Network activity disabled</translation>
</message>
<message>
+ <source>Executing command without any wallet</source>
+ <translation>Executing command without any wallet</translation>
+ </message>
+ <message>
+ <source>Executing command using "%1" wallet</source>
+ <translation>Executing command using "%1" wallet</translation>
+ </message>
+ <message>
<source>(node id: %1)</source>
<translation>(node id: %1)</translation>
</message>
@@ -1870,6 +1922,14 @@
<translation>Clear</translation>
</message>
<message>
+ <source>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</source>
+ <translation>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</translation>
+ </message>
+ <message>
+ <source>Generate native segwit (Bech32) address</source>
+ <translation>Generate native segwit (Bech32) address</translation>
+ </message>
+ <message>
<source>Requested payments history</source>
<translation>Requested payments history</translation>
</message>
@@ -2075,6 +2135,14 @@
<translation>collapse fee-settings</translation>
</message>
<message>
+ <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size.
+
+Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis per kB" for a transaction size of 500 bytes (half of 1 kB) would ultimately yield a fee of only 50 satoshis.</source>
+ <translation>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size.
+
+Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis per kB" for a transaction size of 500 bytes (half of 1 kB) would ultimately yield a fee of only 50 satoshis.</translation>
+ </message>
+ <message>
<source>per kilobyte</source>
<translation>per kilobyte</translation>
</message>
@@ -2195,6 +2263,14 @@
<translation>You can increase the fee later (signals Replace-By-Fee, BIP-125).</translation>
</message>
<message>
+ <source>from wallet %1</source>
+ <translation>from wallet %1</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction.</source>
+ <translation>Please, review your transaction.</translation>
+ </message>
+ <message>
<source>Transaction fee</source>
<translation>Transaction fee</translation>
</message>
@@ -2203,6 +2279,10 @@
<translation>Not signalling Replace-By-Fee, BIP-125.</translation>
</message>
<message>
+ <source>Total Amount</source>
+ <translation>Total Amount</translation>
+ </message>
+ <message>
<source>Confirm send coins</source>
<translation>Confirm send coins</translation>
</message>
@@ -2656,6 +2736,10 @@
<translation>Transaction total size</translation>
</message>
<message>
+ <source>Transaction virtual size</source>
+ <translation>Transaction virtual size</translation>
+ </message>
+ <message>
<source>Output index</source>
<translation>Output index</translation>
</message>
@@ -3116,6 +3200,10 @@
<translation>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</translation>
</message>
<message>
+ <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source>
+ <translation>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</translation>
+ </message>
+ <message>
<source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source>
<translation>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</translation>
</message>
@@ -3200,6 +3288,10 @@
<translation>Error loading %s</translation>
</message>
<message>
+ <source>Error loading %s: Private keys can only be disabled during creation</source>
+ <translation>Error loading %s: Private keys can only be disabled during creation</translation>
+ </message>
+ <message>
<source>Error loading %s: Wallet corrupted</source>
<translation>Error loading %s: Wallet corrupted</translation>
</message>
@@ -3252,6 +3344,14 @@
<translation>Invalid amount for -fallbackfee=&lt;amount&gt;: '%s'</translation>
</message>
<message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation>Specified blocks directory "%s" does not exist.</translation>
+ </message>
+ <message>
+ <source>Upgrading txindex database</source>
+ <translation>Upgrading txindex database</translation>
+ </message>
+ <message>
<source>Loading P2P addresses...</source>
<translation>Loading P2P addresses...</translation>
</message>
@@ -3292,6 +3392,10 @@
<translation>Unable to bind to %s on this computer. %s is probably already running.</translation>
</message>
<message>
+ <source>Unable to generate keys</source>
+ <translation>Unable to generate keys</translation>
+ </message>
+ <message>
<source>Unsupported argument -benchmark ignored, use -debug=bench.</source>
<translation>Unsupported argument -benchmark ignored, use -debug=bench.</translation>
</message>
@@ -3465,7 +3569,7 @@
</message>
<message>
<source>Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.</source>
- <translation>Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.</translation>
+ <translation>Unsupported argument -socks found. Setting SOCKS version isn't possible any more, only SOCKS5 proxies are supported.</translation>
</message>
<message>
<source>Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.</source>
@@ -3528,6 +3632,26 @@
<translation>Insufficient funds</translation>
</message>
<message>
+ <source>Can't generate a change-address key. Private keys are disabled for this wallet.</source>
+ <translation>Can't generate a change-address key. Private keys are disabled for this wallet.</translation>
+ </message>
+ <message>
+ <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use -upgradewallet=169900 or -upgradewallet with no version specified.</source>
+ <translation>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use -upgradewallet=169900 or -upgradewallet with no version specified.</translation>
+ </message>
+ <message>
+ <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
+ <translation>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</translation>
+ </message>
+ <message>
+ <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source>
+ <translation>Warning: Private keys detected in wallet {%s} with disabled private keys</translation>
+ </message>
+ <message>
+ <source>Cannot write to data directory '%s'; check permissions.</source>
+ <translation>Cannot write to data directory '%s'; check permissions.</translation>
+ </message>
+ <message>
<source>Loading block index...</source>
<translation>Loading block index...</translation>
</message>
diff --git a/src/qt/locale/bitcoin_es.ts b/src/qt/locale/bitcoin_es.ts
index 0ae126eb33..7b07380606 100644
--- a/src/qt/locale/bitcoin_es.ts
+++ b/src/qt/locale/bitcoin_es.ts
@@ -3199,6 +3199,10 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis
<translation>Error leyendo %s!. Todas las claves se han leido correctamente, pero los datos de transacciones o la libreta de direcciones pueden faltar o ser incorrectos.</translation>
</message>
<message>
+ <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source>
+ <translation>Grupo de salida por dirección, seleccionando todo o nada, en lugar de seleccionar en una base para salida. La privacidad se mejora como una dirección utilizada una sola vez (a menos que alguien lo envíe después de gastarlo), a menos que alguien envíe una solicitud, pero puede resultar en tarifas ligeramente más altas ya que la selección de la moneda puede ser inferior a la óptima debido a la limitación adicional después de gastarla. (por defecto, predeterminado %u)</translation>
+ </message>
+ <message>
<source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source>
<translation>Por favor, compruebe si la fecha y hora en su computadora son correctas! Si su reloj esta mal, %s no trabajara correctamente. </translation>
</message>
@@ -3339,6 +3343,10 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis
<translation>Cantidad inválida para -fallbackfee=&lt;amount&gt;: '%s'</translation>
</message>
<message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation>El directorio de bloques «%s» especificado no existe.</translation>
+ </message>
+ <message>
<source>Upgrading txindex database</source>
<translation>Actualización de la base de datos txindex</translation>
</message>
@@ -3491,12 +3499,6 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis
<translation>El -walletdir "%s" indicado no es un directorio</translation>
</message>
<message>
- <source>Specified blocks directory "%s" does not exist.
-</source>
- <translation>El directorio de bloques especificado "%s" no existe.
-</translation>
- </message>
- <message>
<source>The transaction amount is too small to pay the fee</source>
<translation>Cantidad de la transacción demasiado pequeña para pagar la comisión</translation>
</message>
diff --git a/src/qt/locale/bitcoin_es_VE.ts b/src/qt/locale/bitcoin_es_VE.ts
index 9c7fb2e2a0..b500c16352 100644
--- a/src/qt/locale/bitcoin_es_VE.ts
+++ b/src/qt/locale/bitcoin_es_VE.ts
@@ -50,6 +50,10 @@
<translation>Elige la dirección para recibir monedas</translation>
</message>
<message>
+ <source>C&amp;hoose</source>
+ <translation>Escoger</translation>
+ </message>
+ <message>
<source>Sending addresses</source>
<translation>Envío de direcciones</translation>
</message>
@@ -66,6 +70,10 @@
<translation>Estas son tus direcciones Bitcoin para recibir pagos. Es recomendable usar una nueva dirección de recibo para cada transacción.</translation>
</message>
<message>
+ <source>&amp;Copy Address</source>
+ <translation>Copiar dirección</translation>
+ </message>
+ <message>
<source>Copy &amp;Label</source>
<translation>Copiar &amp;Etiqueta</translation>
</message>
@@ -77,10 +85,30 @@
<source>Export Address List</source>
<translation>Exportar lista de direcciones</translation>
</message>
- </context>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Separar los archivos con comas (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Error al exportar</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Tuvimos un problema al guardar la dirección en la lista %1. Intenta de Nuevo.</translation>
+ </message>
+</context>
<context>
<name>AddressTableModel</name>
<message>
+ <source>Label</source>
+ <translation>Nombre</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Direccion</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(sin etiqueta)</translation>
</message>
@@ -103,6 +131,40 @@
<source>Repeat new passphrase</source>
<translation>Repetir nueva frase de contraseña</translation>
</message>
+ <message>
+ <source>Show password</source>
+ <translation>Mostrar contraseña</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Cifrar monedero</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Esta operación necesita su frase de contraseña de la billetera para desbloquearla.
+</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Desbloquear monedero</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Esta operación necesita su frase de contraseña de la billetera para descifrar la billetera.
+</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Descifrar monedero</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Cambiar frase secreta</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Confirmar cifrado de billetera</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -577,6 +639,14 @@
<translation>&amp;Copiar Dirección</translation>
</message>
<message>
+ <source>Address</source>
+ <translation>Direccion</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Nombre</translation>
+ </message>
+ <message>
<source>Wallet</source>
<translation>Billetera</translation>
</message>
@@ -584,6 +654,10 @@
<context>
<name>RecentRequestsTableModel</name>
<message>
+ <source>Label</source>
+ <translation>Nombre</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(sin etiqueta)</translation>
</message>
@@ -670,12 +744,32 @@
<context>
<name>TransactionTableModel</name>
<message>
+ <source>Label</source>
+ <translation>Nombre</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(sin etiqueta)</translation>
</message>
</context>
<context>
<name>TransactionView</name>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Separar los archivos con comas (*.csv)</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Nombre</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Direccion</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Error al exportar</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
diff --git a/src/qt/locale/bitcoin_eu_ES.ts b/src/qt/locale/bitcoin_eu_ES.ts
index 1abc55acce..e266621d16 100644
--- a/src/qt/locale/bitcoin_eu_ES.ts
+++ b/src/qt/locale/bitcoin_eu_ES.ts
@@ -3,7 +3,7 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation>Klikatu eskuinean helbidea edo etiketa aldatzeko</translation>
+ <translation>Klikatu eskuinarekin helbidea edo etiketa aldatzeko</translation>
</message>
<message>
<source>Create a new address</source>
@@ -136,6 +136,14 @@
<translation>Pasahitz berria errepiikatu</translation>
</message>
<message>
+ <source>Show password</source>
+ <translation>Erakutsi pasahitza</translation>
+ </message>
+ <message>
+ <source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;ten or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
+ <translation>Sartu pasaesaldi bat diru-zorrorako. Mesedez erabili ausazko hamar edo gehiago karaktere edo zortzi edo gehiago hitz.</translation>
+ </message>
+ <message>
<source>Encrypt wallet</source>
<translation>Diruzorroa enkriptatu</translation>
</message>
@@ -274,6 +282,10 @@
<translation>Fitxen tresna-barra</translation>
</message>
<message>
+ <source>Error</source>
+ <translation>Akatsa</translation>
+ </message>
+ <message>
<source>Up to date</source>
<translation>Eguneratua</translation>
</message>
@@ -368,6 +380,10 @@
</context>
<context>
<name>Intro</name>
+ <message>
+ <source>Error</source>
+ <translation>Akatsa</translation>
+ </message>
</context>
<context>
<name>ModalOverlay</name>
@@ -385,6 +401,10 @@
<source>Options</source>
<translation>Aukerak</translation>
</message>
+ <message>
+ <source>Error</source>
+ <translation>Akatsa</translation>
+ </message>
</context>
<context>
<name>OverviewPage</name>
@@ -808,6 +828,10 @@
<context>
<name>bitcoin-core</name>
<message>
+ <source>Loading wallet...</source>
+ <translation>Diru-zorroa kargatzen</translation>
+ </message>
+ <message>
<source>Rescanning...</source>
<translation>Birbilatzen...</translation>
</message>
@@ -815,5 +839,9 @@
<source>Done loading</source>
<translation>Zamaketa amaitua</translation>
</message>
- </context>
+ <message>
+ <source>Error</source>
+ <translation>Akatsa</translation>
+ </message>
+</context>
</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_fa.ts b/src/qt/locale/bitcoin_fa.ts
index 1fa0d9fb44..c2f2930a08 100644
--- a/src/qt/locale/bitcoin_fa.ts
+++ b/src/qt/locale/bitcoin_fa.ts
@@ -997,6 +997,10 @@
<context>
<name>PeerTableModel</name>
<message>
+ <source>Ping</source>
+ <translation>پینگ</translation>
+ </message>
+ <message>
<source>Sent</source>
<translation>ارسال شده</translation>
</message>
@@ -1811,10 +1815,30 @@
</context>
<context>
<name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>فرستادن سکه ها</translation>
+ </message>
+ <message>
+ <source>Current fee:</source>
+ <translation>دستمزد فعلی</translation>
+ </message>
+ <message>
+ <source>Increase:</source>
+ <translation>افزایش</translation>
+ </message>
+ <message>
+ <source>New fee:</source>
+ <translation>تعرفه جدید</translation>
+ </message>
</context>
<context>
<name>WalletView</name>
<message>
+ <source>&amp;Export</source>
+ <translation>و صدور</translation>
+ </message>
+ <message>
<source>Export the data in the current tab to a file</source>
<translation>صدور داده‌های برگهٔ فعلی به یک پرونده</translation>
</message>
diff --git a/src/qt/locale/bitcoin_fa_IR.ts b/src/qt/locale/bitcoin_fa_IR.ts
index 7912f43582..be00b00656 100644
--- a/src/qt/locale/bitcoin_fa_IR.ts
+++ b/src/qt/locale/bitcoin_fa_IR.ts
@@ -231,6 +231,10 @@
<context>
<name>BanTableModel</name>
<message>
+ <source>IP/Netmask</source>
+ <translation>آی پی/نت ماسک</translation>
+ </message>
+ <message>
<source>Banned Until</source>
<translation>مسدودشده تا</translation>
</message>
@@ -239,7 +243,7 @@
<name>BitcoinGUI</name>
<message>
<source>Sign &amp;message...</source>
- <translation>امضا و پیام</translation>
+ <translation>ثبت &amp;پیام</translation>
</message>
<message>
<source>Synchronizing with network...</source>
@@ -318,6 +322,10 @@
<translation>دریافت آدرس ها</translation>
</message>
<message>
+ <source>Open &amp;URI...</source>
+ <translation>بازکردن آدرس...</translation>
+ </message>
+ <message>
<source>Wallet:</source>
<translation>کیف پول:</translation>
</message>
@@ -362,6 +370,10 @@
<translation>پنجره دیباگ</translation>
</message>
<message>
+ <source>Open debugging and diagnostic console</source>
+ <translation>باز کردن کنسول دی باگ و تشخیص</translation>
+ </message>
+ <message>
<source>&amp;Verify message...</source>
<translation>تایید پیام</translation>
</message>
@@ -433,6 +445,10 @@
<source>Open a bitcoin: URI or payment request</source>
<translation>بازکردن بیت‌کوین: آدرس یا درخواست پرداخت</translation>
</message>
+ <message>
+ <source>&amp;Command-line options</source>
+ <translation>گزینه های خط فرمان</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network</source>
<translation><numerusform>%n ارتباط فعال به شبکه بیت‌کوین</numerusform><numerusform>%n ارتباط فعال به شبکه بیت‌کوین</numerusform></translation>
@@ -474,6 +490,10 @@
<translation>به روز</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>در حال اتصال به همتاهای شبکه...</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>در حال روزآمد سازی..</translation>
</message>
@@ -505,7 +525,11 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>wallet رمزگذاری شد و در حال حاضر قفل است</translation>
</message>
- </context>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>خطای بحرانی رخ داده است. بیتکوین دیگر به صورت ایمن قادر به ادامه دادن نمی‌باشد و خارج خواهد شد.</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -517,6 +541,10 @@
<translation>مقدار</translation>
</message>
<message>
+ <source>Bytes:</source>
+ <translation>بایت ها:</translation>
+ </message>
+ <message>
<source>Amount:</source>
<translation>میزان وجه:</translation>
</message>
@@ -525,6 +553,14 @@
<translation>هزینه</translation>
</message>
<message>
+ <source>Dust:</source>
+ <translation>گرد و غبار با داست:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation>بعد از احتساب کارمزد</translation>
+ </message>
+ <message>
<source>Change:</source>
<translation>تغییر</translation>
</message>
@@ -589,6 +625,22 @@
<translation>کپی هزینه</translation>
</message>
<message>
+ <source>Copy after fee</source>
+ <translation>کپی کردن بعد از احتساب کارمزد</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>کپی کردن بایت ها</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>کپی کردن داست:</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>کپی کردن تغییر</translation>
+ </message>
+ <message>
<source>yes</source>
<translation>بله</translation>
</message>
@@ -600,7 +652,11 @@
<source>(no label)</source>
<translation>(برچسب ندارد)</translation>
</message>
- </context>
+ <message>
+ <source>(change)</source>
+ <translation>(تغییر)</translation>
+ </message>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -631,21 +687,41 @@
<source>The entered address "%1" is not a valid Bitcoin address.</source>
<translation>آدرس وارد شده "%1" آدرس معتبر بیت کوین نیست.</translation>
</message>
- </context>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>نمیتوان کیف پول را باز کرد.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>تولید کلید جدید به خطا انجامید.</translation>
+ </message>
+</context>
<context>
<name>FreespaceChecker</name>
<message>
+ <source>A new data directory will be created.</source>
+ <translation>پوشه داده جدید ساخته خواهد شد</translation>
+ </message>
+ <message>
<source>name</source>
<translation>نام</translation>
</message>
- </context>
+ <message>
+ <source>Cannot create data directory here.</source>
+ <translation>نمیتوان در اینجا پوشه داده ساخت.</translation>
+ </message>
+</context>
<context>
<name>HelpMessageDialog</name>
<message>
<source>version</source>
<translation>نسخه</translation>
</message>
- </context>
+ <message>
+ <source>Command-line options</source>
+ <translation>گزینه های خط-فرمان </translation>
+ </message>
+</context>
<context>
<name>Intro</name>
<message>
@@ -657,6 +733,14 @@
<translation>به %1 خوش آمدید.</translation>
</message>
<message>
+ <source>Use the default data directory</source>
+ <translation>استفاده کردن از پوشه داده پیشفرض</translation>
+ </message>
+ <message>
+ <source>Use a custom data directory:</source>
+ <translation>استفاده کردن از پوشه داده مخصوص:</translation>
+ </message>
+ <message>
<source>Bitcoin</source>
<translation>بیت کوین</translation>
</message>
@@ -692,6 +776,10 @@
<translation>پیشرفت</translation>
</message>
<message>
+ <source>Progress increase per hour</source>
+ <translation>سرعت افزایش پیشرفت بر ساعت</translation>
+ </message>
+ <message>
<source>calculating...</source>
<translation>در حال محاسبه...</translation>
</message>
@@ -702,7 +790,27 @@
</context>
<context>
<name>OpenURIDialog</name>
- </context>
+ <message>
+ <source>Open URI</source>
+ <translation>باز کردن آدرس URL</translation>
+ </message>
+ <message>
+ <source>Open payment request from URI or file</source>
+ <translation>بازکردن درخواست پرداخت از آدرس URL یا فایل</translation>
+ </message>
+ <message>
+ <source>URI:</source>
+ <translation>آدرس:</translation>
+ </message>
+ <message>
+ <source>Select payment request file</source>
+ <translation>انتخاب فایل درخواست وجه (Payment Request)</translation>
+ </message>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>انتخاب فایل درحواست وجه برای باز کردن</translation>
+ </message>
+</context>
<context>
<name>OptionsDialog</name>
<message>
@@ -710,10 +818,26 @@
<translation>گزینه ها</translation>
</message>
<message>
+ <source>&amp;Main</source>
+ <translation>&amp;اصلی</translation>
+ </message>
+ <message>
+ <source>Size of &amp;database cache</source>
+ <translation>اندازه کش پایگاه داده.</translation>
+ </message>
+ <message>
<source>MB</source>
<translation>مگابایت</translation>
</message>
<message>
+ <source>Open Configuration File</source>
+ <translation>بازکردن فایل پیکربندی</translation>
+ </message>
+ <message>
+ <source>Reset all client options to default.</source>
+ <translation>ریست تمامی تنظیمات کلاینت به پیشفرض</translation>
+ </message>
+ <message>
<source>&amp;Reset Options</source>
<translation>تنظیم مجدد گزینه ها</translation>
</message>
@@ -722,14 +846,50 @@
<translation>شبکه</translation>
</message>
<message>
+ <source>GB</source>
+ <translation>گیگابایت</translation>
+ </message>
+ <message>
<source>W&amp;allet</source>
<translation>کیف پول</translation>
</message>
<message>
+ <source>Expert</source>
+ <translation>حرفه‌ای</translation>
+ </message>
+ <message>
+ <source>Accept connections from outside.</source>
+ <translation>پذیرفتن اتصال شدن از بیرون</translation>
+ </message>
+ <message>
+ <source>Allow incomin&amp;g connections</source>
+ <translation>اجازه دادن به ارتباطات ورودی</translation>
+ </message>
+ <message>
+ <source>Proxy &amp;IP:</source>
+ <translation>پراکسی و آی‌پی:</translation>
+ </message>
+ <message>
<source>&amp;Port:</source>
<translation>پورت:</translation>
</message>
<message>
+ <source>IPv4</source>
+ <translation>IPv4</translation>
+ </message>
+ <message>
+ <source>IPv6</source>
+ <translation>IPv6</translation>
+ </message>
+ <message>
+ <source>Tor</source>
+ <translation>شبکه Tor</translation>
+ </message>
+ <message>
+ <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source>
+ <translation>اتصال به شبکه بیت کوین با استفاده از پراکسی SOCKS5 برای استفاده از سرویس مخفی تور</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation>پنجره</translation>
</message>
@@ -738,6 +898,18 @@
<translation>نمایش</translation>
</message>
<message>
+ <source>User Interface &amp;language:</source>
+ <translation>زبان واسط کاربری:</translation>
+ </message>
+ <message>
+ <source>&amp;Unit to show amounts in:</source>
+ <translation>واحد نمایشگر مقادیر:</translation>
+ </message>
+ <message>
+ <source>&amp;Third party transaction URLs</source>
+ <translation>URLهای تراکنش شخص ثالث</translation>
+ </message>
+ <message>
<source>&amp;OK</source>
<translation>تایید</translation>
</message>
@@ -750,10 +922,42 @@
<translation>پیش فرض</translation>
</message>
<message>
+ <source>none</source>
+ <translation>خالی</translation>
+ </message>
+ <message>
+ <source>Confirm options reset</source>
+ <translation>تایید ریست تنظیمات</translation>
+ </message>
+ <message>
+ <source>Client restart required to activate changes.</source>
+ <translation>کلاینت نیازمند ریست شدن است برای فعال کردن تغییرات</translation>
+ </message>
+ <message>
+ <source>Client will be shut down. Do you want to proceed?</source>
+ <translation>کلاینت خاموش خواهد شد.آیا میخواهید ادامه دهید؟</translation>
+ </message>
+ <message>
+ <source>Configuration options</source>
+ <translation>تنظیمات پیکربندی</translation>
+ </message>
+ <message>
<source>Error</source>
<translation>خطا</translation>
</message>
- </context>
+ <message>
+ <source>The configuration file could not be opened.</source>
+ <translation>فایل پیکربندی قادر به بازشدن نبود.</translation>
+ </message>
+ <message>
+ <source>This change would require a client restart.</source>
+ <translation>تغییرات منوط به ریست کاربر است.</translation>
+ </message>
+ <message>
+ <source>The supplied proxy address is invalid.</source>
+ <translation>آدرس پراکسی ارائه شده نامعتبر است.</translation>
+ </message>
+</context>
<context>
<name>OverviewPage</name>
<message>
@@ -765,18 +969,46 @@
<translation>اطلاعات نمایش داده شده ممکن است روزآمد نباشد. wallet شما به صورت خودکار بعد از برقراری اتصال با شبکه bitcoin به روز می شود اما این فرایند هنوز تکمیل نشده است.</translation>
</message>
<message>
+ <source>Watch-only:</source>
+ <translation>فقط قابل-مشاهده:</translation>
+ </message>
+ <message>
<source>Available:</source>
<translation>در دسترس:</translation>
</message>
<message>
+ <source>Your current spendable balance</source>
+ <translation>موجودی قابل خرج در الان</translation>
+ </message>
+ <message>
<source>Pending:</source>
<translation>در حال انتظار:</translation>
</message>
<message>
+ <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source>
+ <translation>تعداد تراکنشهایی که نیاز به تایید دارند و هنوز در مانده حساب جاری شما به حساب نیامده اند</translation>
+ </message>
+ <message>
+ <source>Mined balance that has not yet matured</source>
+ <translation>موجودی استخراج شده هنوز کامل نشده است</translation>
+ </message>
+ <message>
+ <source>Balances</source>
+ <translation>موجودی ها</translation>
+ </message>
+ <message>
<source>Total:</source>
<translation>کل:</translation>
</message>
<message>
+ <source>Your current total balance</source>
+ <translation>موجودی شما در همین لحظه</translation>
+ </message>
+ <message>
+ <source>Your current balance in watch-only addresses</source>
+ <translation>موجودی شما در همین لحظه در آدرس های Watch only Addresses </translation>
+ </message>
+ <message>
<source>Spendable:</source>
<translation>قابل مصرف:</translation>
</message>
@@ -784,13 +1016,65 @@
<source>Recent transactions</source>
<translation>تراکنش های اخیر</translation>
</message>
+ <message>
+ <source>Unconfirmed transactions to watch-only addresses</source>
+ <translation>تراکنش های تایید نشده به آدرس های فقط قابل مشاهده watch-only</translation>
+ </message>
+ <message>
+ <source>Mined balance in watch-only addresses that has not yet matured</source>
+ <translation>موجودی استخراج شده در آدرس های فقط قابل مشاهده هنوز کامل نشده است</translation>
+ </message>
</context>
<context>
<name>PaymentServer</name>
+ <message>
+ <source>Payment request error</source>
+ <translation>درخواست پرداخت با خطا مواجه شد</translation>
+ </message>
+ <message>
+ <source>Payment request rejected</source>
+ <translation>درخواست پرداخت رد شد</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>درخواست پرداخت منقضی شد یا تاریخ آن گذشت.</translation>
+ </message>
+ <message>
+ <source>Payment request is not initialized.</source>
+ <translation>درخواست پرداخت, با مقداردهی اولیه یکسان نبود.</translation>
+ </message>
+ <message>
+ <source>Invalid payment request.</source>
+ <translation>درخواست پرداخت نامعتبر بود.</translation>
+ </message>
+ <message>
+ <source>Network request error</source>
+ <translation>درخواست از شبکه با خطا مواجه شد</translation>
+ </message>
</context>
<context>
<name>PeerTableModel</name>
- </context>
+ <message>
+ <source>Node/Service</source>
+ <translation>گره/خدمت</translation>
+ </message>
+ <message>
+ <source>NodeId</source>
+ <translation>شناسه گره</translation>
+ </message>
+ <message>
+ <source>Ping</source>
+ <translation>پینگ</translation>
+ </message>
+ <message>
+ <source>Sent</source>
+ <translation>فرستاده شد</translation>
+ </message>
+ <message>
+ <source>Received</source>
+ <translation>دریافت شد</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
<message>
@@ -798,6 +1082,14 @@
<translation>میزان</translation>
</message>
<message>
+ <source>None</source>
+ <translation>هیچ کدام</translation>
+ </message>
+ <message>
+ <source>N/A</source>
+ <translation>موجود نیست</translation>
+ </message>
+ <message>
<source>unknown</source>
<translation>ناشناس</translation>
</message>
@@ -807,18 +1099,58 @@
</context>
<context>
<name>QRImageWidget</name>
- </context>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;ذخیره کردن Image...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>&amp;کپی کردن image</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>ذحیره کردن Qr Code</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>تصویر با فرمت PNG انتخاب(*.png)</translation>
+ </message>
+</context>
<context>
<name>RPCConsole</name>
<message>
+ <source>N/A</source>
+ <translation>موجود نیست</translation>
+ </message>
+ <message>
<source>Client version</source>
<translation>ویرایش کنسول RPC</translation>
</message>
<message>
+ <source>&amp;Information</source>
+ <translation>&amp;اطلاعات</translation>
+ </message>
+ <message>
+ <source>Debug window</source>
+ <translation>پنجره یا صفحه دی باگ</translation>
+ </message>
+ <message>
+ <source>General</source>
+ <translation>عمومی</translation>
+ </message>
+ <message>
+ <source>Datadir</source>
+ <translation>پوشه داده Datadir</translation>
+ </message>
+ <message>
<source>Network</source>
<translation>شبکه</translation>
</message>
<message>
+ <source>Name</source>
+ <translation>نام</translation>
+ </message>
+ <message>
<source>Number of connections</source>
<translation>تعداد اتصال</translation>
</message>
@@ -831,14 +1163,174 @@
<translation>تعداد زنجیره های حاضر</translation>
</message>
<message>
+ <source>Current number of transactions</source>
+ <translation>تعداد تراکنش ها در حال حاضر</translation>
+ </message>
+ <message>
+ <source>Memory usage</source>
+ <translation>حافظه استفاده شده</translation>
+ </message>
+ <message>
+ <source>Wallet: </source>
+ <translation>کیف پول:</translation>
+ </message>
+ <message>
+ <source>(none)</source>
+ <translation>(هیچ کدام)</translation>
+ </message>
+ <message>
+ <source>&amp;Reset</source>
+ <translation>&amp;ریست کردن</translation>
+ </message>
+ <message>
+ <source>Received</source>
+ <translation>دریافت شد</translation>
+ </message>
+ <message>
+ <source>Sent</source>
+ <translation>فرستاده شد</translation>
+ </message>
+ <message>
+ <source>&amp;Peers</source>
+ <translation>&amp;همتاها</translation>
+ </message>
+ <message>
+ <source>Banned peers</source>
+ <translation>همتاهای بن شده</translation>
+ </message>
+ <message>
+ <source>Select a peer to view detailed information.</source>
+ <translation>انتخاب همتا یا جفت برای جزییات اطلاعات</translation>
+ </message>
+ <message>
+ <source>Whitelisted</source>
+ <translation>لیست سفید شده یا لیست سالم WhiteList</translation>
+ </message>
+ <message>
+ <source>Direction</source>
+ <translation>مسیر</translation>
+ </message>
+ <message>
+ <source>Version</source>
+ <translation>نسخه</translation>
+ </message>
+ <message>
+ <source>Decrease font size</source>
+ <translation>کاهش دادن اندازه فونت</translation>
+ </message>
+ <message>
+ <source>Increase font size</source>
+ <translation>افزایش دادن اندازه فونت</translation>
+ </message>
+ <message>
+ <source>Services</source>
+ <translation>خدمات</translation>
+ </message>
+ <message>
+ <source>Connection Time</source>
+ <translation>زمان اتصال</translation>
+ </message>
+ <message>
+ <source>Last Send</source>
+ <translation>آخرین ارسال</translation>
+ </message>
+ <message>
+ <source>Last Receive</source>
+ <translation>آخرین دریافت</translation>
+ </message>
+ <message>
+ <source>Ping Time</source>
+ <translation>مدت زمان پینگ</translation>
+ </message>
+ <message>
+ <source>Ping Wait</source>
+ <translation>انتظار پینگ</translation>
+ </message>
+ <message>
+ <source>Min Ping</source>
+ <translation>حداقل پینگ</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation>زمان آخرین بلوک</translation>
</message>
<message>
+ <source>&amp;Open</source>
+ <translation>&amp;بازکردن</translation>
+ </message>
+ <message>
+ <source>&amp;Network Traffic</source>
+ <translation>&amp;شلوغی شبکه</translation>
+ </message>
+ <message>
+ <source>Totals</source>
+ <translation>جمع کل ها</translation>
+ </message>
+ <message>
+ <source>In:</source>
+ <translation>به یا داخل:</translation>
+ </message>
+ <message>
+ <source>Out:</source>
+ <translation>خارج شده:</translation>
+ </message>
+ <message>
+ <source>Clear console</source>
+ <translation>پاک کردن کنسول</translation>
+ </message>
+ <message>
+ <source>1 &amp;hour</source>
+ <translation>1 &amp;ساعت</translation>
+ </message>
+ <message>
+ <source>1 &amp;day</source>
+ <translation>1 &amp;روز</translation>
+ </message>
+ <message>
+ <source>1 &amp;week</source>
+ <translation>1 &amp;هفته</translation>
+ </message>
+ <message>
+ <source>1 &amp;year</source>
+ <translation>1 &amp;سال</translation>
+ </message>
+ <message>
+ <source>&amp;Disconnect</source>
+ <translation>&amp;قطع شدن</translation>
+ </message>
+ <message>
+ <source>Ban for</source>
+ <translation>بن یا بن شده برای</translation>
+ </message>
+ <message>
+ <source>&amp;Unban</source>
+ <translation>&amp;خارج کردن از بن</translation>
+ </message>
+ <message>
<source>default wallet</source>
<translation>کیف پول پیش‌فرض</translation>
</message>
- </context>
+ <message>
+ <source>Network activity disabled</source>
+ <translation>فعالیت شبکه غیر فعال شد</translation>
+ </message>
+ <message>
+ <source>never</source>
+ <translation>هیچ وقت</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>بله</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>خیر</translation>
+ </message>
+ <message>
+ <source>Unknown</source>
+ <translation>ناشناس یا نامعلوم</translation>
+ </message>
+</context>
<context>
<name>ReceiveCoinsDialog</name>
<message>
@@ -854,14 +1346,46 @@
<translation>پیام:</translation>
</message>
<message>
+ <source>Use this form to request payments. All fields are &lt;b&gt;optional&lt;/b&gt;.</source>
+ <translation>از این فرم استفاده کنید برای درخواست پرداخت ها.تمامی گزینه ها &lt;b&gt;اختیاری&lt;/b&gt;هستند.</translation>
+ </message>
+ <message>
+ <source>Clear all fields of the form.</source>
+ <translation>پاک کردن تمامی گزینه های این فرم</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>پاک کردن</translation>
+ </message>
+ <message>
+ <source>Requested payments history</source>
+ <translation>تاریخچه پرداخت های درخواست شده</translation>
+ </message>
+ <message>
+ <source>&amp;Request payment</source>
+ <translation>&amp;درخواست پرداخت</translation>
+ </message>
+ <message>
+ <source>Show</source>
+ <translation>نمایش</translation>
+ </message>
+ <message>
<source>Remove</source>
<translation>حذف</translation>
</message>
<message>
+ <source>Copy URI</source>
+ <translation>کپی کردن آدرس URL</translation>
+ </message>
+ <message>
<source>Copy label</source>
<translation>کپی برچسب</translation>
</message>
<message>
+ <source>Copy message</source>
+ <translation>کپی کردن پیام</translation>
+ </message>
+ <message>
<source>Copy amount</source>
<translation>کپی مقدار</translation>
</message>
@@ -869,18 +1393,46 @@
<context>
<name>ReceiveRequestDialog</name>
<message>
+ <source>QR Code</source>
+ <translation>کی یو آر کد Qr Code</translation>
+ </message>
+ <message>
+ <source>Copy &amp;URI</source>
+ <translation>کپی کردن &amp;آدرس URL</translation>
+ </message>
+ <message>
<source>Copy &amp;Address</source>
<translation>کپی آدرس</translation>
</message>
<message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;ذخیره کردن تصویر...</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>اطلاعات پرداخت</translation>
+ </message>
+ <message>
+ <source>URI</source>
+ <translation>آدرس URL</translation>
+ </message>
+ <message>
<source>Address</source>
<translation>آدرس</translation>
</message>
<message>
+ <source>Amount</source>
+ <translation>میزان وجه:</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>برچسب</translation>
</message>
<message>
+ <source>Message</source>
+ <translation>پیام</translation>
+ </message>
+ <message>
<source>Wallet</source>
<translation>کیف پول</translation>
</message>
@@ -888,14 +1440,34 @@
<context>
<name>RecentRequestsTableModel</name>
<message>
+ <source>Date</source>
+ <translation>تاریخ</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>برچسب</translation>
</message>
<message>
+ <source>Message</source>
+ <translation>پیام</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(برچسب ندارد)</translation>
</message>
- </context>
+ <message>
+ <source>(no message)</source>
+ <translation>(بدون پیام)</translation>
+ </message>
+ <message>
+ <source>(no amount requested)</source>
+ <translation>(هیچ درخواست پرداخت وجود ندارد)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation>درخواست شده</translation>
+ </message>
+</context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -903,6 +1475,14 @@
<translation>سکه های ارسالی</translation>
</message>
<message>
+ <source>Coin Control Features</source>
+ <translation>قابلیت های کنترل کوین</translation>
+ </message>
+ <message>
+ <source>automatically selected</source>
+ <translation>به صورت خودکار انتخاب شده</translation>
+ </message>
+ <message>
<source>Insufficient funds!</source>
<translation>وجوه ناکافی</translation>
</message>
@@ -911,6 +1491,10 @@
<translation>مقدار</translation>
</message>
<message>
+ <source>Bytes:</source>
+ <translation>بایت ها:</translation>
+ </message>
+ <message>
<source>Amount:</source>
<translation>میزان وجه:</translation>
</message>
@@ -919,18 +1503,86 @@
<translation>هزینه</translation>
</message>
<message>
+ <source>After Fee:</source>
+ <translation>بعد از احتساب کارمزد</translation>
+ </message>
+ <message>
<source>Change:</source>
<translation>تغییر</translation>
</message>
<message>
+ <source>Custom change address</source>
+ <translation>تغییر آدرس مخصوص</translation>
+ </message>
+ <message>
+ <source>Transaction Fee:</source>
+ <translation>کارمزد تراکنش:</translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>انتخاب...</translation>
+ </message>
+ <message>
+ <source>Warning: Fee estimation is currently not possible.</source>
+ <translation>هشدار:تخمین کارمزد در حال حاضر امکان پذیر نیست.</translation>
+ </message>
+ <message>
+ <source>collapse fee-settings</source>
+ <translation>تنظیمات کاهش کارمزد</translation>
+ </message>
+ <message>
+ <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size.
+
+Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis per kB" for a transaction size of 500 bytes (half of 1 kB) would ultimately yield a fee of only 50 satoshis.</source>
+ <translation>مشخص کردن هزینه کارمزد مخصوص به ازاری کیلوبایت(1,000 بایت) حجم مجازی تراکنش
+
+توجه: از آن جایی که کارمزد بر اساس هر بایت محاسبه میشود,هزینه کارمزد"100 ساتوشی بر کیلو بایت"برای تراکنش با حجم 500 بایت(نصف 1 کیلوبایت) کارمزد فقط اندازه 50 ساتوشی خواهد بود.</translation>
+ </message>
+ <message>
+ <source>per kilobyte</source>
+ <translation>به ازای هر کیلوبایت</translation>
+ </message>
+ <message>
<source>Hide</source>
<translation>پنهان کردن</translation>
</message>
<message>
+ <source>Recommended:</source>
+ <translation>پیشنهاد شده:</translation>
+ </message>
+ <message>
+ <source>Custom:</source>
+ <translation>سفارشی:</translation>
+ </message>
+ <message>
+ <source>(Smart fee not initialized yet. This usually takes a few blocks...)</source>
+ <translation>(مقداردهی کارمزد هوشمند هنوز مشخص نشده است.این کارمزد معمولا به اندازه چند بلاک طول میکشد...) </translation>
+ </message>
+ <message>
<source>Send to multiple recipients at once</source>
<translation>ارسال همزمان به گیرنده های متعدد</translation>
</message>
<message>
+ <source>Add &amp;Recipient</source>
+ <translation>اضافه کردن &amp;گیرنده</translation>
+ </message>
+ <message>
+ <source>Clear all fields of the form.</source>
+ <translation>پاک کردن تمامی گزینه های این فرم</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation>گرد و غبار یا داست:</translation>
+ </message>
+ <message>
+ <source>Confirmation time target:</source>
+ <translation>هدف زمانی تایید شدن:</translation>
+ </message>
+ <message>
+ <source>Enable Replace-By-Fee</source>
+ <translation>فعال کردن جایگذاری دوباره از کارمزد</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>پاک کردن همه</translation>
</message>
@@ -959,6 +1611,90 @@
<translation>کپی هزینه</translation>
</message>
<message>
+ <source>Copy after fee</source>
+ <translation>کپی کردن بعد از احتساب کارمزد</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>کپی کردن بایت ها</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>کپی کردن داست:</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>کپی کردن تغییر</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to send?</source>
+ <translation>آیا برای ارسال کردن یا فرستادن مطمئن هستید؟</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>یا</translation>
+ </message>
+ <message>
+ <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source>
+ <translation>تو میتوانی بعدا هزینه کارمزد را افزایش بدی(signals Replace-By-Fee, BIP-125)</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction.</source>
+ <translation>لطفا,تراکنش خود را بازبینی کنید.</translation>
+ </message>
+ <message>
+ <source>Transaction fee</source>
+ <translation>کارمزد تراکنش</translation>
+ </message>
+ <message>
+ <source>Total Amount</source>
+ <translation>میزان کل</translation>
+ </message>
+ <message>
+ <source>Confirm send coins</source>
+ <translation>تایید کردن ارسال کوین ها</translation>
+ </message>
+ <message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>آدرس گیرنده نامعتبر است.لطفا دوباره چک یا بررسی کنید.</translation>
+ </message>
+ <message>
+ <source>The amount to pay must be larger than 0.</source>
+ <translation>میزان پولی کخ پرداخت می کنید باید بزرگتر از 0 باشد.</translation>
+ </message>
+ <message>
+ <source>The amount exceeds your balance.</source>
+ <translation>این میزان پول بیشتر از موجودی شما است.</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>آدرس تکراری یافت شد:آدرس ها باید فقط یک بار استفاده شوند.</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <translation>ایجاد تراکنش با خطا مواجه شد!</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>درخواست پرداخت منقضی شد یا تاریخ آن گذشت.</translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>هشدار: آدرس بیت کوین نامعتبر</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation>هشدار:تغییر آدرس نامعلوم</translation>
+ </message>
+ <message>
+ <source>Confirm custom change address</source>
+ <translation>تایید کردن تغییر آدرس سفارشی</translation>
+ </message>
+ <message>
+ <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
+ <translation>این آدرس که شما انتخاب کرده اید بخشی از کیف پول شما نیست.هر یا همه دارایی های شما در این کیف پول به این آدرس ارسال خواهد شد.آیا مطمئن هستید؟</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(برچسب ندارد)</translation>
</message>
@@ -978,10 +1714,38 @@
<translation>برچسب:</translation>
</message>
<message>
+ <source>Choose previously used address</source>
+ <translation>انتخاب آدرس قبلا استفاده شده</translation>
+ </message>
+ <message>
+ <source>This is a normal payment.</source>
+ <translation>این پرداحت,عادی هست.</translation>
+ </message>
+ <message>
+ <source>The Bitcoin address to send the payment to</source>
+ <translation>آدرس بیت کوین برای ارسال پرداحت به آن</translation>
+ </message>
+ <message>
+ <source>Alt+A</source>
+ <translation>Alt+A</translation>
+ </message>
+ <message>
<source>Paste address from clipboard</source>
<translation>استفاده از آدرس کلیپ بورد</translation>
</message>
<message>
+ <source>Alt+P</source>
+ <translation>Alt+P</translation>
+ </message>
+ <message>
+ <source>Remove this entry</source>
+ <translation>پاک کردن این ورودی</translation>
+ </message>
+ <message>
+ <source>Use available balance</source>
+ <translation>استفاده از موجودی حساب</translation>
+ </message>
+ <message>
<source>Message:</source>
<translation>پیام:</translation>
</message>
@@ -996,7 +1760,11 @@
</context>
<context>
<name>SendConfirmationDialog</name>
- </context>
+ <message>
+ <source>Yes</source>
+ <translation>بله</translation>
+ </message>
+</context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -1007,14 +1775,30 @@
<context>
<name>SignVerifyMessageDialog</name>
<message>
+ <source>Signatures - Sign / Verify a Message</source>
+ <translation>امضاها -ثبت/تایید پیام</translation>
+ </message>
+ <message>
<source>&amp;Sign Message</source>
- <translation>امضای پیام </translation>
+ <translation>&amp;ثبت پیام </translation>
+ </message>
+ <message>
+ <source>Choose previously used address</source>
+ <translation>انتخاب آدرس قبلا استفاده شده</translation>
+ </message>
+ <message>
+ <source>Alt+A</source>
+ <translation>Alt+A</translation>
</message>
<message>
<source>Paste address from clipboard</source>
<translation>آدرس را بر کلیپ بورد کپی کنید</translation>
</message>
<message>
+ <source>Alt+P</source>
+ <translation>Alt+P</translation>
+ </message>
+ <message>
<source>Enter the message you want to sign here</source>
<translation>پیامی که می خواهید امضا کنید را اینجا وارد کنید</translation>
</message>
@@ -1024,7 +1808,7 @@
</message>
<message>
<source>Sign &amp;Message</source>
- <translation>امضای پیام </translation>
+ <translation>ثبت &amp;پیام</translation>
</message>
<message>
<source>Clear &amp;All</source>
@@ -1039,10 +1823,30 @@
<translation>تایید پیام</translation>
</message>
<message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation>برای تولید امضا "Sign Message" و یا "ثبت پیام" را کلیک کنید</translation>
+ </message>
+ <message>
<source>The entered address is invalid.</source>
<translation>آدرس وارد شده نامعتبر است.</translation>
</message>
- </context>
+ <message>
+ <source>Message signed.</source>
+ <translation>پیام ثبت شده</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation>این امضا با حرفو پیام همخوانی ندارد</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>پیام شما با خطا مواجه شد</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>پیام شما تایید شد</translation>
+ </message>
+</context>
<context>
<name>SplashScreen</name>
<message>
@@ -1052,7 +1856,11 @@
</context>
<context>
<name>TrafficGraphWidget</name>
- </context>
+ <message>
+ <source>KB/s</source>
+ <translation>کیلو بایت بر ثانیه</translation>
+ </message>
+</context>
<context>
<name>TransactionDesc</name>
<message>
@@ -1060,6 +1868,10 @@
<translation>وضعیت</translation>
</message>
<message>
+ <source>Date</source>
+ <translation>تاریخ</translation>
+ </message>
+ <message>
<source>Source</source>
<translation>منبع</translation>
</message>
@@ -1072,10 +1884,86 @@
<translation>از</translation>
</message>
<message>
+ <source>unknown</source>
+ <translation>ناشناس</translation>
+ </message>
+ <message>
<source>To</source>
<translation>به</translation>
</message>
- </context>
+ <message>
+ <source>own address</source>
+ <translation>آدرس خود</translation>
+ </message>
+ <message>
+ <source>watch-only</source>
+ <translation>فقط-با قابلیت دیدن</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>برچسب</translation>
+ </message>
+ <message>
+ <source>Credit</source>
+ <translation>اعتبار</translation>
+ </message>
+ <message>
+ <source>not accepted</source>
+ <translation>قبول نشده</translation>
+ </message>
+ <message>
+ <source>Total credit</source>
+ <translation>تمامی اعتبار</translation>
+ </message>
+ <message>
+ <source>Transaction fee</source>
+ <translation>کارمزد تراکنش</translation>
+ </message>
+ <message>
+ <source>Net amount</source>
+ <translation>میزان وجه دقیق</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>پیام</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation>کامنت</translation>
+ </message>
+ <message>
+ <source>Transaction ID</source>
+ <translation>شناسه تراکنش</translation>
+ </message>
+ <message>
+ <source>Transaction total size</source>
+ <translation>حجم کل تراکنش</translation>
+ </message>
+ <message>
+ <source>Debug information</source>
+ <translation>اطلاعات دی باگ Debug</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>تراکنش</translation>
+ </message>
+ <message>
+ <source>Inputs</source>
+ <translation>ورودی ها</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>میزان وجه:</translation>
+ </message>
+ <message>
+ <source>true</source>
+ <translation>درست</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation>نادرست</translation>
+ </message>
+</context>
<context>
<name>TransactionDescDialog</name>
<message>
@@ -1086,6 +1974,14 @@
<context>
<name>TransactionTableModel</name>
<message>
+ <source>Date</source>
+ <translation>تاریخ</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>نوع</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>برچسب</translation>
</message>
@@ -1094,6 +1990,14 @@
<translation>تایید نشده</translation>
</message>
<message>
+ <source>Generated but not accepted</source>
+ <translation>تولید شده ولی هنوز قبول نشده است</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>دریافت شده با</translation>
+ </message>
+ <message>
<source>Received from</source>
<translation>دریافت شده از</translation>
</message>
@@ -1102,25 +2006,101 @@
<translation>ارسال شده به</translation>
</message>
<message>
+ <source>Payment to yourself</source>
+ <translation>پرداخت به خود</translation>
+ </message>
+ <message>
<source>Mined</source>
<translation>استخراج شده</translation>
</message>
<message>
+ <source>watch-only</source>
+ <translation>فقط-با قابلیت دیدن</translation>
+ </message>
+ <message>
+ <source>(n/a)</source>
+ <translation>(موجود نیست)</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(برچسب ندارد)</translation>
</message>
- </context>
+ <message>
+ <source>Date and time that the transaction was received.</source>
+ <translation>تاریخ و زمان تراکنش دریافت شده است</translation>
+ </message>
+ <message>
+ <source>Type of transaction.</source>
+ <translation>نوع تراکنش.</translation>
+ </message>
+ <message>
+ <source>Amount removed from or added to balance.</source>
+ <translation> میزان وجه کم شده یا اضافه شده به حساب</translation>
+ </message>
+</context>
<context>
<name>TransactionView</name>
<message>
+ <source>All</source>
+ <translation>همه</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>امروز</translation>
+ </message>
+ <message>
+ <source>This week</source>
+ <translation>این هفته</translation>
+ </message>
+ <message>
+ <source>This month</source>
+ <translation>این ماه</translation>
+ </message>
+ <message>
+ <source>Last month</source>
+ <translation>ماه گذشته</translation>
+ </message>
+ <message>
+ <source>This year</source>
+ <translation>امسال یا این سال</translation>
+ </message>
+ <message>
+ <source>Range...</source>
+ <translation>دامنه...</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>گرفته شده با</translation>
+ </message>
+ <message>
<source>Sent to</source>
<translation>ارسال شده به</translation>
</message>
<message>
+ <source>To yourself</source>
+ <translation>به خودت</translation>
+ </message>
+ <message>
<source>Mined</source>
<translation>استخراج شده</translation>
</message>
<message>
+ <source>Other</source>
+ <translation>بقیه</translation>
+ </message>
+ <message>
+ <source>Enter address, transaction id, or label to search</source>
+ <translation>وارد کردن آدرس,شناسه تراکنش, یا برچسب برای جست و جو</translation>
+ </message>
+ <message>
+ <source>Min amount</source>
+ <translation>حداقل میزان وجه</translation>
+ </message>
+ <message>
+ <source>Increase transaction fee</source>
+ <translation>افزایش کارمزد تراکنش</translation>
+ </message>
+ <message>
<source>Copy address</source>
<translation>کپی آدرس</translation>
</message>
@@ -1137,10 +2117,38 @@
<translation>کپی شناسه تراکنش</translation>
</message>
<message>
+ <source>Copy full transaction details</source>
+ <translation>کپی کردن تمامی اطلاعات تراکنش</translation>
+ </message>
+ <message>
+ <source>Edit label</source>
+ <translation>ویرایش کردن برچسب</translation>
+ </message>
+ <message>
+ <source>Show transaction details</source>
+ <translation>نشان دادن جرییات تراکنش</translation>
+ </message>
+ <message>
+ <source>Export Transaction History</source>
+ <translation>خارج کردن یا بالا بردن سابقه تراکنش ها</translation>
+ </message>
+ <message>
<source>Comma separated file (*.csv)</source>
<translation>فایل سی اس وی (*.csv)</translation>
</message>
<message>
+ <source>Confirmed</source>
+ <translation>تایید شده</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>تاریخ</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>نوع</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>برچسب</translation>
</message>
@@ -1149,10 +2157,26 @@
<translation>آدرس</translation>
</message>
<message>
+ <source>ID</source>
+ <translation>شناسه</translation>
+ </message>
+ <message>
<source>Exporting Failed</source>
<translation>گرفتن خروجی به مشکل خورد</translation>
</message>
- </context>
+ <message>
+ <source>Exporting Successful</source>
+ <translation>خارج کردن موفقیت آمیز بود Exporting</translation>
+ </message>
+ <message>
+ <source>Range:</source>
+ <translation>دامنه:</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>به</translation>
+ </message>
+</context>
<context>
<name>UnitDisplayStatusBarControl</name>
</context>
@@ -1161,29 +2185,209 @@
</context>
<context>
<name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>ارسال کوین ها یا سکه ها</translation>
+ </message>
+ <message>
+ <source>Increasing transaction fee failed</source>
+ <translation>افزایش کارمزد تراکنش با خطا مواجه شد</translation>
+ </message>
+ <message>
+ <source>Do you want to increase the fee?</source>
+ <translation>آیا میخواهید اندازه کارمزد را افزایش دهید؟</translation>
+ </message>
+ <message>
+ <source>Current fee:</source>
+ <translation>کارمزد الان:</translation>
+ </message>
+ <message>
+ <source>Increase:</source>
+ <translation>افزایش دادن:</translation>
+ </message>
+ <message>
+ <source>New fee:</source>
+ <translation>کارمزد جدید:</translation>
+ </message>
+ <message>
+ <source>Can't sign transaction.</source>
+ <translation>نمیتوان تراکنش را ثبت کرد</translation>
+ </message>
</context>
<context>
<name>WalletView</name>
- </context>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;صدور</translation>
+ </message>
+ <message>
+ <source>Backup Wallet</source>
+ <translation>بازیابی یا پشتیبان گیری کیف پول</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation>بازیابی یا پشتیبان گیری با خطا مواجه شد</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation>بازیابی یا پشتیبان گیری موفقیت آمیز بود.</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>لغو</translation>
+ </message>
+</context>
<context>
<name>bitcoin-core</name>
<message>
+ <source>Bitcoin Core</source>
+ <translation>هسته بیت کوین</translation>
+ </message>
+ <message>
+ <source>Change index out of range</source>
+ <translation>تغییر دادن اندیس خارج از دامنه</translation>
+ </message>
+ <message>
+ <source>Copyright (C) %i-%i</source>
+ <translation>کپی رایت (C) %i-%i</translation>
+ </message>
+ <message>
+ <source>Do you want to rebuild the block database now?</source>
+ <translation>آیا میخواهید الان پایگاه داده بلاک را بازسازی کنید؟</translation>
+ </message>
+ <message>
+ <source>Error loading block database</source>
+ <translation>خطا در بارگذاری پایگاه داده بلاک block</translation>
+ </message>
+ <message>
+ <source>Error opening block database</source>
+ <translation>خطا در بازکردن پایگاه داده بلاک block</translation>
+ </message>
+ <message>
+ <source>Error: Disk space is low!</source>
+ <translation>حطا:فضای دیسک کم است!</translation>
+ </message>
+ <message>
+ <source>Importing...</source>
+ <translation>در حال وارد کردن...</translation>
+ </message>
+ <message>
+ <source>Invalid amount for -%s=&lt;amount&gt;: '%s'</source>
+ <translation>میزان نامعتبر برای -%s=&lt;amount&gt;: '%s'</translation>
+ </message>
+ <message>
+ <source>Upgrading txindex database</source>
+ <translation>ارتقا دادن پایگاه داده اندیس تراکنش ها یا txindex</translation>
+ </message>
+ <message>
+ <source>Loading P2P addresses...</source>
+ <translation>در حال بارگذاری آدرس های همتا-به-همتا یا P2P</translation>
+ </message>
+ <message>
+ <source>Loading banlist...</source>
+ <translation>در حال بارگذاری لیست بن...</translation>
+ </message>
+ <message>
+ <source>Unable to generate keys</source>
+ <translation>نمیتوان کلید ها را تولید کرد</translation>
+ </message>
+ <message>
+ <source>Upgrading UTXO database</source>
+ <translation>ارتقا دادن پایگاه داده UTXO</translation>
+ </message>
+ <message>
+ <source>Verifying blocks...</source>
+ <translation>در حال تایید کردن بلاک ها...</translation>
+ </message>
+ <message>
<source>The transaction amount is too small to send after the fee has been deducted</source>
<translation>مبلغ تراکنش کمتر از آن است که پس از کسر هزینه تراکنش قابل ارسال باشد</translation>
</message>
<message>
+ <source>Error reading from database, shutting down.</source>
+ <translation>خواندن از پایگاه داده با خطا مواجه شد,در حال خاموش شدن.</translation>
+ </message>
+ <message>
<source>Information</source>
<translation>اطلاعات</translation>
</message>
<message>
+ <source>Signing transaction failed</source>
+ <translation>ثبت تراکنش با خطا مواجه شد</translation>
+ </message>
+ <message>
+ <source>The transaction amount is too small to pay the fee</source>
+ <translation>حجم تراکنش بسیار کم است برای پرداخت کارمزد</translation>
+ </message>
+ <message>
+ <source>This is experimental software.</source>
+ <translation>این یک نرم افزار تجربی است.</translation>
+ </message>
+ <message>
+ <source>Transaction amount too small</source>
+ <translation>حجم تراکنش خیلی کم است</translation>
+ </message>
+ <message>
+ <source>Transaction too large for fee policy</source>
+ <translation>حجم تراکنش خیلی زیاد است به خاطر سیاست های کارمزدی بیت کوین</translation>
+ </message>
+ <message>
+ <source>Transaction too large</source>
+ <translation>حجم تراکنش خیلی زیاد است</translation>
+ </message>
+ <message>
+ <source>Unable to generate initial keys</source>
+ <translation>نمیتوان کلید های اولیه را تولید کرد.</translation>
+ </message>
+ <message>
+ <source>Verifying wallet(s)...</source>
+ <translation>در حال تایید شدن کیف پول(ها)...</translation>
+ </message>
+ <message>
<source>Warning</source>
<translation>هشدار</translation>
</message>
<message>
+ <source>This is the transaction fee you may pay when fee estimates are not available.</source>
+ <translation>این هزینه تراکنشی است که در صورت عدم وجود هزینه تخمینی، پرداخت می کنید.</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source>
+ <translation>هشدار:یک بلاک از یک نسخه ناشناس در حال ماین شدن است.در این اتفاق ممکن است قوانین ناشناسی اثرات نامعلوم بگذارند.</translation>
+ </message>
+ <message>
+ <source>%s is set very high!</source>
+ <translation>%s بسیار بزرگ انتخاب شده است.</translation>
+ </message>
+ <message>
+ <source>Keypool ran out, please call keypoolrefill first</source>
+ <translation>کلید استخر تمام شده است، لطفاً درخواست کلید استخر را پرنمایید.</translation>
+ </message>
+ <message>
+ <source>Starting network threads...</source>
+ <translation>ایجاد نخ‌های شبکه ...</translation>
+ </message>
+ <message>
+ <source>This is the minimum transaction fee you pay on every transaction.</source>
+ <translation>این کمترین فی تراکنش است که در هر تراکنش پرداخت می‌نمایید.</translation>
+ </message>
+ <message>
+ <source>Transaction amounts must not be negative</source>
+ <translation>مقدار تراکنش نمی‌تواند منفی باشد.</translation>
+ </message>
+ <message>
+ <source>Transaction must have at least one recipient</source>
+ <translation>تراکنش باید حداقل یک دریافت کننده داشته باشد</translation>
+ </message>
+ <message>
<source>Insufficient funds</source>
<translation>وجوه ناکافی</translation>
</message>
<message>
+ <source>Can't generate a change-address key. Private keys are disabled for this wallet.</source>
+ <translation>نمیتوان تغییر-آدرس کلید را تولید کرد.کلید های خصوصی در این کیف پول غیر فعال شده اند.</translation>
+ </message>
+ <message>
<source>Loading block index...</source>
<translation>لود شدن نمایه بلاکها..</translation>
</message>
diff --git a/src/qt/locale/bitcoin_fi.ts b/src/qt/locale/bitcoin_fi.ts
index ea97d48b10..71832200df 100644
--- a/src/qt/locale/bitcoin_fi.ts
+++ b/src/qt/locale/bitcoin_fi.ts
@@ -326,6 +326,14 @@
<translation>Avaa &amp;URI...</translation>
</message>
<message>
+ <source>Wallet:</source>
+ <translation>Lompakko:</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation>oletuslompakko</translation>
+ </message>
+ <message>
<source>Click to disable network activity.</source>
<translation>Paina poistaaksesi verkkoyhteysilmaisin käytöstä.</translation>
</message>
@@ -346,6 +354,10 @@
<translation>Ladataan lohkoindeksiä...</translation>
</message>
<message>
+ <source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
+ <translation>Välipalvelin on &lt;b&gt;käytössä&lt;/b&gt;: %1</translation>
+ </message>
+ <message>
<source>Send coins to a Bitcoin address</source>
<translation>Lähetä kolikoita Bitcoin-osoitteeseen</translation>
</message>
@@ -441,6 +453,10 @@
<source>&amp;Command-line options</source>
<translation>&amp;Komentorivin valinnat</translation>
</message>
+ <message numerus="yes">
+ <source>%n active connection(s) to Bitcoin network</source>
+ <translation><numerusform>%n aktiivinen yhteys Bitcoin-verkkoon</numerusform><numerusform>%n aktiivista yhteyttä Bitcoin-verkkoon</numerusform></translation>
+ </message>
<message>
<source>Indexing blocks on disk...</source>
<translation>Ladataan lohkoindeksiä...</translation>
@@ -449,6 +465,10 @@
<source>Processing blocks on disk...</source>
<translation>Käsitellään lohkoja levyllä...</translation>
</message>
+ <message numerus="yes">
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation><numerusform>Käsitelty %n lohko rahansiirtohistoriasta.</numerusform><numerusform>Käsitelty %n lohkoa rahansiirtohistoriasta.</numerusform></translation>
+ </message>
<message>
<source>%1 behind</source>
<translation>%1 jäljessä</translation>
@@ -742,6 +762,14 @@
<translation>Antamasi osoite "%1" ei ole kelvollinen Bitcoin-osoite.</translation>
</message>
<message>
+ <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source>
+ <translation>Osoite "%1" on jo vastaanotto-osoitteena nimellä "%2", joten sitä ei voi lisätä lähetysosoitteeksi.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book with label "%2".</source>
+ <translation>Syötetty osoite "%1" on jo osoitekirjassa nimellä "%2".</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation>Lompakkoa ei voitu avata.</translation>
</message>
@@ -854,7 +882,15 @@
<source>Error</source>
<translation>Virhe</translation>
</message>
- </context>
+ <message numerus="yes">
+ <source>%n GB of free space available</source>
+ <translation><numerusform>%n GB tilaa vapaana</numerusform><numerusform>%n GB tilaa vapaana</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation><numerusform>(tarvitaan %n GB)</numerusform><numerusform>(tarvitaan %n GB)</numerusform></translation>
+ </message>
+</context>
<context>
<name>ModalOverlay</name>
<message>
@@ -957,7 +993,7 @@
</message>
<message>
<source>Number of script &amp;verification threads</source>
- <translation>Script &amp;varmistuksen threadien määrä</translation>
+ <translation>Säikeiden määrä skriptien &amp;varmistuksessa</translation>
</message>
<message>
<source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
@@ -968,6 +1004,10 @@
<translation>Ilmoittaa, mikäli oletetettua SOCKS5-välityspalvelinta käytetään vertaisten tavoittamiseen tämän verkkotyypin kautta.</translation>
</message>
<message>
+ <source>Use separate SOCKS&amp;5 proxy to reach peers via Tor hidden services:</source>
+ <translation>Käytä SOCKS&amp;5-välityspalvelinta tavoittamaan Tor-verkon piilotetut palvelut:</translation>
+ </message>
+ <message>
<source>Hide the icon from the system tray.</source>
<translation>Piilota kuvake järjestelmäpalkista.</translation>
</message>
@@ -1008,6 +1048,18 @@
<translation>&amp;Verkko</translation>
</message>
<message>
+ <source>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</source>
+ <translation>Jättää pois joitain edistyneitä ominaisuuksia, mutta silti varmistaa kaikki lohkot kokonaan. Tämän asetuksen muutto vaatii koko lohkoketjun uudelleen lataamisen. Levyn käyttöaste saattaa olla hiukan suurempaa.</translation>
+ </message>
+ <message>
+ <source>Prune &amp;block storage to</source>
+ <translation>Karsi lohkovaraston kooksi</translation>
+ </message>
+ <message>
+ <source>Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation>Tämän asetuksen muuttaminen vaatii koko lohkoketjun uudelleenlataamista.</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation>(0 = auto, &lt;0 = jätä näin monta ydintä vapaaksi)</translation>
</message>
@@ -1274,6 +1326,10 @@
<translation>URI käsittely</translation>
</message>
<message>
+ <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source>
+ <translation>'bitcoin://' ei ole kelvollinen URI. Käytä 'bitcoin:' sen sijaan.</translation>
+ </message>
+ <message>
<source>Payment request fetch URL is invalid: %1</source>
<translation>Maksupyynnön haku URL on virheellinen: %1</translation>
</message>
@@ -1447,10 +1503,18 @@
<context>
<name>QObject::QObject</name>
<message>
+ <source>Error parsing command line arguments: %1.</source>
+ <translation>Virhe käsitellessä komentorivin valintaa: %1.</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
<translation>Virhe: Annettua data-hakemistoa "%1" ei ole olemassa.</translation>
</message>
<message>
+ <source>Error: Cannot parse configuration file: %1.</source>
+ <translation>Virhe: Asetustiedostoa ei voida käsitellä: %1.</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation>Virhe: %1</translation>
</message>
@@ -1709,6 +1773,10 @@
<translation>&amp;Poista esto</translation>
</message>
<message>
+ <source>default wallet</source>
+ <translation>oletuslompakko</translation>
+ </message>
+ <message>
<source>Welcome to the %1 RPC console.</source>
<translation>Tervetuloa %1 RPC-konsoliin.</translation>
</message>
@@ -1800,6 +1868,10 @@
<translation>Tyhjennä</translation>
</message>
<message>
+ <source>Generate native segwit (Bech32) address</source>
+ <translation>Luo natiivi segwit (Bech32) -osoite</translation>
+ </message>
+ <message>
<source>Requested payments history</source>
<translation>Pyydettyjen maksujen historia</translation>
</message>
@@ -2013,6 +2085,10 @@
<translation>Piilota</translation>
</message>
<message>
+ <source>Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks. But be aware that this can end up in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source>
+ <translation>Vähimmäispalkkion maksaminen käy hyvin, kunhan verkossa on vähemmän siirtotapahtumia kuin lohkoissa on tilaa. Huomaa, että tämä saattaa johtaa ei-koskaan-vahvistuvaan siirtoon, jos verkon käsittelykyky ylittyy.</translation>
+ </message>
+ <message>
<source>(read the tooltip)</source>
<translation>(lue työkaluvinkki)</translation>
</message>
@@ -2053,6 +2129,10 @@
<translation>Käytä Replace-By-Fee:tä</translation>
</message>
<message>
+ <source>With Replace-By-Fee (BIP-125) you can increase a transaction's fee after it is sent. Without this, a higher fee may be recommended to compensate for increased transaction delay risk.</source>
+ <translation>Replace-By-Fee:tä (BIP-125) käyttämällä voit korottaa siirtotapahtuman palkkiota sen lähettämisen jälkeen. Ilman tätä saatetaan suositella käyttämään suurempaa palkkiota kompensoimaan viiveen kasvamisen riskiä.</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>&amp;Tyhjennnä Kaikki</translation>
</message>
@@ -2113,6 +2193,14 @@
<translation>tai</translation>
</message>
<message>
+ <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source>
+ <translation>Voit korottaa palkkiota myöhemmin (osoittaa Replace-By-Fee:tä, BIP-125).</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction.</source>
+ <translation>Tarkistathan siirtosi.</translation>
+ </message>
+ <message>
<source>Transaction fee</source>
<translation>Siirtokulu</translation>
</message>
@@ -2160,6 +2248,10 @@
<source>Pay only the required fee of %1</source>
<translation>Maksa vain vaadittu kulu %1 </translation>
</message>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation><numerusform>Vahvistuminen alkaa arviolta %n lohkon sisällä.</numerusform><numerusform>Vahvistuminen alkaa arviolta %n lohkon sisällä.</numerusform></translation>
+ </message>
<message>
<source>Warning: Invalid Bitcoin address</source>
<translation>Varoitus: Virheellinen Bitcoin-osoite </translation>
@@ -2441,6 +2533,10 @@
</context>
<context>
<name>TransactionDesc</name>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>Avoinna vielä %n lohkon ajan</numerusform><numerusform>Avoinna vielä %n lohkon ajan</numerusform></translation>
+ </message>
<message>
<source>Open until %1</source>
<translation>Avoinna %1 asti</translation>
@@ -2615,6 +2711,10 @@
<source>Label</source>
<translation>Nimike</translation>
</message>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>Avoinna vielä %n lohkon ajan</numerusform><numerusform>Avoinna vielä %n lohkon ajan</numerusform></translation>
+ </message>
<message>
<source>Open until %1</source>
<translation>Avoinna %1 asti</translation>
@@ -2884,6 +2984,10 @@
<translation>Lähetä kolikoita</translation>
</message>
<message>
+ <source>Fee bump error</source>
+ <translation>Virhe nostaessa palkkiota.</translation>
+ </message>
+ <message>
<source>Increasing transaction fee failed</source>
<translation>Siirtokulun nosto epäonnistui</translation>
</message>
@@ -2950,7 +3054,11 @@
<source>The wallet data was successfully saved to %1.</source>
<translation>Lompakko tallennettiin onnistuneesti tiedostoon %1.</translation>
</message>
- </context>
+ <message>
+ <source>Cancel</source>
+ <translation>Peruuta</translation>
+ </message>
+</context>
<context>
<name>bitcoin-core</name>
<message>
@@ -3122,6 +3230,14 @@
<translation>Virheellinen määrä -fallbackfee=&lt;amount&gt;: '%s'</translation>
</message>
<message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation>Määrättyä lohkohakemistoa "%s" ei ole olemassa.</translation>
+ </message>
+ <message>
+ <source>Upgrading txindex database</source>
+ <translation>Päivitetään txindex -tietokantaa</translation>
+ </message>
+ <message>
<source>Loading P2P addresses...</source>
<translation>Ladataan P2P-vertaisten osoitteita...</translation>
</message>
@@ -3142,6 +3258,10 @@
<translation>Karsittu tila ei ole yhteensopiva -txindex:n kanssa.</translation>
</message>
<message>
+ <source>Replaying blocks...</source>
+ <translation>Tarkastetaan lohkoja..</translation>
+ </message>
+ <message>
<source>Rewinding blocks...</source>
<translation>Varmistetaan lohkoja...</translation>
</message>
@@ -3158,6 +3278,10 @@
<translation>Kytkeytyminen kohteeseen %s ei onnistu tällä tietokoneella. %s on luultavasti jo käynnissä.</translation>
</message>
<message>
+ <source>Unable to generate keys</source>
+ <translation>Avaimia ei voitu luoda</translation>
+ </message>
+ <message>
<source>Unsupported argument -benchmark ignored, use -debug=bench.</source>
<translation>Argumenttia -benchmark ei tueta, käytä -debug=bench.</translation>
</message>
@@ -3206,6 +3330,10 @@
<translation>Virheitä tietokantaa luettaessa, ohjelma pysäytetään.</translation>
</message>
<message>
+ <source>Error upgrading chainstate database</source>
+ <translation>Virhe päivittäessä chainstate-tietokantaa</translation>
+ </message>
+ <message>
<source>Information</source>
<translation>Tietoa</translation>
</message>
@@ -3238,6 +3366,14 @@
<translation>Siirron vahvistus epäonnistui</translation>
</message>
<message>
+ <source>Specified -walletdir "%s" does not exist</source>
+ <translation>Määriteltyä lompakon hakemistoa "%s" ei ole olemassa.</translation>
+ </message>
+ <message>
+ <source>Specified -walletdir "%s" is a relative path</source>
+ <translation>Määritelty lompakkohakemisto "%s" sijaitsee suhteellisessa polussa</translation>
+ </message>
+ <message>
<source>The transaction amount is too small to pay the fee</source>
<translation>Rahansiirron määrä on liian pieni kattaakseen maksukulun</translation>
</message>
@@ -3266,6 +3402,10 @@
<translation>Varmistetaan lompakko(ja)...</translation>
</message>
<message>
+ <source>Wallet %s resides outside wallet directory %s</source>
+ <translation>Lompakko %s sijaitsee lompakkohakemiston %s ulkopuolella.</translation>
+ </message>
+ <message>
<source>Warning</source>
<translation>Varoitus</translation>
</message>
@@ -3286,6 +3426,10 @@
<translation>Virhe ladattaessa %s: Et voi ottaa HD:ta käyttöön jo olemassa olevalle ei-HD -lompakolle.</translation>
</message>
<message>
+ <source>This is the transaction fee you may pay when fee estimates are not available.</source>
+ <translation>Tämän siirtomaksun maksat, kun siirtomaksun arviointi ei ole käytettävissä.</translation>
+ </message>
+ <message>
<source>Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.</source>
<translation>Ei tuettu argumentti -socks löytynyt. SOCKS -version asetusta ei enää tueta, ainoastaan SOCKS5 -välityspalvelimet on tuettu.</translation>
</message>
@@ -3314,6 +3458,10 @@
<translation>Käynnistetään verkkoa...</translation>
</message>
<message>
+ <source>The wallet will avoid paying less than the minimum relay fee.</source>
+ <translation>Lompakko välttää maksamasta alle vähimmäisen välityskulun.</translation>
+ </message>
+ <message>
<source>This is the minimum transaction fee you pay on every transaction.</source>
<translation>Tämä on jokaisesta siirrosta maksettava vähimmäismaksu.</translation>
</message>
@@ -3342,6 +3490,14 @@
<translation>Lompakon saldo ei riitä</translation>
</message>
<message>
+ <source>Can't generate a change-address key. Private keys are disabled for this wallet.</source>
+ <translation>Vaihtorahaosoitetteen avainta ei voitu luoda. Yksityisavaimet on poistettu käytöstä tässä lompakossa.</translation>
+ </message>
+ <message>
+ <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
+ <translation>Siirtomaksun arviointi epäonnistui. Odota muutama lohko tai käytä -fallbackfee -valintaa..</translation>
+ </message>
+ <message>
<source>Loading block index...</source>
<translation>Ladataan lohkoindeksiä...</translation>
</message>
diff --git a/src/qt/locale/bitcoin_fr.ts b/src/qt/locale/bitcoin_fr.ts
index 52e7bda368..046972360e 100644
--- a/src/qt/locale/bitcoin_fr.ts
+++ b/src/qt/locale/bitcoin_fr.ts
@@ -842,7 +842,7 @@
</message>
<message>
<source>When you click OK, %1 will begin to download and process the full %4 block chain (%2GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
- <translation>Lorsque vous cliquez sur OK, %1 commence à télécharger et à traiter l’intégralité de la chaîne de blocs %4 (%2 Go) en débutant avec les transactions les plus anciennes de %3, quand %4 a été lancé initialement.</translation>
+ <translation>Quand vous cliquerez sur Valider, %1 commencera à télécharger et à traiter l’intégralité de la chaîne de blocs %4 (%2 Go) en débutant avec les transactions les plus anciennes de %3, quand %4 a été lancé initialement.</translation>
</message>
<message>
<source>This initial synchronisation is very demanding, and may expose hardware problems with your computer that had previously gone unnoticed. Each time you run %1, it will continue downloading where it left off.</source>
@@ -1195,7 +1195,7 @@
</message>
<message>
<source>&amp;OK</source>
- <translation>&amp;OK</translation>
+ <translation>&amp;Valider</translation>
</message>
<message>
<source>&amp;Cancel</source>
@@ -1254,7 +1254,7 @@
</message>
<message>
<source>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</source>
- <translation>Les informations affichées peuvent être obsolètes. Votre porte-monnaie est automatiquement synchronisé avec le réseau Bitcoin lorsque la connexion s’établit, or ce processus n’est pas encore terminé.</translation>
+ <translation>Les informations affichées peuvent être obsolètes. Votre porte-monnaie se synchronise automatiquement avec le réseau Bitcoin dès qu’une connexion est établie, mais ce processus n’est pas encore achevé.</translation>
</message>
<message>
<source>Watch-only:</source>
@@ -2300,7 +2300,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par
</message>
<message>
<source>The total exceeds your balance when the %1 transaction fee is included.</source>
- <translation>Le montant dépasse votre solde lorsque les frais de transaction de %1 sont inclus.</translation>
+ <translation>Le montant dépasse votre solde quand les frais de transaction de %1 sont inclus.</translation>
</message>
<message>
<source>Duplicate address found: addresses should only be used once each.</source>
@@ -2741,7 +2741,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par
</message>
<message>
<source>Output index</source>
- <translation>Index de sorties</translation>
+ <translation>Index des sorties</translation>
</message>
<message>
<source>Merchant</source>
@@ -2749,7 +2749,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par
</message>
<message>
<source>Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source>
- <translation>Les pièces générées doivent mûrir pendant %1 blocs avant de pouvoir être dépensées. Lorsque ce bloc a été généré, il a été diffusé sur le réseau pour être ajouté à la chaîne de blocs. Si son intégration à la chaîne échoue, son état sera modifié en « refusée » et il ne sera pas possible de le dépenser. Cela peut arriver occasionnellement si un autre nœud génère un bloc à quelques secondes du vôtre.</translation>
+ <translation>Les pièces générées doivent mûrir pendant %1 blocs avant de pouvoir être dépensées. Quand vous avez généré ce bloc, il a été diffusé sur le réseau pour être ajouté à la chaîne de blocs. Si son intégration à la chaîne échoue, son état sera modifié en « refusée » et il ne sera pas possible de le dépenser. Cela peut arriver occasionnellement si un autre nœud génère un bloc à quelques secondes du vôtre.</translation>
</message>
<message>
<source>Debug information</source>
@@ -3200,6 +3200,10 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par
<translation>Erreur de lecture de %s ! Toutes les clés ont été lues correctement, mais les données transactionnelles ou les entrées du carnet d’adresses sont peut-être manquantes ou incorrectes.</translation>
</message>
<message>
+ <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source>
+ <translation>Grouper les sorties par adresse, les sélectionnant toutes ou n’en sélectionnant aucune, au lieu d’une sélection par sortie. La confidentialité est améliorée dans la mesure où une adresse n’est utilisée qu’une fois (à moins que quelqu’un envoie à adresse après l’avoir utilisée pour une dépense). Cela pourrait entraîner des frais légèrement plus élevés, car une sélection sous-optimale des pièces pourrait en résulter en raison de la restriction supplémentaire (par défaut : %u)</translation>
+ </message>
+ <message>
<source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source>
<translation>Veuillez vérifier que l’heure et la date de votre ordinateur sont justes ! Si votre horloge n’est pas à l’heure, %s ne fonctionnera pas correctement.</translation>
</message>
@@ -3340,6 +3344,10 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par
<translation>Montant invalide pour -fallbackfee=&lt;amount&gt; : « %s »</translation>
</message>
<message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation>Le répertoire des blocs indiqué « %s » n’existe pas.</translation>
+ </message>
+ <message>
<source>Upgrading txindex database</source>
<translation>Mise à niveau de la base de données txindex</translation>
</message>
@@ -3480,12 +3488,6 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par
<translation>Échec de signature de la transaction</translation>
</message>
<message>
- <source>Specified blocks directory "%s" does not exist.
-</source>
- <translation>Le répertoire de blocs indiqué « %s » n’existe pas.
-</translation>
- </message>
- <message>
<source>The transaction amount is too small to pay the fee</source>
<translation>Le montant de la transaction est trop bas pour que les frais soient payés</translation>
</message>
diff --git a/src/qt/locale/bitcoin_he.ts b/src/qt/locale/bitcoin_he.ts
index cf884f0fc7..c8088da4e2 100644
--- a/src/qt/locale/bitcoin_he.ts
+++ b/src/qt/locale/bitcoin_he.ts
@@ -3,7 +3,7 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation>יש ללחוץ על הכפתור הימני כדי לערוך כתובת או תווית</translation>
+ <translation>לחץ על הכפתור הימני בעכבר כדי לערוך את הכתובת או התווית</translation>
</message>
<message>
<source>Create a new address</source>
@@ -279,19 +279,19 @@
</message>
<message>
<source>&amp;About %1</source>
- <translation>על &amp;אודות %1</translation>
+ <translation>&amp;אודות %1</translation>
</message>
<message>
<source>Show information about %1</source>
- <translation>הצגת מידע על %1</translation>
+ <translation>הצג מידע על %1</translation>
</message>
<message>
<source>About &amp;Qt</source>
- <translation>על אודות Qt</translation>
+ <translation>אודות &amp;Qt</translation>
</message>
<message>
<source>Show information about Qt</source>
- <translation>הצגת מידע על Qt</translation>
+ <translation>הצג מידע על Qt</translation>
</message>
<message>
<source>&amp;Options...</source>
@@ -815,7 +815,7 @@
</message>
<message>
<source>About %1</source>
- <translation>על אודות %1</translation>
+ <translation>אודות %1</translation>
</message>
<message>
<source>Command-line options</source>
@@ -1002,6 +1002,14 @@
<translation>כתובת ה־IP של המתווך (לדוגמה IPv4: 127.0.0.1‏ / IPv6: ::1)</translation>
</message>
<message>
+ <source>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source>
+ <translation>מראה אם פרוקסי SOCKS5 המסופק כבררת מחדל משמש להתקשרות עם עמיתים באמצעות סוג רשת זה.</translation>
+ </message>
+ <message>
+ <source>Use separate SOCKS&amp;5 proxy to reach peers via Tor hidden services:</source>
+ <translation>השתמשו בפרוקסי SOCKS&amp;5 נפרד כדי להתקשר עם עמיתים באמצעות שירותים חבויים ברשת Tor:</translation>
+ </message>
+ <message>
<source>Hide the icon from the system tray.</source>
<translation>הסתר את סמל מגש המערכת</translation>
</message>
@@ -1556,7 +1564,7 @@
</message>
<message>
<source>Client version</source>
- <translation>גרסת מנשק</translation>
+ <translation>גרסה</translation>
</message>
<message>
<source>&amp;Information</source>
@@ -1572,7 +1580,7 @@
</message>
<message>
<source>Using BerkeleyDB version</source>
- <translation>שימוש ב־BerkeleyDB גרסה</translation>
+ <translation>גרסת BerkeleyDB</translation>
</message>
<message>
<source>Datadir</source>
@@ -1675,6 +1683,10 @@
<translation>סוכן משתמש</translation>
</message>
<message>
+ <source>Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</source>
+ <translation>פתחו את לוג ניפוי השגיאות ה%1 מתיקיית הנתונים הנוכחית. עבור קבצי לוג גדולים ייתכן זמן המתנה של מספר שניות.</translation>
+ </message>
+ <message>
<source>Decrease font size</source>
<translation>הקטן גודל גופן</translation>
</message>
@@ -2203,6 +2215,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p
<translation>העתקת השינוי</translation>
</message>
<message>
+ <source>%1 (%2 blocks)</source>
+ <translation>%1 (%2 בלוקים)</translation>
+ </message>
+ <message>
<source>Are you sure you want to send?</source>
<translation>לשלוח?</translation>
</message>
diff --git a/src/qt/locale/bitcoin_hi_IN.ts b/src/qt/locale/bitcoin_hi_IN.ts
index 51d6770b1a..cf969b67db 100644
--- a/src/qt/locale/bitcoin_hi_IN.ts
+++ b/src/qt/locale/bitcoin_hi_IN.ts
@@ -18,6 +18,14 @@
<translation>चुनिन्दा पते को सिस्टम क्लिपबोर्ड पर कापी करे !</translation>
</message>
<message>
+ <source>&amp;Copy</source>
+ <translation>&amp;कॉपी </translation>
+ </message>
+ <message>
+ <source>C&amp;lose</source>
+ <translation>सी&amp;लूज़ </translation>
+ </message>
+ <message>
<source>Delete the currently selected address from the list</source>
<translation>सूची से वर्तमान में चयनित पता हटाएं</translation>
</message>
@@ -61,13 +69,49 @@
<source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source>
<translation>भुगतान प्राप्त करने के लिए ये आपके बीटकोइन पते हैं प्रत्येक लेनदेन के लिए एक नया प्राप्त पता उपयोग करने की सिफारिश की जाती है।</translation>
</message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;पता कॉपी करें </translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;संशोधित करें </translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>निर्यात पता सूची</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>कोमा द्वारा अलग की गई फ़ाइल (* .csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>निर्यात विफल रहा</translation>
+ </message>
</context>
<context>
<name>AddressTableModel</name>
- </context>
+ <message>
+ <source>Label</source>
+ <translation>परचा</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>पता </translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(कोई परचा नहीं )</translation>
+ </message>
+</context>
<context>
<name>AskPassphraseDialog</name>
<message>
+ <source>Passphrase Dialog</source>
+ <translation>पासफ़्रेज़ डायलॉग</translation>
+ </message>
+ <message>
<source>Enter passphrase</source>
<translation>पहचान शब्द/अक्षर डालिए !</translation>
</message>
@@ -79,6 +123,18 @@
<source>Repeat new passphrase</source>
<translation>दोबारा नया पहचान शब्द/अक्षर डालिए !</translation>
</message>
+ <message>
+ <source>Show password</source>
+ <translation>पासवर्ड दिखाए</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>वॉलेट एन्क्रिप्ट करें</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>पासफ़्रेज़ बदलें</translation>
+ </message>
</context>
<context>
<name>BanTableModel</name>
@@ -205,6 +261,10 @@
<source>Confirmed</source>
<translation>पक्का</translation>
</message>
+ <message>
+ <source>(no label)</source>
+ <translation>(कोई परचा नहीं )</translation>
+ </message>
</context>
<context>
<name>EditAddressDialog</name>
@@ -340,12 +400,28 @@
<translation>&amp;पता कॉपी करे</translation>
</message>
<message>
+ <source>Address</source>
+ <translation>पता </translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>परचा</translation>
+ </message>
+ <message>
<source>Wallet</source>
<translation>वॉलेट</translation>
</message>
</context>
<context>
<name>RecentRequestsTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>परचा</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(कोई परचा नहीं )</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -369,7 +445,11 @@
<source>Confirm the send action</source>
<translation>भेजने की पुष्टि करें</translation>
</message>
- </context>
+ <message>
+ <source>(no label)</source>
+ <translation>(कोई परचा नहीं )</translation>
+ </message>
+</context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -448,9 +528,33 @@
</context>
<context>
<name>TransactionTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>परचा</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(कोई परचा नहीं )</translation>
+ </message>
</context>
<context>
<name>TransactionView</name>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>कोमा द्वारा अलग की गई फ़ाइल (* .csv)</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>परचा</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>पता </translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>निर्यात विफल रहा</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
diff --git a/src/qt/locale/bitcoin_hr.ts b/src/qt/locale/bitcoin_hr.ts
index 2bd6c7df03..381c99946b 100644
--- a/src/qt/locale/bitcoin_hr.ts
+++ b/src/qt/locale/bitcoin_hr.ts
@@ -3,7 +3,7 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation>Desni klik za uređivanje adresa i oznaka</translation>
+ <translation>Desni klik za uređivanje adrese ili oznake</translation>
</message>
<message>
<source>Create a new address</source>
@@ -15,19 +15,19 @@
</message>
<message>
<source>Copy the currently selected address to the system clipboard</source>
- <translation>Kopiraj trenutno odabranu adresu u međuspremnik</translation>
+ <translation>Kopirajte trenutno odabranu adresu u međuspremnik</translation>
</message>
<message>
<source>&amp;Copy</source>
- <translation>&amp;Kopiraj</translation>
+ <translation>&amp;Kopirajte</translation>
</message>
<message>
<source>C&amp;lose</source>
- <translation>&amp;Zatvori</translation>
+ <translation>&amp;Zatvorite</translation>
</message>
<message>
<source>Delete the currently selected address from the list</source>
- <translation>Brisanje trenutno odabrane adrese s popisa.</translation>
+ <translation>Obrišite trenutno odabranu adresu s popisa.</translation>
</message>
<message>
<source>Enter address or label to search</source>
@@ -35,35 +35,35 @@
</message>
<message>
<source>Export the data in the current tab to a file</source>
- <translation>Izvoz podataka iz trenutnog lista u datoteku</translation>
+ <translation>Izvezite podatke iz trenutne kartice u datoteku</translation>
</message>
<message>
<source>&amp;Export</source>
- <translation>&amp;Izvozi</translation>
+ <translation>&amp;Izvezite</translation>
</message>
<message>
<source>&amp;Delete</source>
- <translation>Iz&amp;briši</translation>
+ <translation>Iz&amp;brišite</translation>
</message>
<message>
<source>Choose the address to send coins to</source>
- <translation>Odaberi adresu na koju šalješ novac</translation>
+ <translation>Odaberite adresu na koju ćete poslati novac</translation>
</message>
<message>
<source>Choose the address to receive coins with</source>
- <translation>Odaberi adresu na koju primaš novac</translation>
+ <translation>Odaberite adresu na koju ćete primiti novac</translation>
</message>
<message>
<source>C&amp;hoose</source>
- <translation>&amp;Odaberi</translation>
+ <translation>&amp;Odaberite</translation>
</message>
<message>
<source>Sending addresses</source>
- <translation>Adresa pošiljatelja</translation>
+ <translation>Adrese pošiljatelja</translation>
</message>
<message>
<source>Receiving addresses</source>
- <translation>Adresa primatelja</translation>
+ <translation>Adrese primatelja</translation>
</message>
<message>
<source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
@@ -71,23 +71,23 @@
</message>
<message>
<source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source>
- <translation>Ovo su vaše Bitcoin adrese za primanje novca. Preporučamo da koristite novu adresu za primanje za svaku transakciju.</translation>
+ <translation>Ovo su vaše Bitcoin adrese za primanje novca. Preporučeno je da koristite novu primateljsku adresu za svaku transakciju.</translation>
</message>
<message>
<source>&amp;Copy Address</source>
- <translation>&amp;Kopiraj adresu</translation>
+ <translation>&amp;Kopirajte adresu</translation>
</message>
<message>
<source>Copy &amp;Label</source>
- <translation>Kopiraj i označi</translation>
+ <translation>Kopirajte &amp;oznaku</translation>
</message>
<message>
<source>&amp;Edit</source>
- <translation>Uredi</translation>
+ <translation>&amp;Uredite</translation>
</message>
<message>
<source>Export Address List</source>
- <translation>Izvezi listu adresa</translation>
+ <translation>Izvezite listu adresa</translation>
</message>
<message>
<source>Comma separated file (*.csv)</source>
@@ -136,12 +136,16 @@
<translation>Ponovite novu lozinku</translation>
</message>
<message>
+ <source>Show password</source>
+ <translation>Prikažite lozinku</translation>
+ </message>
+ <message>
<source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;ten or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
- <translation>Unesite novu lozinku za novčanik. &lt;br/&gt;Molimo Vas da koristite zaporku od &lt;b&gt;deset ili više slučajnih znakova&lt;/b&gt;, ili &lt;b&gt;osam ili više riječi.&lt;/b&gt;</translation>
+ <translation>Unesite novu lozinku za novčanik. &lt;br/&gt;Molimo vas da koristite zaporku od &lt;b&gt;deset ili više slučajnih znakova&lt;/b&gt;, ili &lt;b&gt;osam ili više riječi.&lt;/b&gt;</translation>
</message>
<message>
<source>Encrypt wallet</source>
- <translation>Šifriranje novčanika</translation>
+ <translation>Šifrirajte novčanik</translation>
</message>
<message>
<source>This operation needs your wallet passphrase to unlock the wallet.</source>
@@ -149,7 +153,7 @@
</message>
<message>
<source>Unlock wallet</source>
- <translation>Otključaj novčanik</translation>
+ <translation>Otključajte novčanik</translation>
</message>
<message>
<source>This operation needs your wallet passphrase to decrypt the wallet.</source>
@@ -157,11 +161,11 @@
</message>
<message>
<source>Decrypt wallet</source>
- <translation>Dešifriranje novčanika.</translation>
+ <translation>Dešifrirajte novčanik</translation>
</message>
<message>
<source>Change passphrase</source>
- <translation>Promjena lozinke</translation>
+ <translation>Promijenite lozinku</translation>
</message>
<message>
<source>Enter the old passphrase and new passphrase to the wallet.</source>
@@ -169,7 +173,7 @@
</message>
<message>
<source>Confirm wallet encryption</source>
- <translation>Potvrdi šifriranje novčanika</translation>
+ <translation>Potvrdite šifriranje novčanika</translation>
</message>
<message>
<source>Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
@@ -184,6 +188,10 @@
<translation>Novčanik šifriran</translation>
</message>
<message>
+ <source>%1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
+ <translation>%1 će se sada zatvoriti kako bi dovršio postupak šifriranja. Zapamtite da šifriranje vašeg novčanika ne može u potpunosti zaštititi vaše bitcoine od krađe preko zloćudnog softvera koji bi bio na vašem računalu.</translation>
+ </message>
+ <message>
<source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
<translation>VAŽNO: Sve prethodne pričuve vašeg novčanika trebale bi biti zamijenjene novo stvorenom, šifriranom datotekom novčanika. Zbog sigurnosnih razloga, prethodne pričuve nešifriranog novčanika će postati beskorisne čim počnete koristiti novi, šifrirani novčanik.</translation>
</message>
@@ -222,7 +230,15 @@
</context>
<context>
<name>BanTableModel</name>
- </context>
+ <message>
+ <source>IP/Netmask</source>
+ <translation>IP/Mrežna maska</translation>
+ </message>
+ <message>
+ <source>Banned Until</source>
+ <translation>Zabranjen do</translation>
+ </message>
+</context>
<context>
<name>BitcoinGUI</name>
<message>
@@ -231,7 +247,7 @@
</message>
<message>
<source>Synchronizing with network...</source>
- <translation>Usklađivanje s mrežom ...</translation>
+ <translation>Sinkronizira se s mrežom...</translation>
</message>
<message>
<source>&amp;Overview</source>
@@ -251,7 +267,7 @@
</message>
<message>
<source>Browse transaction history</source>
- <translation>Pretraži povijest transakcija</translation>
+ <translation>Pretražite povijest transakcija</translation>
</message>
<message>
<source>E&amp;xit</source>
@@ -259,35 +275,43 @@
</message>
<message>
<source>Quit application</source>
- <translation>Izlazak iz programa</translation>
+ <translation>Zatvorite aplikaciju</translation>
</message>
<message>
<source>&amp;About %1</source>
<translation>&amp;Više o %1</translation>
</message>
<message>
+ <source>Show information about %1</source>
+ <translation>Prikažite informacije o programu %1</translation>
+ </message>
+ <message>
<source>About &amp;Qt</source>
<translation>Više o &amp;Qt</translation>
</message>
<message>
<source>Show information about Qt</source>
- <translation>Prikaži informacije o Qt</translation>
+ <translation>Prikažite informacije o Qt</translation>
</message>
<message>
<source>&amp;Options...</source>
<translation>Pos&amp;tavke...</translation>
</message>
<message>
+ <source>Modify configuration options for %1</source>
+ <translation>Promijenite postavke za %1</translation>
+ </message>
+ <message>
<source>&amp;Encrypt Wallet...</source>
- <translation>Ši&amp;friraj novčanik...</translation>
+ <translation>Ši&amp;frirajte novčanik...</translation>
</message>
<message>
<source>&amp;Backup Wallet...</source>
- <translation>Spremi &amp;kopiju novčanika...</translation>
+ <translation>Spremite &amp;kopiju novčanika...</translation>
</message>
<message>
<source>&amp;Change Passphrase...</source>
- <translation>Promjena &amp;lozinke...</translation>
+ <translation>Promijenite &amp;lozinku...</translation>
</message>
<message>
<source>&amp;Sending addresses...</source>
@@ -299,15 +323,43 @@
</message>
<message>
<source>Open &amp;URI...</source>
- <translation>Otvori &amp;URI...</translation>
+ <translation>Otvorite &amp;URI...</translation>
+ </message>
+ <message>
+ <source>Wallet:</source>
+ <translation>Novčanik:</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation>uobičajeni novčanik</translation>
+ </message>
+ <message>
+ <source>Click to disable network activity.</source>
+ <translation>Kliknite da isključite mrežnu aktivnost.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Mrežna aktivnost isključena.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>Kliknite da ponovo uključite mrežnu aktivnost.</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Sinkroniziraju se zaglavlja (%1%)...</translation>
</message>
<message>
<source>Reindexing blocks on disk...</source>
<translation>Re-indeksiranje blokova na disku...</translation>
</message>
<message>
+ <source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
+ <translation>Proxy je &lt;b&gt;uključen&lt;/b&gt;: %1</translation>
+ </message>
+ <message>
<source>Send coins to a Bitcoin address</source>
- <translation>Slanje novca na bitcoin adresu</translation>
+ <translation>Pošaljite novac na Bitcoin adresu</translation>
</message>
<message>
<source>Backup wallet to another location</source>
@@ -323,7 +375,7 @@
</message>
<message>
<source>Open debugging and diagnostic console</source>
- <translation>Otvori konzolu za dijagnostiku</translation>
+ <translation>Otvorite konzolu za dijagnostiku</translation>
</message>
<message>
<source>&amp;Verify message...</source>
@@ -339,31 +391,31 @@
</message>
<message>
<source>&amp;Send</source>
- <translation>&amp;Pošalji</translation>
+ <translation>&amp;Pošaljite</translation>
</message>
<message>
<source>&amp;Receive</source>
- <translation>Pri&amp;mi</translation>
+ <translation>Pri&amp;mite</translation>
</message>
<message>
<source>&amp;Show / Hide</source>
- <translation>Po&amp;kaži / Sakrij</translation>
+ <translation>Po&amp;kažite / Sakrijte</translation>
</message>
<message>
<source>Show or hide the main Window</source>
- <translation>Prikaži ili sakrij glavni prozor</translation>
+ <translation>Prikažite ili sakrijte glavni prozor</translation>
</message>
<message>
<source>Encrypt the private keys that belong to your wallet</source>
- <translation>Šifriranje privatnih ključeva koji u novčaniku</translation>
+ <translation>Šifrirajte privatne ključeve u novčaniku</translation>
</message>
<message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
- <translation>Poruku potpišemo s bitcoin adresom, kako bi dokazali vlasništvo nad tom adresom</translation>
+ <translation>Poruku potpišemo s Bitcoin adresom, kako bi dokazali vlasništvo nad tom adresom</translation>
</message>
<message>
<source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
- <translation>Provjeravanje poruke, kao dokaz, da je potpisana navedenom bitcoin adresom</translation>
+ <translation>Provjerite poruku da je potpisana s navedenom Bitcoin adresom</translation>
</message>
<message>
<source>&amp;File</source>
@@ -383,19 +435,19 @@
</message>
<message>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
- <translation>Zatraži uplatu (stvara QR kod i bitcoin: URI adresu)</translation>
+ <translation>Zatražite uplatu (stvara QR kod i bitcoin: URI adresu)</translation>
</message>
<message>
<source>Show the list of used sending addresses and labels</source>
- <translation>Prikaži popis korištenih adresa i oznaka za slanje novca</translation>
+ <translation>Prikažite popis korištenih adresa i oznaka za slanje novca</translation>
</message>
<message>
<source>Show the list of used receiving addresses and labels</source>
- <translation>Prikaži popis korištenih adresa i oznaka za primanje novca</translation>
+ <translation>Prikažite popis korištenih adresa i oznaka za primanje novca</translation>
</message>
<message>
<source>Open a bitcoin: URI or payment request</source>
- <translation>Otvori bitcoin: URI adresu ili zahtjev za uplatu</translation>
+ <translation>Otvorite bitcoin: URI adresu ili zahtjev za uplatu</translation>
</message>
<message>
<source>&amp;Command-line options</source>
@@ -407,17 +459,21 @@
</message>
<message>
<source>Indexing blocks on disk...</source>
- <translation>Indeksiram blokove na disku...</translation>
+ <translation>Indeksiraju se blokovi na disku...</translation>
</message>
<message>
<source>Processing blocks on disk...</source>
- <translation>Procesiram blokove na disku...</translation>
+ <translation>Procesiraju se blokovi na disku...</translation>
</message>
<message numerus="yes">
<source>Processed %n block(s) of transaction history.</source>
<translation><numerusform>Obrađen %n blok povijesti transakcije.</numerusform><numerusform>Obrađeno %n bloka povijesti transakcije.</numerusform><numerusform>Obrađeno %n blokova povijesti transakcije.</numerusform></translation>
</message>
<message>
+ <source>%1 behind</source>
+ <translation>%1 iza</translation>
+ </message>
+ <message>
<source>Last received block was generated %1 ago.</source>
<translation>Zadnji primljeni blok je bio ustvaren prije %1.</translation>
</message>
@@ -442,10 +498,18 @@
<translation>Ažurno</translation>
</message>
<message>
+ <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <translation>Prikažite pomoć programa %1 kako biste ispisali moguće opcije preko terminala</translation>
+ </message>
+ <message>
<source>%1 client</source>
<translation>%1 klijent</translation>
</message>
<message>
+ <source>Connecting to peers...</source>
+ <translation>Spaja se na klijente...</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Ažuriranje...</translation>
</message>
@@ -462,6 +526,11 @@
</translation>
</message>
<message>
+ <source>Wallet: %1
+</source>
+ <translation>Novčanik: %1</translation>
+ </message>
+ <message>
<source>Type: %1
</source>
<translation>Vrsta: %1
@@ -488,6 +557,14 @@
<translation>Dolazna transakcija</translation>
</message>
<message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation>Generiranje HD ključeva je &lt;b&gt;uključeno&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation>Generiranje HD ključeva je &lt;b&gt;isključeno&lt;/b&gt;</translation>
+ </message>
+ <message>
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
<translation>Novčanik je &lt;b&gt;šifriran&lt;/b&gt; i trenutno &lt;b&gt;otključan&lt;/b&gt;</translation>
</message>
@@ -495,7 +572,11 @@
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
<translation>Novčanik je &lt;b&gt;šifriran&lt;/b&gt; i trenutno &lt;b&gt;zaključan&lt;/b&gt;</translation>
</message>
- </context>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>Dogodila se kobna greška. Bitcoin ne može više sigurno nastaviti te će se zatvoriti.</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
@@ -520,7 +601,11 @@
</message>
<message>
<source>Dust:</source>
- <translation>Prah:</translation>
+ <translation>Prašina:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation>Nakon naknade:</translation>
</message>
<message>
<source>Change:</source>
@@ -531,6 +616,14 @@
<translation>Izaberi sve/ništa</translation>
</message>
<message>
+ <source>Tree mode</source>
+ <translation>Prikažite kao stablo</translation>
+ </message>
+ <message>
+ <source>List mode</source>
+ <translation>Prikažite kao listu</translation>
+ </message>
+ <message>
<source>Amount</source>
<translation>Iznos</translation>
</message>
@@ -556,19 +649,55 @@
</message>
<message>
<source>Copy address</source>
- <translation>Kopiraj adresu</translation>
+ <translation>Kopirajte adresu</translation>
</message>
<message>
<source>Copy label</source>
- <translation>Kopiraj oznaku</translation>
+ <translation>Kopirajte oznaku</translation>
</message>
<message>
<source>Copy amount</source>
- <translation>Kopiraj iznos</translation>
+ <translation>Kopirajte iznos</translation>
</message>
<message>
<source>Copy transaction ID</source>
- <translation>Kopiraj ID transakcije</translation>
+ <translation>Kopirajte ID transakcije</translation>
+ </message>
+ <message>
+ <source>Lock unspent</source>
+ <translation>Zaključajte nepotrošen input</translation>
+ </message>
+ <message>
+ <source>Unlock unspent</source>
+ <translation>Otključajte nepotrošen input</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Kopirajte iznos</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Kopirajte naknadu</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Kopirajte iznos nakon naknade</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Kopirajte količinu bajtova</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Kopirajte prašinu</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Kopirajte ostatak</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 zaključen)</translation>
</message>
<message>
<source>yes</source>
@@ -579,15 +708,31 @@
<translation>ne</translation>
</message>
<message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation>Oznaka postane crvene boje ako bilo koji primatelj dobije iznos manji od trenutnog praga "prašine" (sićušnog iznosa).</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Može varirati +/- %1 satoši(ja) po inputu.</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(nema oznake)</translation>
</message>
- </context>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>ostatak od %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(ostatak)</translation>
+ </message>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
<source>Edit Address</source>
- <translation>Uredi adresu</translation>
+ <translation>Uredite adresu</translation>
</message>
<message>
<source>&amp;Label</source>
@@ -595,11 +740,11 @@
</message>
<message>
<source>The label associated with this address list entry</source>
- <translation>Oznaka bitcoin adrese</translation>
+ <translation>Oznaka ovog zapisa u adresaru</translation>
</message>
<message>
<source>The address associated with this address list entry. This can only be modified for sending addresses.</source>
- <translation>Bitcoin adresa. Izmjene adrese su moguće samo za adrese za slanje.</translation>
+ <translation>Adresa ovog zapisa u adresaru. Može se mijenjati samo kod adresa za slanje.</translation>
</message>
<message>
<source>&amp;Address</source>
@@ -619,11 +764,19 @@
</message>
<message>
<source>The entered address "%1" is not a valid Bitcoin address.</source>
- <translation>Upisana adresa "%1" nije valjana bitcoin adresa.</translation>
+ <translation>Upisana adresa "%1" nije valjana Bitcoin adresa.</translation>
+ </message>
+ <message>
+ <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source>
+ <translation>Adresa "%1" već postoji kao primateljska adresa s oznakom "%2" te se ne može dodati kao pošiljateljska adresa.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book with label "%2".</source>
+ <translation>Unesena adresa "%1" postoji već u imeniku pod oznakom "%2".</translation>
</message>
<message>
<source>Could not unlock wallet.</source>
- <translation>Ne mogu otključati novčanik.</translation>
+ <translation>Ne može se otključati novčanik.</translation>
</message>
<message>
<source>New key generation failed.</source>
@@ -634,13 +787,21 @@
<name>FreespaceChecker</name>
<message>
<source>A new data directory will be created.</source>
- <translation>Stvoren će biti novi direktorij za podatke.</translation>
+ <translation>Bit će stvorena nova podatkovna mapa.</translation>
</message>
<message>
<source>name</source>
<translation>ime</translation>
</message>
<message>
+ <source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
+ <translation>Mapa već postoji. Dodajte %1 ako namjeravate stvoriti novu mapu ovdje.</translation>
+ </message>
+ <message>
+ <source>Path already exists, and is not a directory.</source>
+ <translation>Put već postoji i nije mapa.</translation>
+ </message>
+ <message>
<source>Cannot create data directory here.</source>
<translation>Nije moguće stvoriti direktorij za podatke na tom mjestu.</translation>
</message>
@@ -656,6 +817,10 @@
<translation>(%1-bit)</translation>
</message>
<message>
+ <source>About %1</source>
+ <translation>O programu %1</translation>
+ </message>
+ <message>
<source>Command-line options</source>
<translation>Opcije programa u naredbenoj liniji</translation>
</message>
@@ -667,13 +832,65 @@
<translation>Dobrodošli</translation>
</message>
<message>
+ <source>Welcome to %1.</source>
+ <translation>Dobrodošli u %1.</translation>
+ </message>
+ <message>
+ <source>As this is the first time the program is launched, you can choose where %1 will store its data.</source>
+ <translation>Kako je ovo prvi put da je ova aplikacija pokrenuta, možete izabrati gdje će %1 spremati svoje podatke.</translation>
+ </message>
+ <message>
+ <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
+ <translation>Kada kliknete OK, %1 počet će preuzimati i procesirati cijeli lanac blokova (%2GB) počevši s najranijim transakcijama u %3 kad je %4 prvi put pokrenut.</translation>
+ </message>
+ <message>
+ <source>This initial synchronisation is very demanding, and may expose hardware problems with your computer that had previously gone unnoticed. Each time you run %1, it will continue downloading where it left off.</source>
+ <translation>Početna sinkronizacija je vrlo zahtjevna i može otkriti hardverske probleme kod vašeg računala koji su prije prošli nezamijećeno. Svaki put kad pokrenete %1, nastavit će preuzimati odakle je stao.</translation>
+ </message>
+ <message>
+ <source>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</source>
+ <translation>Ako odlučite ograničiti spremanje lanca blokova pomoću pruninga (obrezivanja), treba preuzeti i procesirati povijesne podatke. Bit će obrisani naknadno kako bi se smanjila količina zauzetog prostora na disku.</translation>
+ </message>
+ <message>
+ <source>Use the default data directory</source>
+ <translation>Koristite uobičajenu podatkovnu mapu</translation>
+ </message>
+ <message>
+ <source>Use a custom data directory:</source>
+ <translation>Odaberite različitu podatkovnu mapu:</translation>
+ </message>
+ <message>
<source>Bitcoin</source>
<translation>Bitcoin</translation>
</message>
<message>
+ <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
+ <translation>Bit će spremljeno barem %1 GB podataka u ovoj mapi te će se povećati tijekom vremena.</translation>
+ </message>
+ <message>
+ <source>Approximately %1 GB of data will be stored in this directory.</source>
+ <translation>Otprilike %1 GB podataka bit će spremljeno u ovoj mapi.</translation>
+ </message>
+ <message>
+ <source>%1 will download and store a copy of the Bitcoin block chain.</source>
+ <translation>%1 preuzet će i pohraniti kopiju Bitcoinovog lanca blokova.</translation>
+ </message>
+ <message>
+ <source>The wallet will also be stored in this directory.</source>
+ <translation>Novčanik bit će pohranjen u ovoj mapi.</translation>
+ </message>
+ <message>
+ <source>Error: Specified data directory "%1" cannot be created.</source>
+ <translation>Greška: Zadana podatkovna mapa "%1" ne može biti stvorena.</translation>
+ </message>
+ <message>
<source>Error</source>
<translation>Greška</translation>
</message>
+ <message numerus="yes">
+ <source>%n GB of free space available</source>
+ <translation><numerusform>Dostupno %n GB slobodnog prostora</numerusform><numerusform>Dostupno %n GB slobodnog prostora</numerusform><numerusform>Dostupno %n GB slobodnog prostora</numerusform></translation>
+ </message>
</context>
<context>
<name>ModalOverlay</name>
@@ -682,10 +899,50 @@
<translation>Oblik</translation>
</message>
<message>
+ <source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source>
+ <translation>Nedavne transakcije možda još nisu vidljive pa vam stanje novčanika može biti netočno. Ove informacije bit će točne nakon što vaš novčanik dovrši sinkronizaciju s Bitcoinovom mrežom, kako je opisano dolje.</translation>
+ </message>
+ <message>
+ <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source>
+ <translation>Mreža neće prihvatiti pokušaje trošenja bitcoina koji su utjecani sa strane transakcija koje još nisu vidljive.</translation>
+ </message>
+ <message>
+ <source>Number of blocks left</source>
+ <translation>Broj preostalih blokova</translation>
+ </message>
+ <message>
+ <source>Unknown...</source>
+ <translation>Nepoznato...</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation>Posljednje vrijeme bloka</translation>
</message>
- </context>
+ <message>
+ <source>Progress</source>
+ <translation>Napredak</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation>Postotak povećanja napretka na sat</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>računa...</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation>Preostalo vrijeme do završetka sinkronizacije</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Sakrijte</translation>
+ </message>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>Nepoznato. Sinkroniziraju se zaglavlja (%1)...</translation>
+ </message>
+</context>
<context>
<name>OpenURIDialog</name>
<message>
@@ -720,6 +977,14 @@
<translation>&amp;Glavno</translation>
</message>
<message>
+ <source>Automatically start %1 after logging in to the system.</source>
+ <translation>Automatski pokrenite %1 nakon prijave u sustav.</translation>
+ </message>
+ <message>
+ <source>&amp;Start %1 on system login</source>
+ <translation>&amp;Pokrenite %1 kod prijave u sustav</translation>
+ </message>
+ <message>
<source>Size of &amp;database cache</source>
<translation>Veličina predmemorije baze podataka</translation>
</message>
@@ -736,10 +1001,42 @@
<translation>IP adresa proxy servera (npr. IPv4: 127.0.0.1 / IPv6: ::1)</translation>
</message>
<message>
+ <source>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source>
+ <translation>Prikazuje se ako je isporučeni uobičajeni SOCKS5 proxy korišten radi dohvaćanja klijenata preko ovog tipa mreže.</translation>
+ </message>
+ <message>
+ <source>Use separate SOCKS&amp;5 proxy to reach peers via Tor hidden services:</source>
+ <translation>Koristite zaseban SOCKS&amp;5 proxy kako biste dohvatili klijente preko Tora:</translation>
+ </message>
+ <message>
+ <source>Hide the icon from the system tray.</source>
+ <translation>Sakrijte ikonu sa sustavne trake.</translation>
+ </message>
+ <message>
+ <source>&amp;Hide tray icon</source>
+ <translation>&amp;Sakrijte ikonu</translation>
+ </message>
+ <message>
<source>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source>
<translation>Minimizirati aplikaciju umjesto zatvoriti, kada se zatvori prozor. Kada je ova opcija omogućena, aplikacija će biti zatvorena tek nakon odabira naredbe Izlaz u izborniku.</translation>
</message>
<message>
+ <source>Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source>
+ <translation>URL-ovi treće stranke (npr. preglednik blokova) koji se javljaju u kartici transakcija kao elementi kontekstnog izbornika. %s u URL-u zamijenjen je hashom transakcije. Višestruki URL-ovi su odvojeni vertikalnom crtom |.</translation>
+ </message>
+ <message>
+ <source>Active command-line options that override above options:</source>
+ <translation>Aktivne terminalne opcije koje poništavaju navedene opcije:</translation>
+ </message>
+ <message>
+ <source>Open the %1 configuration file from the working directory.</source>
+ <translation>Otvorite konfiguracijsku datoteku programa %1 s radne mape.</translation>
+ </message>
+ <message>
+ <source>Open Configuration File</source>
+ <translation>Otvorite konfiguracijsku datoteku</translation>
+ </message>
+ <message>
<source>Reset all client options to default.</source>
<translation>Nastavi sve postavke programa na početne vrijednosti.</translation>
</message>
@@ -752,10 +1049,42 @@
<translation>&amp;Mreža</translation>
</message>
<message>
+ <source>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</source>
+ <translation>Isključuje napredne mogućnosti ali će svi blokovi ipak biti potpuno validirani. Vraćanje na prijašnje stanje zahtijeva ponovo preuzimanje cijelog lanca blokova. Realna količina zauzetog prostora na disku može biti ponešto veća.</translation>
+ </message>
+ <message>
+ <source>Prune &amp;block storage to</source>
+ <translation>Obrezujte pohranu &amp;blokova na</translation>
+ </message>
+ <message>
+ <source>GB</source>
+ <translation>GB</translation>
+ </message>
+ <message>
+ <source>Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation>Vraćanje na prijašnje stanje zahtijeva ponovo preuzimanje cijelog lanca blokova.</translation>
+ </message>
+ <message>
+ <source>(0 = auto, &lt;0 = leave that many cores free)</source>
+ <translation>(0 = automatski odredite, &lt;0 = ostavite slobodno upravo toliko jezgri)</translation>
+ </message>
+ <message>
<source>W&amp;allet</source>
<translation>&amp;Novčanik</translation>
</message>
<message>
+ <source>Expert</source>
+ <translation>Stručne postavke</translation>
+ </message>
+ <message>
+ <source>Enable coin &amp;control features</source>
+ <translation>Uključite postavke kontroliranja inputa</translation>
+ </message>
+ <message>
+ <source>If you disable the spending of unconfirmed change, the change from a transaction cannot be used until that transaction has at least one confirmation. This also affects how your balance is computed.</source>
+ <translation>Ako isključite trošenje nepotvrđenog ostatka, ostatak transakcije ne može biti korišten dok ta transakcija ne dobije barem jednu potvrdu. Također utječe na to kako je vaše stanje računato.</translation>
+ </message>
+ <message>
<source>&amp;Spend unconfirmed change</source>
<translation>&amp;Trošenje nepotvrđenih vraćenih iznosa</translation>
</message>
@@ -768,6 +1097,22 @@
<translation>Mapiraj port koristeći &amp;UPnP</translation>
</message>
<message>
+ <source>Accept connections from outside.</source>
+ <translation>Prihvatite veze izvana.</translation>
+ </message>
+ <message>
+ <source>Allow incomin&amp;g connections</source>
+ <translation>Dozvolite dolazeće veze</translation>
+ </message>
+ <message>
+ <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source>
+ <translation>Spojite se na Bitcoin mrežu kroz SOCKS5 proxy.</translation>
+ </message>
+ <message>
+ <source>&amp;Connect through SOCKS5 proxy (default proxy):</source>
+ <translation>&amp;Spojite se kroz SOCKS5 proxy (uobičajeni proxy)</translation>
+ </message>
+ <message>
<source>Proxy &amp;IP:</source>
<translation>Proxy &amp;IP:</translation>
</message>
@@ -780,6 +1125,26 @@
<translation>Proxy vrata (npr. 9050)</translation>
</message>
<message>
+ <source>Used for reaching peers via:</source>
+ <translation>Korišten za dohvaćanje klijenata preko:</translation>
+ </message>
+ <message>
+ <source>IPv4</source>
+ <translation>IPv4-a</translation>
+ </message>
+ <message>
+ <source>IPv6</source>
+ <translation>IPv6-a</translation>
+ </message>
+ <message>
+ <source>Tor</source>
+ <translation>Tora</translation>
+ </message>
+ <message>
+ <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source>
+ <translation>Spojite se na Bitcoin mrežu kroz zaseban SOCKS5 proxy za povezivanje na Tor.</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation>&amp;Prozor</translation>
</message>
@@ -804,6 +1169,10 @@
<translation>Jezi&amp;k sučelja:</translation>
</message>
<message>
+ <source>The user interface language can be set here. This setting will take effect after restarting %1.</source>
+ <translation>Jezik korisničkog sučelja može se postaviti ovdje. Postavka će vrijediti nakon ponovnog pokretanja programa %1.</translation>
+ </message>
+ <message>
<source>&amp;Unit to show amounts in:</source>
<translation>&amp;Jedinica za prikaz iznosa:</translation>
</message>
@@ -812,6 +1181,14 @@
<translation>Izaberite željeni najmanji dio bitcoina koji će biti prikazan u sučelju i koji će se koristiti za plaćanje.</translation>
</message>
<message>
+ <source>Whether to show coin control features or not.</source>
+ <translation>Ovisi želite li prikazati mogućnosti kontroliranja inputa ili ne.</translation>
+ </message>
+ <message>
+ <source>&amp;Third party transaction URLs</source>
+ <translation>&amp;URL-ovi treće stranke o transakciji</translation>
+ </message>
+ <message>
<source>&amp;OK</source>
<translation>&amp;U redu</translation>
</message>
@@ -824,10 +1201,42 @@
<translation>standardne vrijednosti</translation>
</message>
<message>
+ <source>none</source>
+ <translation>ništa</translation>
+ </message>
+ <message>
+ <source>Confirm options reset</source>
+ <translation>Potvrdite resetiranje opcija</translation>
+ </message>
+ <message>
+ <source>Client restart required to activate changes.</source>
+ <translation>Potrebno je ponovno pokretanje klijenta kako bi se promjene aktivirale.</translation>
+ </message>
+ <message>
+ <source>Client will be shut down. Do you want to proceed?</source>
+ <translation>Zatvorit će se klijent. Želite li nastaviti?</translation>
+ </message>
+ <message>
+ <source>Configuration options</source>
+ <translation>Konfiguracijske postavke</translation>
+ </message>
+ <message>
+ <source>The configuration file is used to specify advanced user options which override GUI settings. Additionally, any command-line options will override this configuration file.</source>
+ <translation>Ova konfiguracijska datoteka je korištena za specificiranje napredne korisničke opcije koje će poništiti postavke GUI-a. Također će bilo koje opcije navedene preko terminala poništiti ovu konfiguracijsku datoteku.</translation>
+ </message>
+ <message>
<source>Error</source>
<translation>Greška</translation>
</message>
<message>
+ <source>The configuration file could not be opened.</source>
+ <translation>Konfiguracijska datoteka nije se mogla otvoriti.</translation>
+ </message>
+ <message>
+ <source>This change would require a client restart.</source>
+ <translation>Ova promjena zahtijeva da se klijent ponovo pokrene.</translation>
+ </message>
+ <message>
<source>The supplied proxy address is invalid.</source>
<translation>Priložena proxy adresa je nevažeća.</translation>
</message>
@@ -843,20 +1252,184 @@
<translation>Prikazani podatci mogu biti zastarjeli. Vaš novčanik se automatski sinkronizira s Bitcoin mrežom kada je veza uspostavljena, ali taj proces još nije završen.</translation>
</message>
<message>
+ <source>Watch-only:</source>
+ <translation>Isključivno promatrane adrese:</translation>
+ </message>
+ <message>
+ <source>Available:</source>
+ <translation>Dostupno:</translation>
+ </message>
+ <message>
+ <source>Your current spendable balance</source>
+ <translation>Trenutno stanje koje možete trošiti</translation>
+ </message>
+ <message>
+ <source>Pending:</source>
+ <translation>Neriješeno:</translation>
+ </message>
+ <message>
+ <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source>
+ <translation>Ukupan iznos transakcija koje se još moraju potvrditi te se ne računa kao stanje koje se može trošiti</translation>
+ </message>
+ <message>
+ <source>Immature:</source>
+ <translation>Nezrelo:</translation>
+ </message>
+ <message>
+ <source>Mined balance that has not yet matured</source>
+ <translation>Izrudareno stanje koje još nije dozrijevalo</translation>
+ </message>
+ <message>
+ <source>Balances</source>
+ <translation>Stanja</translation>
+ </message>
+ <message>
<source>Total:</source>
<translation>Ukupno:</translation>
</message>
- </context>
+ <message>
+ <source>Your current total balance</source>
+ <translation>Vaše trenutno svekupno stanje</translation>
+ </message>
+ <message>
+ <source>Your current balance in watch-only addresses</source>
+ <translation>Vaše trenutno stanje kod eksluzivno promatranih (watch-only) adresa</translation>
+ </message>
+ <message>
+ <source>Spendable:</source>
+ <translation>Stanje koje se može trošiti:</translation>
+ </message>
+ <message>
+ <source>Recent transactions</source>
+ <translation>Nedavne transakcije</translation>
+ </message>
+ <message>
+ <source>Unconfirmed transactions to watch-only addresses</source>
+ <translation>Nepotvrđene transakcije isključivo promatranim adresama</translation>
+ </message>
+ <message>
+ <source>Mined balance in watch-only addresses that has not yet matured</source>
+ <translation>Izrudareno stanje na isključivo promatranim adresama koje još nije dozrijevalo</translation>
+ </message>
+ <message>
+ <source>Current total balance in watch-only addresses</source>
+ <translation>Trenutno ukupno stanje na isključivo promatranim adresama</translation>
+ </message>
+</context>
<context>
<name>PaymentServer</name>
<message>
+ <source>Payment request error</source>
+ <translation>Greška kod zahtjeva za plaćanje</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>Ne može se pokrenuti klijent: rukovatelj "kliknite da platite"</translation>
+ </message>
+ <message>
<source>URI handling</source>
<translation>URI upravljanje</translation>
</message>
- </context>
+ <message>
+ <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source>
+ <translation>'bitcoin://' nije ispravan URI. Koristite 'bitcoin:' umjesto toga.</translation>
+ </message>
+ <message>
+ <source>Payment request fetch URL is invalid: %1</source>
+ <translation>URL za dohvatu zahtjeva za plaćanje neispravan: %1</translation>
+ </message>
+ <message>
+ <source>Invalid payment address %1</source>
+ <translation>Nevažeća adresa za plaćanje %1</translation>
+ </message>
+ <message>
+ <source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
+ <translation>Ne može se parsirati URI! Uzrok tomu može biti nevažeća Bitcoin adresa ili neispravni parametri kod URI-a.</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</source>
+ <translation>Rukovanje datotekom zahtjeva za plaćanje</translation>
+ </message>
+ <message>
+ <source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source>
+ <translation>Nije moguće iščitati datoteku zahtjeva za plaćanje! Uzrok tomu može biti nevažeća datoteka zahtjeva za plaćanje.</translation>
+ </message>
+ <message>
+ <source>Payment request rejected</source>
+ <translation>Zahtjev za plaćanje odbijen</translation>
+ </message>
+ <message>
+ <source>Payment request network doesn't match client network.</source>
+ <translation>Mreža zahtjeva za plaćanje ne poklapa se s mrežom klijenta.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Zahtjev za plaćanje istekao.</translation>
+ </message>
+ <message>
+ <source>Payment request is not initialized.</source>
+ <translation>Zahtjev za plaćanje nije inicijaliziran.</translation>
+ </message>
+ <message>
+ <source>Unverified payment requests to custom payment scripts are unsupported.</source>
+ <translation>Neprovjereni zahtjevi za plaćanje prilagođenim skriptima za plaćanje su nepodržani.</translation>
+ </message>
+ <message>
+ <source>Invalid payment request.</source>
+ <translation>Nevažeći zahtjev za plaćanje.</translation>
+ </message>
+ <message>
+ <source>Requested payment amount of %1 is too small (considered dust).</source>
+ <translation>Traženi iznos plaćanja %1 je premalen (smatra se "prašinom", sićušnim iznosom).</translation>
+ </message>
+ <message>
+ <source>Refund from %1</source>
+ <translation>Povrat iz %1</translation>
+ </message>
+ <message>
+ <source>Payment request %1 is too large (%2 bytes, allowed %3 bytes).</source>
+ <translation>Zahtjev za plaćanje %1 je prevelik (%2 bajt(ov)a, dozvoljeno %3 bajt(ov)a).</translation>
+ </message>
+ <message>
+ <source>Error communicating with %1: %2</source>
+ <translation>Greška kod komuniciranja s %1: %2</translation>
+ </message>
+ <message>
+ <source>Payment request cannot be parsed!</source>
+ <translation>Zahtjev za plaćanje ne može se parsirati!</translation>
+ </message>
+ <message>
+ <source>Bad response from server %1</source>
+ <translation>Neispravan odgovor sa strane servera %1</translation>
+ </message>
+ <message>
+ <source>Network request error</source>
+ <translation>Greška kod mrežnog zahtjeva</translation>
+ </message>
+ <message>
+ <source>Payment acknowledged</source>
+ <translation>Plaćanje priznato</translation>
+ </message>
+</context>
<context>
<name>PeerTableModel</name>
<message>
+ <source>User Agent</source>
+ <translation>Korisnički agent</translation>
+ </message>
+ <message>
+ <source>Node/Service</source>
+ <translation>Čvor/Servis</translation>
+ </message>
+ <message>
+ <source>NodeId</source>
+ <translation>NodeId (ID čvora)</translation>
+ </message>
+ <message>
+ <source>Ping</source>
+ <translation>Ping</translation>
+ </message>
+ <message>
<source>Sent</source>
<translation>Poslano</translation>
</message>
@@ -872,13 +1445,85 @@
<translation>Iznos</translation>
</message>
<message>
+ <source>Enter a Bitcoin address (e.g. %1)</source>
+ <translation>Unesite Bitcoin adresu (npr. %1)</translation>
+ </message>
+ <message>
+ <source>%1 d</source>
+ <translation>%1 d</translation>
+ </message>
+ <message>
+ <source>%1 h</source>
+ <translation>%1 h</translation>
+ </message>
+ <message>
+ <source>%1 m</source>
+ <translation>%1 m</translation>
+ </message>
+ <message>
+ <source>%1 s</source>
+ <translation>%1 s</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>Ništa</translation>
+ </message>
+ <message>
<source>N/A</source>
<translation>N/A</translation>
</message>
<message>
+ <source>%1 ms</source>
+ <translation>%1 ms</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation><numerusform>%n sekund</numerusform><numerusform>%n sekundi</numerusform><numerusform>%n sekundi</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation><numerusform>%n minut</numerusform><numerusform>%n minuta</numerusform><numerusform>%n minuta</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation><numerusform>%n sat</numerusform><numerusform>%n sata</numerusform><numerusform>%n sati</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation><numerusform>%n dan</numerusform><numerusform>%n dana</numerusform><numerusform>%n dana</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation><numerusform>%n tjedan</numerusform><numerusform>%n tjedna</numerusform><numerusform>%n tjedana</numerusform></translation>
+ </message>
+ <message>
<source>%1 and %2</source>
<translation>%1 i %2</translation>
</message>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation><numerusform>%n godina</numerusform><numerusform>%n godine</numerusform><numerusform>%n godina</numerusform></translation>
+ </message>
+ <message>
+ <source>%1 B</source>
+ <translation>%1 B</translation>
+ </message>
+ <message>
+ <source>%1 KB</source>
+ <translation>%1 KB</translation>
+ </message>
+ <message>
+ <source>%1 MB</source>
+ <translation>%1 MB</translation>
+ </message>
+ <message>
+ <source>%1 GB</source>
+ <translation>%1 GB</translation>
+ </message>
+ <message>
+ <source>%1 didn't yet exit safely...</source>
+ <translation>%1 se još nije sigurno zatvorio.</translation>
+ </message>
<message>
<source>unknown</source>
<translation>nepoznato</translation>
@@ -886,7 +1531,23 @@
</context>
<context>
<name>QObject::QObject</name>
- </context>
+ <message>
+ <source>Error parsing command line arguments: %1.</source>
+ <translation>Greška kod parsiranja argumenata unesnih preko terminala: %1.</translation>
+ </message>
+ <message>
+ <source>Error: Specified data directory "%1" does not exist.</source>
+ <translation>Greška: Zadana podatkovna mapa "%1" ne postoji.</translation>
+ </message>
+ <message>
+ <source>Error: Cannot parse configuration file: %1.</source>
+ <translation>Greška: Ne može se parsirati konfiguracijska datoteka: %1.</translation>
+ </message>
+ <message>
+ <source>Error: %1</source>
+ <translation>Greška: %1</translation>
+ </message>
+</context>
<context>
<name>QRImageWidget</name>
<message>
@@ -897,7 +1558,11 @@
<source>Save QR Code</source>
<translation>Spremi QR kod</translation>
</message>
- </context>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>PNG slika (*.png)</translation>
+ </message>
+</context>
<context>
<name>RPCConsole</name>
<message>
@@ -917,6 +1582,22 @@
<translation>Konzola za dijagnostiku</translation>
</message>
<message>
+ <source>General</source>
+ <translation>Općenito</translation>
+ </message>
+ <message>
+ <source>Using BerkeleyDB version</source>
+ <translation>Verzija BerkeleyDB-a</translation>
+ </message>
+ <message>
+ <source>Datadir</source>
+ <translation>Datadir (podatkovna mapa)</translation>
+ </message>
+ <message>
+ <source>Startup time</source>
+ <translation>Vrijeme pokretanja</translation>
+ </message>
+ <message>
<source>Network</source>
<translation>Mreža</translation>
</message>
@@ -937,6 +1618,30 @@
<translation>Trenutni broj blokova</translation>
</message>
<message>
+ <source>Memory Pool</source>
+ <translation>Memorijski bazen</translation>
+ </message>
+ <message>
+ <source>Current number of transactions</source>
+ <translation>Trenutan broj transakcija</translation>
+ </message>
+ <message>
+ <source>Memory usage</source>
+ <translation>Korištena memorija</translation>
+ </message>
+ <message>
+ <source>Wallet: </source>
+ <translation>Novčanik:</translation>
+ </message>
+ <message>
+ <source>(none)</source>
+ <translation>(ništa)</translation>
+ </message>
+ <message>
+ <source>&amp;Reset</source>
+ <translation>&amp;Resetirajte</translation>
+ </message>
+ <message>
<source>Received</source>
<translation>Primljeno</translation>
</message>
@@ -945,6 +1650,22 @@
<translation>Poslano</translation>
</message>
<message>
+ <source>&amp;Peers</source>
+ <translation>&amp;Klijenti</translation>
+ </message>
+ <message>
+ <source>Banned peers</source>
+ <translation>Zabranjeni klijenti</translation>
+ </message>
+ <message>
+ <source>Select a peer to view detailed information.</source>
+ <translation>Odaberite klijent kako biste vidjeli detaljne informacije.</translation>
+ </message>
+ <message>
+ <source>Whitelisted</source>
+ <translation>Na bijeloj listi</translation>
+ </message>
+ <message>
<source>Direction</source>
<translation>Smjer</translation>
</message>
@@ -953,10 +1674,74 @@
<translation>Verzija</translation>
</message>
<message>
+ <source>Starting Block</source>
+ <translation>Početni blok</translation>
+ </message>
+ <message>
+ <source>Synced Headers</source>
+ <translation>Broj sinkroniziranih zaglavlja</translation>
+ </message>
+ <message>
+ <source>Synced Blocks</source>
+ <translation>Broj sinkronizranih blokova</translation>
+ </message>
+ <message>
+ <source>User Agent</source>
+ <translation>Korisnički agent</translation>
+ </message>
+ <message>
+ <source>Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</source>
+ <translation>Otvorite datoteku zapisa programa %1 iz trenutne podatkovne mape. Može potrajati nekoliko sekundi za velike datoteke zapisa.</translation>
+ </message>
+ <message>
+ <source>Decrease font size</source>
+ <translation>Smanjite veličinu fonta</translation>
+ </message>
+ <message>
+ <source>Increase font size</source>
+ <translation>Povećajte veličinu fonta</translation>
+ </message>
+ <message>
+ <source>Services</source>
+ <translation>Usluge</translation>
+ </message>
+ <message>
+ <source>Ban Score</source>
+ <translation>Broj zabrana</translation>
+ </message>
+ <message>
<source>Connection Time</source>
<translation>Trajanje veze</translation>
</message>
<message>
+ <source>Last Send</source>
+ <translation>Zadnja pošiljka</translation>
+ </message>
+ <message>
+ <source>Last Receive</source>
+ <translation>Zadnji primitak</translation>
+ </message>
+ <message>
+ <source>Ping Time</source>
+ <translation>Vrijeme pinga</translation>
+ </message>
+ <message>
+ <source>The duration of a currently outstanding ping.</source>
+ <translation>Trajanje trenutno izvanrednog pinga</translation>
+ </message>
+ <message>
+ <source>Ping Wait</source>
+ <translation>Zakašnjenje pinga</translation>
+ </message>
+ <message>
+ <source>Min Ping</source>
+ <translation>Min ping</translation>
+ </message>
+ <message>
+ <source>Time Offset</source>
+ <translation>Vremenski ofset</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation>Posljednje vrijeme bloka</translation>
</message>
@@ -977,10 +1762,114 @@
<translation>Ukupno:</translation>
</message>
<message>
+ <source>In:</source>
+ <translation>Dolazne:</translation>
+ </message>
+ <message>
+ <source>Out:</source>
+ <translation>Izlazne:</translation>
+ </message>
+ <message>
+ <source>Debug log file</source>
+ <translation>Datoteka ispisa za debagiranje</translation>
+ </message>
+ <message>
<source>Clear console</source>
<translation>Očisti konzolu</translation>
</message>
<message>
+ <source>1 &amp;hour</source>
+ <translation>1 &amp;sat</translation>
+ </message>
+ <message>
+ <source>1 &amp;day</source>
+ <translation>1 &amp;dan</translation>
+ </message>
+ <message>
+ <source>1 &amp;week</source>
+ <translation>1 &amp;tjedan</translation>
+ </message>
+ <message>
+ <source>1 &amp;year</source>
+ <translation>1 &amp;godinu</translation>
+ </message>
+ <message>
+ <source>&amp;Disconnect</source>
+ <translation>&amp;Odspojite</translation>
+ </message>
+ <message>
+ <source>Ban for</source>
+ <translation>Zabranite za</translation>
+ </message>
+ <message>
+ <source>&amp;Unban</source>
+ <translation>&amp;Ukinite zabranu</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation>uobičajeni novčanik</translation>
+ </message>
+ <message>
+ <source>Welcome to the %1 RPC console.</source>
+ <translation>Dobrodošli u %1 RPC konzolu.</translation>
+ </message>
+ <message>
+ <source>Use up and down arrows to navigate history, and %1 to clear screen.</source>
+ <translation>Koristite tipke gore i dolje za izbor već korištenih naredbi. %1 kako biste očistili ekran i povijest naredbi.</translation>
+ </message>
+ <message>
+ <source>Type %1 for an overview of available commands.</source>
+ <translation>Utipkajte %1 za pregled dostupnih naredbi.</translation>
+ </message>
+ <message>
+ <source>For more information on using this console type %1.</source>
+ <translation>Za više informacija o korištenju ove konzole utipkajte %1.</translation>
+ </message>
+ <message>
+ <source>WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.</source>
+ <translation>UPOZORENJE: Prevaranti su aktivni i govore korisnicima da utipkaju naredbe ovdje kako bi ispraznili sadržaje njihovih novčanika. Ne koristite ovu konzolu bez da u potpunosti razumijete posljedice naredbe.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled</source>
+ <translation>Mrežna aktivnost isključena</translation>
+ </message>
+ <message>
+ <source>Executing command without any wallet</source>
+ <translation>Izvršava se naredba bez bilo kakvog novčanika</translation>
+ </message>
+ <message>
+ <source>Executing command using "%1" wallet</source>
+ <translation>Izvršava se naredba koristeći novčanik "%1"</translation>
+ </message>
+ <message>
+ <source>(node id: %1)</source>
+ <translation>(ID čvora: %1)</translation>
+ </message>
+ <message>
+ <source>via %1</source>
+ <translation>preko %1</translation>
+ </message>
+ <message>
+ <source>never</source>
+ <translation>nikad</translation>
+ </message>
+ <message>
+ <source>Inbound</source>
+ <translation>Dolazni</translation>
+ </message>
+ <message>
+ <source>Outbound</source>
+ <translation>Izlazni</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Da</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Ne</translation>
+ </message>
+ <message>
<source>Unknown</source>
<translation>Nepoznato</translation>
</message>
@@ -1000,22 +1889,74 @@
<translation>&amp;Poruka:</translation>
</message>
<message>
+ <source>An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Bitcoin network.</source>
+ <translation>Opcionalna poruka koja se može dodati kao privitak zahtjevu za plaćanje. Bit će prikazana kad je zahtjev otvoren. Napomena: Ova poruka neće biti poslana zajedno s uplatom preko Bitcoin mreže.</translation>
+ </message>
+ <message>
+ <source>An optional label to associate with the new receiving address.</source>
+ <translation>Opcionalna oznaka koja će se povezati s novom primateljskom adresom.</translation>
+ </message>
+ <message>
+ <source>Use this form to request payments. All fields are &lt;b&gt;optional&lt;/b&gt;.</source>
+ <translation>Koristite ovaj formular kako biste zahtijevali uplate. Sva su polja &lt;b&gt;opcionalna&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source>
+ <translation>Opcionalan iznos koji možete zahtijevati. Ostavite ovo prazno ili unesite nulu ako ne želite zahtijevati specifičan iznos.</translation>
+ </message>
+ <message>
<source>Clear all fields of the form.</source>
<translation>Obriši sva polja</translation>
</message>
<message>
+ <source>Clear</source>
+ <translation>Obrišite</translation>
+ </message>
+ <message>
+ <source>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</source>
+ <translation>Izvorne SegWit adrese (tzv. Bech32 ili BIP-173) smanjuju vaše transakcijske naknade ubuduće i nude bolju zaštitu protiv tipfelera, ali stari novčanici ih ne podržavaju. Kada je ova opcija isključena, bit će umjesto toga stvorena adresa koja je kompatibilna sa starijim novčanicima.</translation>
+ </message>
+ <message>
+ <source>Generate native segwit (Bech32) address</source>
+ <translation>Generirajte izvornu SegWit (Bech32) adresu</translation>
+ </message>
+ <message>
+ <source>Requested payments history</source>
+ <translation>Povijest zahtjeva za plaćanje</translation>
+ </message>
+ <message>
<source>&amp;Request payment</source>
<translation>&amp;Zatraži plaćanje</translation>
</message>
<message>
+ <source>Show the selected request (does the same as double clicking an entry)</source>
+ <translation>Prikazuje izabran zahtjev (isto učini dvostruki klik na zapis)</translation>
+ </message>
+ <message>
<source>Show</source>
<translation>Pokaži</translation>
</message>
<message>
+ <source>Remove the selected entries from the list</source>
+ <translation>Uklonite odabrane zapise s popisa</translation>
+ </message>
+ <message>
+ <source>Remove</source>
+ <translation>Uklonite</translation>
+ </message>
+ <message>
+ <source>Copy URI</source>
+ <translation>Kopirajte URI</translation>
+ </message>
+ <message>
<source>Copy label</source>
<translation>Kopiraj oznaku</translation>
</message>
<message>
+ <source>Copy message</source>
+ <translation>Kopirajte poruku</translation>
+ </message>
+ <message>
<source>Copy amount</source>
<translation>Kopiraj iznos</translation>
</message>
@@ -1039,6 +1980,14 @@
<translation>&amp;Spremi sliku...</translation>
</message>
<message>
+ <source>Request payment to %1</source>
+ <translation>&amp;Zatražite plaćanje na adresu %1</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>Informacije o uplati</translation>
+ </message>
+ <message>
<source>URI</source>
<translation>URI</translation>
</message>
@@ -1093,7 +2042,15 @@
<source>(no message)</source>
<translation>(bez poruke)</translation>
</message>
- </context>
+ <message>
+ <source>(no amount requested)</source>
+ <translation>(nikakav iznos zahtijevan)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation>Zatraženo</translation>
+ </message>
+</context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1101,6 +2058,18 @@
<translation>Slanje novca</translation>
</message>
<message>
+ <source>Coin Control Features</source>
+ <translation>Mogućnosti kontroliranja inputa</translation>
+ </message>
+ <message>
+ <source>Inputs...</source>
+ <translation>Inputi...</translation>
+ </message>
+ <message>
+ <source>automatically selected</source>
+ <translation>automatski izabrano</translation>
+ </message>
+ <message>
<source>Insufficient funds!</source>
<translation>Nedovoljna sredstva</translation>
</message>
@@ -1121,14 +2090,78 @@
<translation>Naknada:</translation>
</message>
<message>
+ <source>After Fee:</source>
+ <translation>Nakon naknade:</translation>
+ </message>
+ <message>
<source>Change:</source>
<translation>Vraćeno:</translation>
</message>
<message>
+ <source>If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</source>
+ <translation>Ako je ovo aktivirano, ali adresa u koju treba poslati ostatak je prazna ili nevažeća, onda će ostatak biti poslan u novo generiranu adresu.</translation>
+ </message>
+ <message>
+ <source>Custom change address</source>
+ <translation>Zadana adresa u koju će ostatak biti poslan</translation>
+ </message>
+ <message>
<source>Transaction Fee:</source>
<translation>Naknada za transakciju:</translation>
</message>
<message>
+ <source>Choose...</source>
+ <translation>Birajte...</translation>
+ </message>
+ <message>
+ <source>Using the fallbackfee can result in sending a transaction that will take several hours or days (or never) to confirm. Consider choosing your fee manually or wait until you have validated the complete chain.</source>
+ <translation>Korištenje rezervnu naknadu može rezultirati slanjem transakcije kojoj može trebati nekoliko sati ili dana (ili pak nikad) da se potvrdi. Uzmite u obzir ručno biranje naknade ili pričekajte da se cijeli lanac validira.</translation>
+ </message>
+ <message>
+ <source>Warning: Fee estimation is currently not possible.</source>
+ <translation>Upozorenje: Procjena naknada trenutno nije moguća.</translation>
+ </message>
+ <message>
+ <source>collapse fee-settings</source>
+ <translation>Sažimajte opcije naknade</translation>
+ </message>
+ <message>
+ <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size.
+
+Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis per kB" for a transaction size of 500 bytes (half of 1 kB) would ultimately yield a fee of only 50 satoshis.</source>
+ <translation>Zadajte prilagođeu naknadu po kB (1000 bajtova) virtualne veličine transakcije.
+
+Napomena: Budući da se naknada računa po bajtu, naknada od "100 satošija po kB" za transakciju veličine 500 bajtova (polovica od 1 kB) rezultirala bi ultimativno naknadom od samo 50 satošija.</translation>
+ </message>
+ <message>
+ <source>per kilobyte</source>
+ <translation>po kilobajtu</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Sakrijte</translation>
+ </message>
+ <message>
+ <source>Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks. But be aware that this can end up in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source>
+ <translation>Plaćanje minimalnu naknadu je dovoljno ukoliko je volumen transakcija manja od prostora u blokovima. Budite svjesni da ovo može završiti tako da se transakcija nikad ne potvrdi ako je potražnja za Bitcoin transakcijama veća nego što mreža može procesirati.</translation>
+ </message>
+ <message>
+ <source>(read the tooltip)</source>
+ <translation>(pročitajte opis alata)</translation>
+ </message>
+ <message>
+ <source>Recommended:</source>
+ <translation>Preporučeno:</translation>
+ </message>
+ <message>
+ <source>Custom:</source>
+ <translation>Zadano:</translation>
+ </message>
+ <message>
+ <source>(Smart fee not initialized yet. This usually takes a few blocks...)</source>
+ <translation>(Pametna procjena naknada još nije inicijalizirana. Uobičajeno traje nekoliko blokova...)</translation>
+ </message>
+ <message>
<source>Send to multiple recipients at once</source>
<translation>Pošalji novce većem broju primatelja u jednoj transakciji</translation>
</message>
@@ -1145,6 +2178,18 @@
<translation>Prah:</translation>
</message>
<message>
+ <source>Confirmation time target:</source>
+ <translation>Ciljno vrijeme potvrde:</translation>
+ </message>
+ <message>
+ <source>Enable Replace-By-Fee</source>
+ <translation>Uključite Replace-By-Fee</translation>
+ </message>
+ <message>
+ <source>With Replace-By-Fee (BIP-125) you can increase a transaction's fee after it is sent. Without this, a higher fee may be recommended to compensate for increased transaction delay risk.</source>
+ <translation>Pomoću mogućnosti Replace-By-Fee (BIP-125) možete povećati naknadu transakcije nakon što je poslana. Bez ovoga može biti preporučena veća naknada kako bi nadoknadila povećani rizik zakašnjenja transakcije.</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>Obriši &amp;sve</translation>
</message>
@@ -1161,22 +2206,82 @@
<translation>&amp;Pošalji</translation>
</message>
<message>
+ <source>Copy quantity</source>
+ <translation>Kopiraj iznos</translation>
+ </message>
+ <message>
<source>Copy amount</source>
<translation>Kopiraj iznos</translation>
</message>
<message>
+ <source>Copy fee</source>
+ <translation>Kopirajte naknadu</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Kopirajte iznos nakon naknade</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Kopirajte količinu bajtova</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Kopirajte sićušne iznose ("prašinu")</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Kopirajte ostatak</translation>
+ </message>
+ <message>
+ <source>%1 (%2 blocks)</source>
+ <translation>%1 (%2 blokova)</translation>
+ </message>
+ <message>
+ <source>%1 to %2</source>
+ <translation>%1 na %2</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to send?</source>
+ <translation>Jeste li sigurni da želite poslati transakciju?</translation>
+ </message>
+ <message>
<source>or</source>
<translation>ili</translation>
</message>
<message>
+ <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source>
+ <translation>Možete kasnije povećati naknadu (javlja Replace-By-Fee, BIP-125).</translation>
+ </message>
+ <message>
+ <source>from wallet %1</source>
+ <translation>iz novčanika %1</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction.</source>
+ <translation>Molim vas, pregledajte svoju transakciju.</translation>
+ </message>
+ <message>
<source>Transaction fee</source>
<translation>Naknada za transakciju</translation>
</message>
<message>
+ <source>Not signalling Replace-By-Fee, BIP-125.</source>
+ <translation>Ne javlja Replace-By-Fee, BIP-125.</translation>
+ </message>
+ <message>
+ <source>Total Amount</source>
+ <translation>Ukupni iznos</translation>
+ </message>
+ <message>
<source>Confirm send coins</source>
<translation>Potvrdi slanje novca</translation>
</message>
<message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>Adresa primatelja je nevažeća. Provjerite ponovno, molim vas.</translation>
+ </message>
+ <message>
<source>The amount to pay must be larger than 0.</source>
<translation>Iznos mora biti veći od 0.</translation>
</message>
@@ -1189,6 +2294,50 @@
<translation>Iznos je veći od stanja novčanika kad se doda naknada za transakcije od %1.</translation>
</message>
<message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>Duplikatna adresa pronađena: adrese trebaju biti korištene samo jedanput.</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <translation>Neuspješno stvorenje transakcije!</translation>
+ </message>
+ <message>
+ <source>The transaction was rejected with the following reason: %1</source>
+ <translation>Transakcija je bila odbijena zbog sljedećeg razloga: %1</translation>
+ </message>
+ <message>
+ <source>A fee higher than %1 is considered an absurdly high fee.</source>
+ <translation>Naknada veća od %1 smatra se apsurdno visokim naknadom.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Zahtjev za plaćanje istekao.</translation>
+ </message>
+ <message>
+ <source>Pay only the required fee of %1</source>
+ <translation>Platite samo potrebnu naknadu u iznosu od %1</translation>
+ </message>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation><numerusform>Procijenjeno je da će početi potvrđivanje unutar %n bloka.</numerusform><numerusform>Procijenjeno je da će početi potvrđivanje unutar %n bloka.</numerusform><numerusform>Procijenjeno je da će početi potvrđivanje unutar %n blokova.</numerusform></translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>Upozorenje: Nevažeća Bitcoin adresa</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation>Upozorenje: Nepoznata adresa u koju će ostatak biti poslan</translation>
+ </message>
+ <message>
+ <source>Confirm custom change address</source>
+ <translation>Potvrdite zadanu adresu u koju će ostatak biti poslan</translation>
+ </message>
+ <message>
+ <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
+ <translation>Adresa koju ste izabrali kamo ćete poslati ostatak nije dio ovog novčanika. Bilo koji iznosi u vašem novčaniku mogu biti poslani na ovu adresu. Jeste li sigurni?</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(nema oznake)</translation>
</message>
@@ -1208,6 +2357,18 @@
<translation>&amp;Oznaka:</translation>
</message>
<message>
+ <source>Choose previously used address</source>
+ <translation>Odaberite prethodno korištenu adresu</translation>
+ </message>
+ <message>
+ <source>This is a normal payment.</source>
+ <translation>Ovo je normalna uplata.</translation>
+ </message>
+ <message>
+ <source>The Bitcoin address to send the payment to</source>
+ <translation>Bitcoin adresa na koju ćete poslati uplatu</translation>
+ </message>
+ <message>
<source>Alt+A</source>
<translation>Alt+A</translation>
</message>
@@ -1220,31 +2381,95 @@
<translation>Alt+P</translation>
</message>
<message>
+ <source>Remove this entry</source>
+ <translation>Obrišite ovaj zapis</translation>
+ </message>
+ <message>
+ <source>The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally.</source>
+ <translation>Naknada će biti oduzeta od poslanog iznosa. Primatelj će primiti manji iznos od onoga koji unesete u polje iznosa. Ako je odabrano više primatelja, onda će naknada biti podjednako raspodijeljena.</translation>
+ </message>
+ <message>
+ <source>S&amp;ubtract fee from amount</source>
+ <translation>Oduzmite naknadu od iznosa</translation>
+ </message>
+ <message>
+ <source>Use available balance</source>
+ <translation>Koristite dostupno stanje</translation>
+ </message>
+ <message>
<source>Message:</source>
<translation>Poruka:</translation>
</message>
<message>
+ <source>This is an unauthenticated payment request.</source>
+ <translation>Ovo je neautenticiran zahtjev za plaćanje.</translation>
+ </message>
+ <message>
+ <source>This is an authenticated payment request.</source>
+ <translation>Ovo je autenticiran zahtjev za plaćanje.</translation>
+ </message>
+ <message>
+ <source>Enter a label for this address to add it to the list of used addresses</source>
+ <translation>Unesite oznaku za ovu adresu kako bi ju dodali u vaš adresar</translation>
+ </message>
+ <message>
+ <source>A message that was attached to the bitcoin: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Bitcoin network.</source>
+ <translation>Poruka koja je dodana uplati: URI koji će biti spremljen s transakcijom za referencu. Napomena: Ova poruka neće biti poslana preko Bitcoin mreže.</translation>
+ </message>
+ <message>
<source>Pay To:</source>
<translation>Primatelj plaćanja:</translation>
</message>
<message>
+ <source>Memo:</source>
+ <translation>Zapis:</translation>
+ </message>
+ <message>
<source>Enter a label for this address to add it to your address book</source>
<translation>Unesite oznaku za ovu adresu kako bi ju dodali u vaš adresar</translation>
</message>
</context>
<context>
<name>SendConfirmationDialog</name>
- </context>
+ <message>
+ <source>Yes</source>
+ <translation>Da</translation>
+ </message>
+</context>
<context>
<name>ShutdownWindow</name>
- </context>
+ <message>
+ <source>%1 is shutting down...</source>
+ <translation>Zatvara se %1...</translation>
+ </message>
+ <message>
+ <source>Do not shut down the computer until this window disappears.</source>
+ <translation>Ne ugasite računalo dok ovaj prozor ne nestane.</translation>
+ </message>
+</context>
<context>
<name>SignVerifyMessageDialog</name>
<message>
+ <source>Signatures - Sign / Verify a Message</source>
+ <translation>Potpisi - Potpisujte / Provjerite poruku</translation>
+ </message>
+ <message>
<source>&amp;Sign Message</source>
<translation>&amp;Potpišite poruku</translation>
</message>
<message>
+ <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source>
+ <translation>Možete potpisati poruke/dogovore svojim adresama kako biste dokazali da možete pristupiti bitcoinima poslanim na te adrese. Budite oprezni da ne potpisujte ništa nejasno ili nasumično, jer napadi phishingom vas mogu prevariti da prepišite svoj identitet njima. Potpisujte samo detaljno objašnjene izjave s kojima se slažete.</translation>
+ </message>
+ <message>
+ <source>The Bitcoin address to sign the message with</source>
+ <translation>Bitcoin adresa pomoću koje ćete potpisati poruku</translation>
+ </message>
+ <message>
+ <source>Choose previously used address</source>
+ <translation>Odaberite prethodno korištenu adresu</translation>
+ </message>
+ <message>
<source>Alt+A</source>
<translation>Alt+A</translation>
</message>
@@ -1265,10 +2490,22 @@
<translation>Potpis</translation>
</message>
<message>
+ <source>Copy the current signature to the system clipboard</source>
+ <translation>Kopirajte trenutni potpis u međuspremnik</translation>
+ </message>
+ <message>
+ <source>Sign the message to prove you own this Bitcoin address</source>
+ <translation>Potpišite poruku kako biste dokazali da posjedujete ovu Bitcoin adresu</translation>
+ </message>
+ <message>
<source>Sign &amp;Message</source>
<translation>&amp;Potpišite poruku</translation>
</message>
<message>
+ <source>Reset all sign message fields</source>
+ <translation>Resetirajte sva polja formulara</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>Obriši &amp;sve</translation>
</message>
@@ -1277,18 +2514,78 @@
<translation>&amp;Potvrdite poruku</translation>
</message>
<message>
+ <source>Enter the receiver's address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction!</source>
+ <translation>Unesite primateljevu adresu, poruku (provjerite da kopirate prekide crta, razmake, tabove, itd. točno) i potpis ispod da provjerite poruku. Pazite da ne pridodate veće značenje potpisu nego što je sadržano u samoj poruci kako biste izbjegli napad posrednika (MITM attack). Primijetite da ovo samo dokazuje da stranka koja potpisuje prima na adresu. Ne može dokažati da je neka stranka poslala transakciju!</translation>
+ </message>
+ <message>
+ <source>The Bitcoin address the message was signed with</source>
+ <translation>Bitcoin adresa kojom je poruka potpisana</translation>
+ </message>
+ <message>
+ <source>Verify the message to ensure it was signed with the specified Bitcoin address</source>
+ <translation>Provjerite poruku da budete sigurni da je potpisana zadanom Bitcoin adresom</translation>
+ </message>
+ <message>
<source>Verify &amp;Message</source>
<translation>&amp;Potvrdite poruku</translation>
</message>
<message>
+ <source>Reset all verify message fields</source>
+ <translation>Resetirajte sva polja provjeravanja poruke</translation>
+ </message>
+ <message>
+ <source>Click "Sign Message" to generate signature</source>
+ <translation>Kliknite "Potpišite poruku" da generirate potpis</translation>
+ </message>
+ <message>
+ <source>The entered address is invalid.</source>
+ <translation>Unesena adresa je neispravna.</translation>
+ </message>
+ <message>
+ <source>Please check the address and try again.</source>
+ <translation>Molim provjerite adresu i pokušajte ponovo.</translation>
+ </message>
+ <message>
+ <source>The entered address does not refer to a key.</source>
+ <translation>Unesena adresa ne odnosi se na ključ.</translation>
+ </message>
+ <message>
<source>Wallet unlock was cancelled.</source>
<translation>Otključavanje novčanika je otkazano.</translation>
</message>
<message>
+ <source>Private key for the entered address is not available.</source>
+ <translation>Privatni ključ za unesenu adresu nije dostupan.</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>Potpisivanje poruke neuspješno.</translation>
+ </message>
+ <message>
<source>Message signed.</source>
<translation>Poruka je potpisana.</translation>
</message>
- </context>
+ <message>
+ <source>The signature could not be decoded.</source>
+ <translation>Potpis nije mogao biti dešifriran.</translation>
+ </message>
+ <message>
+ <source>Please check the signature and try again.</source>
+ <translation>Molim provjerite potpis i pokušajte ponovo.</translation>
+ </message>
+ <message>
+ <source>The signature did not match the message digest.</source>
+ <translation>Potpis se ne poklapa sa sažetkom poruke (message digest).</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>Provjera poruke neuspješna.</translation>
+ </message>
+ <message>
+ <source>Message verified.</source>
+ <translation>Poruka provjerena.</translation>
+ </message>
+</context>
<context>
<name>SplashScreen</name>
<message>
@@ -1298,14 +2595,42 @@
</context>
<context>
<name>TrafficGraphWidget</name>
- </context>
+ <message>
+ <source>KB/s</source>
+ <translation>KB/s</translation>
+ </message>
+</context>
<context>
<name>TransactionDesc</name>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>Otvoren za još %n blok</numerusform><numerusform>Otvoren za još %n bloka</numerusform><numerusform>Otvoren za još %n blokova</numerusform></translation>
+ </message>
<message>
<source>Open until %1</source>
<translation>Otvoren do %1</translation>
</message>
<message>
+ <source>conflicted with a transaction with %1 confirmations</source>
+ <translation>subokljen s transakcijom broja potvrde %1</translation>
+ </message>
+ <message>
+ <source>0/unconfirmed, %1</source>
+ <translation>0/nepotvrđeno, %1</translation>
+ </message>
+ <message>
+ <source>in memory pool</source>
+ <translation>u memorijskom bazenu</translation>
+ </message>
+ <message>
+ <source>not in memory pool</source>
+ <translation>nije u memorijskom bazenu</translation>
+ </message>
+ <message>
+ <source>abandoned</source>
+ <translation>napušteno</translation>
+ </message>
+ <message>
<source>%1/unconfirmed</source>
<translation>%1/nepotvrđeno</translation>
</message>
@@ -1346,6 +2671,10 @@
<translation>vlastita adresa</translation>
</message>
<message>
+ <source>watch-only</source>
+ <translation>isključivo promatrano</translation>
+ </message>
+ <message>
<source>label</source>
<translation>oznaka</translation>
</message>
@@ -1353,6 +2682,10 @@
<source>Credit</source>
<translation>Uplaćeno</translation>
</message>
+ <message numerus="yes">
+ <source>matures in %n more block(s)</source>
+ <translation><numerusform>dozrije za još %n blok</numerusform><numerusform>dozrije za još %n bloka</numerusform><numerusform>dozrije za još %n blokova</numerusform></translation>
+ </message>
<message>
<source>not accepted</source>
<translation>Nije prihvaćeno</translation>
@@ -1362,6 +2695,14 @@
<translation>Zaduženje</translation>
</message>
<message>
+ <source>Total debit</source>
+ <translation>Ukupni debit</translation>
+ </message>
+ <message>
+ <source>Total credit</source>
+ <translation>Ukupni kredit</translation>
+ </message>
+ <message>
<source>Transaction fee</source>
<translation>Naknada za transakciju</translation>
</message>
@@ -1382,6 +2723,30 @@
<translation>ID transakcije</translation>
</message>
<message>
+ <source>Transaction total size</source>
+ <translation>Ukupna veličina transakcije</translation>
+ </message>
+ <message>
+ <source>Transaction virtual size</source>
+ <translation>Virtualna veličina transakcije</translation>
+ </message>
+ <message>
+ <source>Output index</source>
+ <translation>Indeks outputa</translation>
+ </message>
+ <message>
+ <source>Merchant</source>
+ <translation>Trgovac</translation>
+ </message>
+ <message>
+ <source>Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source>
+ <translation>Generirani novčići moraju dozrijeti %1 blokova prije nego što mogu biti potrošeni. Kada ste generirali ovaj blok, bio je emitiran na mreži kako bi bio dodan lancu blokova. Ako ne uspije ući u lanac, stanje će mu promijeniti na "neprihvaćeno" i neće se moći trošiti. Ovo se može dogoditi povremeno ako drugi čvor generira blok u roku od nekoliko sekundi od vas.</translation>
+ </message>
+ <message>
+ <source>Debug information</source>
+ <translation>Informacije za debugiranje</translation>
+ </message>
+ <message>
<source>Transaction</source>
<translation>Transakcija</translation>
</message>
@@ -1393,14 +2758,26 @@
<source>Amount</source>
<translation>Iznos</translation>
</message>
- </context>
+ <message>
+ <source>true</source>
+ <translation>istina</translation>
+ </message>
+ <message>
+ <source>false</source>
+ <translation>laž</translation>
+ </message>
+</context>
<context>
<name>TransactionDescDialog</name>
<message>
<source>This pane shows a detailed description of the transaction</source>
<translation>Ovaj prozor prikazuje detaljni opis transakcije</translation>
</message>
- </context>
+ <message>
+ <source>Details for %1</source>
+ <translation>Detalji za %1</translation>
+ </message>
+</context>
<context>
<name>TransactionTableModel</name>
<message>
@@ -1415,15 +2792,39 @@
<source>Label</source>
<translation>Oznaka</translation>
</message>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>Otvoren za još %n blok</numerusform><numerusform>Otvoren za još %n bloka</numerusform><numerusform>Otvoren za još %n blokova</numerusform></translation>
+ </message>
<message>
<source>Open until %1</source>
<translation>Otvoren do %1</translation>
</message>
<message>
+ <source>Unconfirmed</source>
+ <translation>Nepotvrđeno</translation>
+ </message>
+ <message>
+ <source>Abandoned</source>
+ <translation>Napušteno</translation>
+ </message>
+ <message>
+ <source>Confirming (%1 of %2 recommended confirmations)</source>
+ <translation>Potvrđuje se (%1 od %2 preporučenih potvrda)</translation>
+ </message>
+ <message>
<source>Confirmed (%1 confirmations)</source>
<translation>Potvrđen (%1 potvrda)</translation>
</message>
<message>
+ <source>Conflicted</source>
+ <translation>Sukobljeno</translation>
+ </message>
+ <message>
+ <source>Immature (%1 confirmations, will be available after %2)</source>
+ <translation>Nezrelo (%1 potvrda/e, bit će dostupno nakon %2)</translation>
+ </message>
+ <message>
<source>Generated but not accepted</source>
<translation>Generirano, ali nije prihvaćeno</translation>
</message>
@@ -1448,6 +2849,10 @@
<translation>Rudareno</translation>
</message>
<message>
+ <source>watch-only</source>
+ <translation>isključivo promatrano</translation>
+ </message>
+ <message>
<source>(n/a)</source>
<translation>(n/d)</translation>
</message>
@@ -1468,6 +2873,14 @@
<translation>Vrsta transakcije.</translation>
</message>
<message>
+ <source>Whether or not a watch-only address is involved in this transaction.</source>
+ <translation>Ovisi je li isključivo promatrana adresa povezana s ovom transakcijom ili ne.</translation>
+ </message>
+ <message>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation>Korisničko definirana namjera transakcije.</translation>
+ </message>
+ <message>
<source>Amount removed from or added to balance.</source>
<translation>Iznos odbijen od ili dodan k saldu.</translation>
</message>
@@ -1523,10 +2936,22 @@
<translation>Ostalo</translation>
</message>
<message>
+ <source>Enter address, transaction id, or label to search</source>
+ <translation>Unesite adresu, ID transakcije ili oznaku za pretragu</translation>
+ </message>
+ <message>
<source>Min amount</source>
<translation>Min iznos</translation>
</message>
<message>
+ <source>Abandon transaction</source>
+ <translation>Napustite transakciju</translation>
+ </message>
+ <message>
+ <source>Increase transaction fee</source>
+ <translation>Povećajte transakcijsku naknadu</translation>
+ </message>
+ <message>
<source>Copy address</source>
<translation>Kopiraj adresu</translation>
</message>
@@ -1543,6 +2968,14 @@
<translation>Kopiraj ID transakcije</translation>
</message>
<message>
+ <source>Copy raw transaction</source>
+ <translation>Kopirajte sirovu transakciju</translation>
+ </message>
+ <message>
+ <source>Copy full transaction details</source>
+ <translation>Kopirajte potpune transakcijske detalje</translation>
+ </message>
+ <message>
<source>Edit label</source>
<translation>Izmjeni oznaku</translation>
</message>
@@ -1551,6 +2984,10 @@
<translation>Prikaži detalje transakcije</translation>
</message>
<message>
+ <source>Export Transaction History</source>
+ <translation>Izvozite povijest transakcija</translation>
+ </message>
+ <message>
<source>Comma separated file (*.csv)</source>
<translation>Datoteka podataka odvojenih zarezima (*.csv)</translation>
</message>
@@ -1559,6 +2996,10 @@
<translation>Potvrđeno</translation>
</message>
<message>
+ <source>Watch-only</source>
+ <translation>Isključivo promatrano</translation>
+ </message>
+ <message>
<source>Date</source>
<translation>Datum</translation>
</message>
@@ -1583,6 +3024,18 @@
<translation>Izvoz neuspješan</translation>
</message>
<message>
+ <source>There was an error trying to save the transaction history to %1.</source>
+ <translation>Nastala je greška pokušavajući snimiti povijest transakcija na %1.</translation>
+ </message>
+ <message>
+ <source>Exporting Successful</source>
+ <translation>Izvoz uspješan</translation>
+ </message>
+ <message>
+ <source>The transaction history was successfully saved to %1.</source>
+ <translation>Povijest transakcija je bila uspješno snimljena na %1.</translation>
+ </message>
+ <message>
<source>Range:</source>
<translation>Raspon:</translation>
</message>
@@ -1593,17 +3046,61 @@
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
- </context>
+ <message>
+ <source>Unit to show amounts in. Click to select another unit.</source>
+ <translation>Jedinica u kojoj ćete prikazati iznose. Kliknite da izabrate drugu jedinicu.</translation>
+ </message>
+</context>
<context>
<name>WalletFrame</name>
- </context>
+ <message>
+ <source>No wallet has been loaded.</source>
+ <translation>Nije pokrenut nikakav novčanik.</translation>
+ </message>
+</context>
<context>
<name>WalletModel</name>
<message>
<source>Send Coins</source>
<translation>Slanje novca</translation>
</message>
- </context>
+ <message>
+ <source>Fee bump error</source>
+ <translation>Greška kod povećanja naknade</translation>
+ </message>
+ <message>
+ <source>Increasing transaction fee failed</source>
+ <translation>Povećavanje transakcijske naknade neuspješno</translation>
+ </message>
+ <message>
+ <source>Do you want to increase the fee?</source>
+ <translation>Želite li povećati naknadu?</translation>
+ </message>
+ <message>
+ <source>Current fee:</source>
+ <translation>Trenutna naknada:</translation>
+ </message>
+ <message>
+ <source>Increase:</source>
+ <translation>Povećanje:</translation>
+ </message>
+ <message>
+ <source>New fee:</source>
+ <translation>Nova naknada:</translation>
+ </message>
+ <message>
+ <source>Confirm fee bump</source>
+ <translation>Potvrdite povećanje naknade</translation>
+ </message>
+ <message>
+ <source>Can't sign transaction.</source>
+ <translation>Transakcija ne može biti potpisana.</translation>
+ </message>
+ <message>
+ <source>Could not commit transaction</source>
+ <translation>Transakcija ne može biti izvršena.</translation>
+ </message>
+</context>
<context>
<name>WalletView</name>
<message>
@@ -1626,30 +3123,522 @@
<source>Backup Failed</source>
<translation>Arhiviranje nije uspjelo</translation>
</message>
- </context>
+ <message>
+ <source>There was an error trying to save the wallet data to %1.</source>
+ <translation>Nastala je greška pokušavajući snimiti podatke novčanika na %1.</translation>
+ </message>
+ <message>
+ <source>Backup Successful</source>
+ <translation>Sigurnosna kopija uspješna</translation>
+ </message>
+ <message>
+ <source>The wallet data was successfully saved to %1.</source>
+ <translation>Podaci novčanika su bili uspješno snimljeni na %1.</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Odustanite</translation>
+ </message>
+</context>
<context>
<name>bitcoin-core</name>
<message>
+ <source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
+ <translation>Distribuirano pod MIT licencom softvera. Vidite pripadajuću datoteku %s ili %s.</translation>
+ </message>
+ <message>
+ <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source>
+ <translation>Obrezivanje postavljeno ispod minimuma od %d MiB. Molim koristite veći broj.</translation>
+ </message>
+ <message>
+ <source>Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)</source>
+ <translation>Obrezivanje: zadnja sinkronizacija novčanika ide dalje od obrezivanih podataka. Morate koristiti -reindex (ponovo preuzeti cijeli lanac blokova u slučaju obrezivanog čvora)</translation>
+ </message>
+ <message>
+ <source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
+ <translation>Ponovno skeniranje nije moguće u obrezanim načinu (pruned mode). Morat ćete koristiti -reindex, što će ponovno preuzeti cijeli lanac blokova.</translation>
+ </message>
+ <message>
+ <source>Error: A fatal internal error occurred, see debug.log for details</source>
+ <translation>Greška: Dogodila se kobna interna greška. Vidite debug.log za detalje</translation>
+ </message>
+ <message>
+ <source>Pruning blockstore...</source>
+ <translation>Obrezuje se blockstore...</translation>
+ </message>
+ <message>
+ <source>Unable to start HTTP server. See debug log for details.</source>
+ <translation>Ne može se pokrenuti HTTP server. Vidite debug.log za više detalja.</translation>
+ </message>
+ <message>
<source>Bitcoin Core</source>
<translation>Bitcoin Core</translation>
</message>
<message>
+ <source>The %s developers</source>
+ <translation>Ekipa %s</translation>
+ </message>
+ <message>
+ <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source>
+ <translation>Program ne može pristupiti podatkovnoj mapi %s. %s je vjerojatno već pokrenut.</translation>
+ </message>
+ <message>
+ <source>Cannot provide specific connections and have addrman find outgoing connections at the same.</source>
+ <translation>Ne može ponuditi specifične veze i dati addrman da traži izlazne veze istovremeno.</translation>
+ </message>
+ <message>
+ <source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source>
+ <translation>Greška kod iščitanja %s! Svi ključevi su ispravno učitani, ali transakcijski podaci ili zapisi u adresaru mogu biti nepotpuni ili netočni.</translation>
+ </message>
+ <message>
+ <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source>
+ <translation>Grupirajte outpute po adresi, birajući sve ili ništa umjesto biranja po outputu. Privatnost je povećana jer je adresa korištena samo jedanput (osim ako netko šalje na tu adresu nakon trošenja iz nje), ali može rezultirati neznatno većim naknadama jer suboptimalno biranje novčića može nastati zbog dodanog ograničenja (uobičajeno: %u)</translation>
+ </message>
+ <message>
+ <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source>
+ <translation>Molimo provjerite jesu li datum i vrijeme na vašem računalu točni. Ako je vaš sat krivo namješten, %s neće raditi ispravno.</translation>
+ </message>
+ <message>
+ <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source>
+ <translation>Molimo vas da doprinijete programu %s ako ga smatrate korisnim. Posjetite %s za više informacija.</translation>
+ </message>
+ <message>
+ <source>The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct</source>
+ <translation>Baza blokova sadrži blok koji je naizgled iz budućnosti. Može to biti posljedica krivo namještenog datuma i vremena na vašem računalu. Obnovite bazu blokova samo ako ste sigurni da su točni datum i vrijeme na vašem računalu.</translation>
+ </message>
+ <message>
+ <source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source>
+ <translation>Ovo je eksperimentalna verzija za testiranje - koristite je na vlastitu odgovornost - ne koristite je za rudarenje ili trgovačke primjene</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you may discard if change is smaller than dust at this level</source>
+ <translation>Ovo je transakcijska naknada koju možete odbaciti ako je ostatak manji od "prašine" (sićušnih iznosa) po ovoj stopi</translation>
+ </message>
+ <message>
+ <source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source>
+ <translation>Ne mogu se ponovo odigrati blokovi. Morat ćete ponovo složiti bazu koristeći -reindex-chainstate.</translation>
+ </message>
+ <message>
+ <source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source>
+ <translation>Baza se ne može povratiti na stanje prije raskola. Morat ćete ponovno preuzeti lanac blokova</translation>
+ </message>
+ <message>
+ <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
+ <translation>Upozorenje: Čini se da se mreža ne slaže u potpunosti! Izgleda da su neki rudari suočeni s poteškoćama.</translation>
+ </message>
+ <message>
+ <source>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source>
+ <translation>Upozorenje: Izgleda da se ne slažemo u potpunosti s našim klijentima! Možda ćete se vi ili ostali čvorovi morati ažurirati.</translation>
+ </message>
+ <message>
+ <source>%d of last 100 blocks have unexpected version</source>
+ <translation>%d od zadnjih 100 blokova ima neočekivanu verziju</translation>
+ </message>
+ <message>
+ <source>%s corrupt, salvage failed</source>
+ <translation>%s pokvaren, spašavanje neuspješno</translation>
+ </message>
+ <message>
+ <source>-maxmempool must be at least %d MB</source>
+ <translation>-maxmempool mora biti barem %d MB</translation>
+ </message>
+ <message>
+ <source>Cannot resolve -%s address: '%s'</source>
+ <translation>Ne može se razriješiti adresa -%s: '%s'</translation>
+ </message>
+ <message>
+ <source>Change index out of range</source>
+ <translation>Indeks ostatka izvan dosega</translation>
+ </message>
+ <message>
+ <source>Copyright (C) %i-%i</source>
+ <translation>Copyright (C) %i-%i</translation>
+ </message>
+ <message>
+ <source>Corrupted block database detected</source>
+ <translation>Pokvarena baza blokova otkrivena</translation>
+ </message>
+ <message>
+ <source>Do you want to rebuild the block database now?</source>
+ <translation>Želite li sada obnoviti bazu blokova?</translation>
+ </message>
+ <message>
+ <source>Error creating %s: You can't create non-HD wallets with this version.</source>
+ <translation>Greška kod stvaranja %s. S ovom verzijom ne možete stvoriti novčanike koji nisu HD.</translation>
+ </message>
+ <message>
+ <source>Error initializing block database</source>
+ <translation>Greška kod inicijaliziranja baze blokova</translation>
+ </message>
+ <message>
+ <source>Error initializing wallet database environment %s!</source>
+ <translation>Greška kod inicijaliziranja okoline baze novčanika %s!</translation>
+ </message>
+ <message>
+ <source>Error loading %s</source>
+ <translation>Greška kod pokretanja programa %s!</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Private keys can only be disabled during creation</source>
+ <translation>Greška kod učitavanja %s: Privatni ključevi mogu biti isključeni samo tijekom stvaranja</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet corrupted</source>
+ <translation>Greška kod učitavanja %s: Novčanik pokvaren</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet requires newer version of %s</source>
+ <translation>Greška kod učitavanja %s: Novčanik zahtijeva noviju verziju softvera %s.</translation>
+ </message>
+ <message>
+ <source>Error loading block database</source>
+ <translation>Greška kod pokretanja baze blokova</translation>
+ </message>
+ <message>
+ <source>Error opening block database</source>
+ <translation>Greška kod otvaranja baze blokova</translation>
+ </message>
+ <message>
<source>Error: Disk space is low!</source>
<translation>Pogreška: Nema dovoljno prostora na disku!</translation>
</message>
<message>
+ <source>Failed to listen on any port. Use -listen=0 if you want this.</source>
+ <translation>Neuspješno slušanje na svim portovima. Koristite -listen=0 ako to želite.</translation>
+ </message>
+ <message>
+ <source>Failed to rescan the wallet during initialization</source>
+ <translation>Neuspješno ponovo skeniranje novčanika tijekom inicijalizacije</translation>
+ </message>
+ <message>
+ <source>Importing...</source>
+ <translation>Uvozi se...</translation>
+ </message>
+ <message>
+ <source>Incorrect or no genesis block found. Wrong datadir for network?</source>
+ <translation>Neispravan ili nepostojeći blok geneze. Možda je kriva podatkovna mapa za mrežu?</translation>
+ </message>
+ <message>
+ <source>Initialization sanity check failed. %s is shutting down.</source>
+ <translation>Brzinska provjera inicijalizacije neuspješna. %s se zatvara.</translation>
+ </message>
+ <message>
+ <source>Invalid amount for -%s=&lt;amount&gt;: '%s'</source>
+ <translation>Neispravan iznos za -%s=&lt;amount&gt;: '%s'</translation>
+ </message>
+ <message>
+ <source>Invalid amount for -discardfee=&lt;amount&gt;: '%s'</source>
+ <translation>Neispravan iznos za -discardfee=&lt;amount&gt;: '%s'</translation>
+ </message>
+ <message>
+ <source>Invalid amount for -fallbackfee=&lt;amount&gt;: '%s'</source>
+ <translation>Neispravan iznos za -fallbackfee=&lt;amount&gt;: '%s'</translation>
+ </message>
+ <message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation>Zadana mapa blokova "%s" ne postoji.</translation>
+ </message>
+ <message>
+ <source>Upgrading txindex database</source>
+ <translation>Ažurira se txindex baza</translation>
+ </message>
+ <message>
+ <source>Loading P2P addresses...</source>
+ <translation>Pokreće se popis P2P adresa...</translation>
+ </message>
+ <message>
+ <source>Loading banlist...</source>
+ <translation>Pokreće se popis zabrana...</translation>
+ </message>
+ <message>
+ <source>Not enough file descriptors available.</source>
+ <translation>Nema dovoljno dostupnih datotečnih opisivača.</translation>
+ </message>
+ <message>
+ <source>Prune cannot be configured with a negative value.</source>
+ <translation>Obrezivanje (prune) ne može biti postavljeno na negativnu vrijednost.</translation>
+ </message>
+ <message>
+ <source>Prune mode is incompatible with -txindex.</source>
+ <translation>Način obreživanja (pruning) nekompatibilan je s parametrom -txindex.</translation>
+ </message>
+ <message>
+ <source>Replaying blocks...</source>
+ <translation>Odigraju se ponovno blokovi...</translation>
+ </message>
+ <message>
+ <source>Rewinding blocks...</source>
+ <translation>Premotavaju se blokovi...</translation>
+ </message>
+ <message>
+ <source>The source code is available from %s.</source>
+ <translation>Izvorni kod je dostupan na %s.</translation>
+ </message>
+ <message>
+ <source>Transaction fee and change calculation failed</source>
+ <translation>Neuspješno računanje ostatka i transakcijske naknade</translation>
+ </message>
+ <message>
+ <source>Unable to bind to %s on this computer. %s is probably already running.</source>
+ <translation>Ne može se povezati na %s na ovom računalu. %s je vjerojatno već pokrenut.</translation>
+ </message>
+ <message>
+ <source>Unable to generate keys</source>
+ <translation>Ne mogu se generirati ključevi</translation>
+ </message>
+ <message>
+ <source>Unsupported argument -benchmark ignored, use -debug=bench.</source>
+ <translation>Nepodržan argument -benchmark ignoriran. Koristite -debug=bench.</translation>
+ </message>
+ <message>
+ <source>Unsupported argument -debugnet ignored, use -debug=net.</source>
+ <translation>Nepodržan argument -debugnet ignoriran. Koristite -debug=net.</translation>
+ </message>
+ <message>
+ <source>Unsupported argument -tor found, use -onion.</source>
+ <translation>Nepodržan argument -tor pronađen. Koristite -onion.</translation>
+ </message>
+ <message>
+ <source>Unsupported logging category %s=%s.</source>
+ <translation>Nepodržana kategorija zapisa %s=%s.</translation>
+ </message>
+ <message>
+ <source>Upgrading UTXO database</source>
+ <translation>Ažurira se UTXO baza</translation>
+ </message>
+ <message>
+ <source>User Agent comment (%s) contains unsafe characters.</source>
+ <translation>Komentar pod "Korisnički agent" (%s) sadrži nesigurne znakove.</translation>
+ </message>
+ <message>
+ <source>Verifying blocks...</source>
+ <translation>Provjeravaju se blokovi...</translation>
+ </message>
+ <message>
+ <source>Wallet needed to be rewritten: restart %s to complete</source>
+ <translation>Novčanik je trebao prepravak: ponovo pokrenite %s</translation>
+ </message>
+ <message>
+ <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
+ <translation>Greška: Neuspješno slušanje dolažećih veza (listen je izbacio grešku %s)</translation>
+ </message>
+ <message>
+ <source>Invalid amount for -maxtxfee=&lt;amount&gt;: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</source>
+ <translation>Neispravan iznos za -maxtxfee=&lt;amount&gt;: '%s' (mora biti barem minimalnu naknadu za proslijeđivanje od %s kako se ne bi zapela transakcija)</translation>
+ </message>
+ <message>
+ <source>The transaction amount is too small to send after the fee has been deducted</source>
+ <translation>Iznos transakcije je premalen za poslati nakon naknade</translation>
+ </message>
+ <message>
+ <source>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source>
+ <translation>Morat ćete ponovno složiti bazu koristeći -reindex kako biste se vratili na neobrezivan način (unpruned mode). Ovo će ponovno preuzeti cijeli lanac blokova.</translation>
+ </message>
+ <message>
+ <source>Error loading %s: You can't disable HD on an already existing HD wallet</source>
+ <translation>Greška kod učitavanja %s: Ne možete isključiti HD na već postojećem HD novčaniku</translation>
+ </message>
+ <message>
+ <source>Error reading from database, shutting down.</source>
+ <translation>Greška kod iščitanja baze. Zatvara se klijent.</translation>
+ </message>
+ <message>
+ <source>Error upgrading chainstate database</source>
+ <translation>Greška kod ažuriranja baze stanja lanca</translation>
+ </message>
+ <message>
<source>Information</source>
<translation>Informacija</translation>
</message>
<message>
+ <source>Invalid -onion address or hostname: '%s'</source>
+ <translation>Neispravna -onion adresa ili ime računala: '%s'</translation>
+ </message>
+ <message>
+ <source>Invalid -proxy address or hostname: '%s'</source>
+ <translation>Neispravna -proxy adresa ili ime računala: '%s'</translation>
+ </message>
+ <message>
+ <source>Invalid amount for -paytxfee=&lt;amount&gt;: '%s' (must be at least %s)</source>
+ <translation>Neispravan iznos za -paytxfee=&lt;amount&gt;: '%s' (mora biti barem %s)</translation>
+ </message>
+ <message>
+ <source>Invalid netmask specified in -whitelist: '%s'</source>
+ <translation>Neispravna mrežna maska zadana u -whitelist: '%s'</translation>
+ </message>
+ <message>
+ <source>Need to specify a port with -whitebind: '%s'</source>
+ <translation>Treba zadati port pomoću -whitebind: '%s'</translation>
+ </message>
+ <message>
+ <source>Reducing -maxconnections from %d to %d, because of system limitations.</source>
+ <translation>Smanjuje se -maxconnections sa %d na %d zbog sustavnih ograničenja.</translation>
+ </message>
+ <message>
+ <source>Signing transaction failed</source>
+ <translation>Potpisivanje transakcije neuspješno</translation>
+ </message>
+ <message>
+ <source>Specified -walletdir "%s" does not exist</source>
+ <translation>Zadan -walletdir "%s" ne postoji</translation>
+ </message>
+ <message>
+ <source>Specified -walletdir "%s" is a relative path</source>
+ <translation>Zadan -walletdir "%s" je relativan put</translation>
+ </message>
+ <message>
+ <source>Specified -walletdir "%s" is not a directory</source>
+ <translation>Zadan -walletdir "%s" nije mapa</translation>
+ </message>
+ <message>
+ <source>The transaction amount is too small to pay the fee</source>
+ <translation>Transakcijiski iznos je premalen da plati naknadu</translation>
+ </message>
+ <message>
+ <source>This is experimental software.</source>
+ <translation>Ovo je eksperimentalni softver.</translation>
+ </message>
+ <message>
+ <source>Transaction amount too small</source>
+ <translation>Transakcijski iznos premalen</translation>
+ </message>
+ <message>
+ <source>Transaction too large for fee policy</source>
+ <translation>Transakcija prevelika za politiku naknada</translation>
+ </message>
+ <message>
+ <source>Transaction too large</source>
+ <translation>Transakcija prevelika</translation>
+ </message>
+ <message>
+ <source>Unable to bind to %s on this computer (bind returned error %s)</source>
+ <translation>Ne može se povezati na %s na ovom računalu. (povezivanje je vratilo grešku %s)</translation>
+ </message>
+ <message>
+ <source>Unable to generate initial keys</source>
+ <translation>Ne mogu se generirati početni ključevi</translation>
+ </message>
+ <message>
+ <source>Verifying wallet(s)...</source>
+ <translation>Provjerava(ju) se novčanik/(ci)...</translation>
+ </message>
+ <message>
+ <source>Wallet %s resides outside wallet directory %s</source>
+ <translation>Novčanik %s nalazi se izvan mape novčanika %s</translation>
+ </message>
+ <message>
<source>Warning</source>
<translation>Upozorenje</translation>
</message>
<message>
+ <source>Warning: unknown new rules activated (versionbit %i)</source>
+ <translation>Upozorenje: nepoznata nova pravila aktivirana (versionbit %i)</translation>
+ </message>
+ <message>
+ <source>Zapping all transactions from wallet...</source>
+ <translation>Brišu se sve transakcije iz novčanika...</translation>
+ </message>
+ <message>
+ <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
+ <translation>-maxtxfee je postavljen preveliko. Naknade ove veličine će biti plaćene na individualnoj transakciji.</translation>
+ </message>
+ <message>
+ <source>Error loading %s: You can't enable HD on an already existing non-HD wallet</source>
+ <translation>Greška kod učitavanja %s: Ne možete uključiti HD na već postojećem novčaniku koji nije HD</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you may pay when fee estimates are not available.</source>
+ <translation>Ovo je transakcijska naknada koju ćete možda platiti kada su nedostupne procjene naknada.</translation>
+ </message>
+ <message>
+ <source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit %s and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
+ <translation>Ovaj proizvod sadrži softver razvijen sa strane OpenSSL Projecta za upotrebu u OpenSSL Toolkitu %s, kriptografski softver koji je napisao Eric Young te UPnP softver koji je napisao Thomas Bernard.</translation>
+ </message>
+ <message>
+ <source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source>
+ <translation>Ukupna duljina stringa verzije mreže (%i) prelazi maksimalnu duljinu (%i). Smanjite broj ili veličinu komentara o korisničkom agentu (uacomments).</translation>
+ </message>
+ <message>
+ <source>Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.</source>
+ <translation>Nepodržan argument -socks pronađen. Postavljanje verziju SOCKS-a nije više moguće. Samo su SOCKS5 proxyji podržani.</translation>
+ </message>
+ <message>
+ <source>Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.</source>
+ <translation>Nepodržan argument -whitelistalwaysrelay ignoriran. Koristite -whitelistelay i/ili -whitelistforcerelay.</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source>
+ <translation>Upozorenje: Zbiva se rudarenje blokova nepoznatih verzija! Moguće je da su nepoznata pravila na snazi</translation>
+ </message>
+ <message>
+ <source>Warning: Wallet file corrupt, data salvaged! Original %s saved as %s in %s; if your balance or transactions are incorrect you should restore from a backup.</source>
+ <translation>Upozorenje: Datoteka novčanika je pokvarena, ali su podaci spašeni! Original %s snimljen je kao %s u %s; ako su transakcije ili stanje neispravni, onda biste trebali restorirati sa sigurnosne kopije (backupa).</translation>
+ </message>
+ <message>
+ <source>%s is set very high!</source>
+ <translation>%s je postavljen preveliko!</translation>
+ </message>
+ <message>
+ <source>Error loading wallet %s. Duplicate -wallet filename specified.</source>
+ <translation>Greška kod učitavanja novčanika %s. Duplikat imena novčanika zadan.</translation>
+ </message>
+ <message>
+ <source>Keypool ran out, please call keypoolrefill first</source>
+ <translation>Ispraznio se bazen ključeva. Molim pozovite keypoolrefill najprije</translation>
+ </message>
+ <message>
+ <source>Starting network threads...</source>
+ <translation>Pokreću se mrežne niti...</translation>
+ </message>
+ <message>
+ <source>The wallet will avoid paying less than the minimum relay fee.</source>
+ <translation>Ovaj novčanik će izbjegavati plaćanje manje od minimalne naknade prijenosa.</translation>
+ </message>
+ <message>
+ <source>This is the minimum transaction fee you pay on every transaction.</source>
+ <translation>Ovo je minimalna transakcijska naknada koju plaćate za svaku transakciju.</translation>
+ </message>
+ <message>
+ <source>This is the transaction fee you will pay if you send a transaction.</source>
+ <translation>Ovo je transakcijska naknada koju ćete platiti ako pošaljete transakciju.</translation>
+ </message>
+ <message>
+ <source>Transaction amounts must not be negative</source>
+ <translation>Iznosi transakcije ne smiju biti negativni</translation>
+ </message>
+ <message>
+ <source>Transaction has too long of a mempool chain</source>
+ <translation>Transakcija ima prevelik lanac memorijskog bazena</translation>
+ </message>
+ <message>
+ <source>Transaction must have at least one recipient</source>
+ <translation>Transakcija mora imati barem jednog primatelja</translation>
+ </message>
+ <message>
+ <source>Unknown network specified in -onlynet: '%s'</source>
+ <translation>Nepoznata mreža zadana kod -onlynet: '%s'</translation>
+ </message>
+ <message>
<source>Insufficient funds</source>
<translation>Nedovoljna sredstva</translation>
</message>
<message>
+ <source>Can't generate a change-address key. Private keys are disabled for this wallet.</source>
+ <translation>Ne može se generirati ključ adrese na koju će se poslati ostatak. Privatni ključevi su isključeni kod ovog novčanika.</translation>
+ </message>
+ <message>
+ <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use -upgradewallet=169900 or -upgradewallet with no version specified.</source>
+ <translation>Ne može se ažurirati novčanik koji nije HD bez ažuriranja radi podrške za bazen ključeva prije raskola. Molim koristite -upgradewallet=169900 ili -upgradewallet bez zadane verzije.</translation>
+ </message>
+ <message>
+ <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
+ <translation>Neuspješno procjenjivanje naknada. Fallbackfee je isključena. Pričekajte nekoliko blokova ili uključite -fallbackfee.</translation>
+ </message>
+ <message>
+ <source>Cannot write to data directory '%s'; check permissions.</source>
+ <translation>Nije moguće pisati u podatkovnu mapu '%s'; provjerite dozvole.</translation>
+ </message>
+ <message>
<source>Loading block index...</source>
<translation>Učitavanje indeksa blokova...</translation>
</message>
diff --git a/src/qt/locale/bitcoin_id.ts b/src/qt/locale/bitcoin_id.ts
new file mode 100644
index 0000000000..1a4c7236d1
--- /dev/null
+++ b/src/qt/locale/bitcoin_id.ts
@@ -0,0 +1,969 @@
+<TS language="id" version="2.1">
+<context>
+ <name>AddressBookPage</name>
+ <message>
+ <source>Right-click to edit address or label</source>
+ <translation>Klik kanan untuk mengubah alamat atau label</translation>
+ </message>
+ <message>
+ <source>Create a new address</source>
+ <translation>Buat sebuah alamat baru</translation>
+ </message>
+ <message>
+ <source>&amp;New</source>
+ <translation>&amp;Baru</translation>
+ </message>
+ <message>
+ <source>Copy the currently selected address to the system clipboard</source>
+ <translation>Salin alamat yang dipilih ke dalam clipboard sistem</translation>
+ </message>
+ <message>
+ <source>&amp;Copy</source>
+ <translation>&amp;Salin</translation>
+ </message>
+ <message>
+ <source>C&amp;lose</source>
+ <translation>&amp;Tutup</translation>
+ </message>
+ <message>
+ <source>Delete the currently selected address from the list</source>
+ <translation>Hapus alamat yang dipilih dari daftar</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation>Masukkan alamat atau label untuk mencari</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Ekspor data dalam tab saat ini ke file</translation>
+ </message>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;Export</translation>
+ </message>
+ <message>
+ <source>&amp;Delete</source>
+ <translation>&amp;Hapus</translation>
+ </message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Pilih alamat untuk mengirim koin kepada</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Pilih alamat untuk menerima koin</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>P&amp;ilih</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Alamat mengirim</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Alamat menerima</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
+ <translation>Ini adalah alamat Bitcoin anda untuk mengirim pembayaran. Selalu periksa jumlah dan alamat penerima sebelum mengirim koin</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source>
+ <translation>Ini adalah alamat Bitcoin anda untuk menerima pembayaran. Disarankan untuk menggunakan alamat penerimaan baru untuk setiap transaksi</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Salin Alamat</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Copy &amp;Label</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Edit</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Export Daftar Alamat</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>File dipisahkan dengan Comma (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Exporting Gagal</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Terjadi kesalahan saat menyimpan daftar alamat %1. Silahkan coba kembali.</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Label</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Alamat</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(tanpa label)</translation>
+ </message>
+</context>
+<context>
+ <name>AskPassphraseDialog</name>
+ <message>
+ <source>Passphrase Dialog</source>
+ <translation>Dialog passphrase</translation>
+ </message>
+ <message>
+ <source>Enter passphrase</source>
+ <translation>Masukan passphrase</translation>
+ </message>
+ <message>
+ <source>New passphrase</source>
+ <translation>Passphrase baru</translation>
+ </message>
+ <message>
+ <source>Repeat new passphrase</source>
+ <translation>Ulangi passphrase baru</translation>
+ </message>
+ <message>
+ <source>Show password</source>
+ <translation>Tampilkan kata sandi</translation>
+ </message>
+ <message>
+ <source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;ten or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
+ <translation>Masukkan passphrase baru ke dompet.&lt;br/&gt;Harap gunakan passphrase dari &lt;b&gt;sepuluh atau lebih karakter acak&lt;/b&gt;, or &lt;b&gt;delapan atau lebih kata&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Enkripsi wallet</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Tindakan ini memerlukan passphrase untuk membuka wallet anda</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Buka wallet</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Tindakan ini memerlukan passphrase untuk mendekripsi wallet anda</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Dekripsi wallet</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Ganti passphrase</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Masukan passphrase lama dan passphrase baru ke wallet</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Konfirmasi proses enkripsi wallet</translation>
+ </message>
+ <message>
+ <source>Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
+ <translation>Peringatan: Jika anda mengenkripsi wallet anda dan lupa/hilang passphrase anda, anda akan ‭&lt;b&gt; KEHILANGAN SEMUA BITCOIN ANDA &lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Apa anda yakin ingin mengenkripsi wallet anda?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Wallet terenkripsi</translation>
+ </message>
+ <message>
+ <source>%1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
+ <translation>%1 akan ditutup sekarang untuk menyelesaikan proses enkripsi. Ingat bahwa mengenkripsi dompet Anda tidak dapat sepenuhnya melindungi bitcoin Anda dari pencurian oleh malware yang menginfeksi komputer Anda.</translation>
+ </message>
+ <message>
+ <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
+ <translation>PENTING: Semua cadangan sebelumnya yang Anda buat dari file dompet Anda harus diganti dengan file dompet terenkripsi yang baru dibuat. Untuk alasan keamanan, cadangan sebelumnya dari file dompet yang tidak terenkripsi akan menjadi tidak berguna segera setelah Anda mulai menggunakan dompet terenkripsi yang baru.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Enkripsi wallet gagal</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Enkripsi wallet gagal karena kesalahan internal. Wallet anda belum terenkripsi</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>Passphrase yang dimasukan tidak cocok.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Gagal membuka wallet</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>Passphrase yang dimasukan untuk dekripsi wallet salah</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Gagal mendekripsi wallet</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>Passphrase wallet berhasil diganti</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Peringatan: Caps Lock key menyala!</translation>
+ </message>
+</context>
+<context>
+ <name>BanTableModel</name>
+ <message>
+ <source>IP/Netmask</source>
+ <translation>IP/Netmask</translation>
+ </message>
+ <message>
+ <source>Banned Until</source>
+ <translation>Dibanned hingga</translation>
+ </message>
+</context>
+<context>
+ <name>BitcoinGUI</name>
+ <message>
+ <source>Sign &amp;message...</source>
+ <translation>&amp;Verifikasi pesan...</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network...</source>
+ <translation>Sedang sinkronisasi dengan jaringan</translation>
+ </message>
+ <message>
+ <source>&amp;Overview</source>
+ <translation>&amp;Overview</translation>
+ </message>
+ <message>
+ <source>Node</source>
+ <translation>Node</translation>
+ </message>
+ <message>
+ <source>Show general overview of wallet</source>
+ <translation>Tampilkan gambaran umum dompet</translation>
+ </message>
+ <message>
+ <source>&amp;Transactions</source>
+ <translation>&amp;Transaksi</translation>
+ </message>
+ <message>
+ <source>Browse transaction history</source>
+ <translation>Telusuri history transaksi</translation>
+ </message>
+ <message>
+ <source>E&amp;xit</source>
+ <translation>&amp;Keluar</translation>
+ </message>
+ <message>
+ <source>Quit application</source>
+ <translation>Tutup aplikasi</translation>
+ </message>
+ <message>
+ <source>&amp;About %1</source>
+ <translation>&amp;Tentang %1</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation>Tunjukan informasi tentang %1</translation>
+ </message>
+ <message>
+ <source>About &amp;Qt</source>
+ <translation>Tentang &amp;Qt</translation>
+ </message>
+ <message>
+ <source>Show information about Qt</source>
+ <translation>Tampilkan informasi tentang Qt</translation>
+ </message>
+ <message>
+ <source>&amp;Options...</source>
+ <translation>&amp;Pilihan...</translation>
+ </message>
+ <message>
+ <source>Modify configuration options for %1</source>
+ <translation>Ubah pilihan konfigurasi untuk %1</translation>
+ </message>
+ <message>
+ <source>&amp;Encrypt Wallet...</source>
+ <translation>&amp;Enkripsi wallet...</translation>
+ </message>
+ <message>
+ <source>&amp;Backup Wallet...</source>
+ <translation>&amp;Backup wallet</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase...</source>
+ <translation>&amp;Ganti Passphrase...</translation>
+ </message>
+ <message>
+ <source>&amp;Sending addresses...</source>
+ <translation>&amp;Mengirim alamat</translation>
+ </message>
+ <message>
+ <source>&amp;Receiving addresses...</source>
+ <translation>&amp;Menerima alamat...</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI...</source>
+ <translation>Buka &amp;URI...</translation>
+ </message>
+ <message>
+ <source>Wallet:</source>
+ <translation>Dompet:</translation>
+ </message>
+ <message>
+ <source>Click to disable network activity.</source>
+ <translation>Klik untuk menonaktifkan aktifitas network</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Aktifitas network tidak aktif</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>Klik untuk mengaktifkan kembali network</translation>
+ </message>
+ <message>
+ <source>Send coins to a Bitcoin address</source>
+ <translation>Kirim koin ke alamat Bitcoin</translation>
+ </message>
+ <message>
+ <source>Backup wallet to another location</source>
+ <translation>Backup wallet ke lokasi lain</translation>
+ </message>
+ <message>
+ <source>Change the passphrase used for wallet encryption</source>
+ <translation>Ganti passphrase yang digunakan untuk enkripsi wallet</translation>
+ </message>
+ <message>
+ <source>&amp;Debug window</source>
+ <translation>&amp;Debug window</translation>
+ </message>
+ <message>
+ <source>Open debugging and diagnostic console</source>
+ <translation>Buka debugging dan diagnostic console</translation>
+ </message>
+ <message>
+ <source>&amp;Verify message...</source>
+ <translation>&amp;Verifikasi pesan...</translation>
+ </message>
+ <message>
+ <source>Bitcoin</source>
+ <translation>Bitcoin</translation>
+ </message>
+ <message>
+ <source>Wallet</source>
+ <translation>Wallet</translation>
+ </message>
+ <message>
+ <source>&amp;Send</source>
+ <translation>&amp;Kirim</translation>
+ </message>
+ <message>
+ <source>&amp;Receive</source>
+ <translation>&amp;Terima</translation>
+ </message>
+ <message>
+ <source>&amp;Show / Hide</source>
+ <translation>&amp;Tampilkan/ Sembunyikan</translation>
+ </message>
+ <message>
+ <source>Show or hide the main Window</source>
+ <translation>Tampilkan atau sembunyikan tampilan utama</translation>
+ </message>
+ <message>
+ <source>Encrypt the private keys that belong to your wallet</source>
+ <translation>Enkripsi private keys wallet anda</translation>
+ </message>
+ <message>
+ <source>Sign messages with your Bitcoin addresses to prove you own them</source>
+ <translation>Tambahkan pesan di alamat Bitcoin untuk membuktikan bahwa anda pemiliknya</translation>
+ </message>
+ <message>
+ <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
+ <translation>Verifikasi pesan untuk memastikan bahwa telah ditanda tangani dengan alamat Bitcoin tertentu</translation>
+ </message>
+ <message>
+ <source>&amp;File</source>
+ <translation>&amp;File</translation>
+ </message>
+ <message>
+ <source>&amp;Settings</source>
+ <translation>&amp;Pengaturan</translation>
+ </message>
+ <message>
+ <source>&amp;Help</source>
+ <translation>&amp;Bantuan</translation>
+ </message>
+ <message>
+ <source>Tabs toolbar</source>
+ <translation>Toolbar Tabs</translation>
+ </message>
+ <message>
+ <source>Show the list of used sending addresses and labels</source>
+ <translation>Tampilkan daftar alamat kirim yg telah digunakan dan label</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Error</translation>
+ </message>
+ <message>
+ <source>Warning</source>
+ <translation>Peringatan</translation>
+ </message>
+ <message>
+ <source>Information</source>
+ <translation>Informasi</translation>
+ </message>
+ <message>
+ <source>Up to date</source>
+ <translation>Terkini</translation>
+ </message>
+ <message>
+ <source>%1 client</source>
+ <translation>%1 client</translation>
+ </message>
+ <message>
+ <source>Connecting to peers...</source>
+ <translation>Menghubungkan ke peers...</translation>
+ </message>
+ <message>
+ <source>Catching up...</source>
+ <translation>Catching up...</translation>
+ </message>
+ <message>
+ <source>Date: %1
+</source>
+ <translation>Tanggal: %1
+</translation>
+ </message>
+ <message>
+ <source>Amount: %1
+</source>
+ <translation>Jumlah: %1
+</translation>
+ </message>
+ <message>
+ <source>Type: %1
+</source>
+ <translation>Tipe: %1
+</translation>
+ </message>
+ <message>
+ <source>Label: %1
+</source>
+ <translation>Label: %1
+</translation>
+ </message>
+ <message>
+ <source>Address: %1
+</source>
+ <translation>Alamat: %1
+</translation>
+ </message>
+ <message>
+ <source>Sent transaction</source>
+ <translation>Transaksi terkirim</translation>
+ </message>
+ <message>
+ <source>Incoming transaction</source>
+ <translation>Transaksi datang</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation>Pembuatan kunci HD &lt;b&gt;diaktifkan&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation>Pembuatan kunci HD &lt;b&gt;dinonaktifkan&lt;/b&gt;</translation>
+ </message>
+ </context>
+<context>
+ <name>CoinControlDialog</name>
+ <message>
+ <source>Coin Selection</source>
+ <translation>Pemilihan koin</translation>
+ </message>
+ <message>
+ <source>Quantity:</source>
+ <translation>Jumlah:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation>Bytes:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation>Jumlah:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation>Biaya:</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation>Dust:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation>Setelah biaya:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation>Ganti:</translation>
+ </message>
+ <message>
+ <source>(un)select all</source>
+ <translation>(tidak)pilih semua</translation>
+ </message>
+ <message>
+ <source>Tree mode</source>
+ <translation>Mode pohon</translation>
+ </message>
+ <message>
+ <source>List mode</source>
+ <translation>Mode list</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Jumlah</translation>
+ </message>
+ <message>
+ <source>Received with label</source>
+ <translation>Diterima dengan label</translation>
+ </message>
+ <message>
+ <source>Received with address</source>
+ <translation>Diterima dengan alamat</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Tanggal</translation>
+ </message>
+ <message>
+ <source>Confirmations</source>
+ <translation>Konfirmasi</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Telah dikonfirmasi</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Salin alamat</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Salin label</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Salin jumla</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Salin ID transaksi</translation>
+ </message>
+ <message>
+ <source>Lock unspent</source>
+ <translation>Kunci yang tidak digunakan</translation>
+ </message>
+ <message>
+ <source>Unlock unspent</source>
+ <translation>Buka kunci yang tidak digunakan</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Salin jumlah</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Salin biaya</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Salin setelah biaya</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>salin bytes</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Salin dust</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Salin perubahan</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 terkunci)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>Ya</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>Tidak</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(tanpa label)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(ganti)</translation>
+ </message>
+</context>
+<context>
+ <name>EditAddressDialog</name>
+ <message>
+ <source>Edit Address</source>
+ <translation>Ubah Alamat</translation>
+ </message>
+ <message>
+ <source>&amp;Label</source>
+ <translation>&amp;Label</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Alamat pengirim baru</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Ubah alamat penerima</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Ubah alamat pengieim</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Tidak bisa membuka wallet</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Pembuatan kunci baru gagal.</translation>
+ </message>
+</context>
+<context>
+ <name>FreespaceChecker</name>
+ <message>
+ <source>name</source>
+ <translation>nama</translation>
+ </message>
+ </context>
+<context>
+ <name>HelpMessageDialog</name>
+ <message>
+ <source>version</source>
+ <translation>versi</translation>
+ </message>
+ <message>
+ <source>(%1-bit)</source>
+ <translation>(%1-bit)</translation>
+ </message>
+ <message>
+ <source>About %1</source>
+ <translation>Tentang %1</translation>
+ </message>
+ </context>
+<context>
+ <name>Intro</name>
+ <message>
+ <source>Bitcoin</source>
+ <translation>Bitcoin</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Error</translation>
+ </message>
+ </context>
+<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
+ <name>OpenURIDialog</name>
+ </context>
+<context>
+ <name>OptionsDialog</name>
+ <message>
+ <source>Error</source>
+ <translation>Error</translation>
+ </message>
+ </context>
+<context>
+ <name>OverviewPage</name>
+ </context>
+<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
+ <name>PeerTableModel</name>
+ </context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>Amount</source>
+ <translation>Jumlah</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
+ <name>RPCConsole</name>
+ </context>
+<context>
+ <name>ReceiveCoinsDialog</name>
+ <message>
+ <source>Copy label</source>
+ <translation>Salin label</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Salin jumla</translation>
+ </message>
+</context>
+<context>
+ <name>ReceiveRequestDialog</name>
+ <message>
+ <source>Address</source>
+ <translation>Alamat</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Jumlah</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Label</translation>
+ </message>
+ <message>
+ <source>Wallet</source>
+ <translation>Wallet</translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Tanggal</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Label</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(tanpa label)</translation>
+ </message>
+ </context>
+<context>
+ <name>SendCoinsDialog</name>
+ <message>
+ <source>Quantity:</source>
+ <translation>Jumlah:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation>Bytes:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation>Jumlah:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation>Biaya:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation>Setelah biaya:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation>Ganti:</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation>Dust:</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Salin jumlah</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Salin jumla</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Salin setelah biaya</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>salin bytes</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Salin dust</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Salin perubahan</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(tanpa label)</translation>
+ </message>
+</context>
+<context>
+ <name>SendCoinsEntry</name>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
+ <name>ShutdownWindow</name>
+ </context>
+<context>
+ <name>SignVerifyMessageDialog</name>
+ </context>
+<context>
+ <name>SplashScreen</name>
+ </context>
+<context>
+ <name>TrafficGraphWidget</name>
+ </context>
+<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Date</source>
+ <translation>Tanggal</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Jumlah</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionDescDialog</name>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Tanggal</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Label</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(tanpa label)</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Copy address</source>
+ <translation>Salin alamat</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Salin label</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Salin jumla</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Salin ID transaksi</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>File dipisahkan dengan Comma (*.csv)</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Telah dikonfirmasi</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Tanggal</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Label</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Alamat</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Exporting gagal</translation>
+ </message>
+ </context>
+<context>
+ <name>UnitDisplayStatusBarControl</name>
+ </context>
+<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;Export</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Ekspor data dalam tab saat ini ke file</translation>
+ </message>
+ </context>
+<context>
+ <name>bitcoin-core</name>
+ <message>
+ <source>Information</source>
+ <translation>Informasi</translation>
+ </message>
+ <message>
+ <source>Warning</source>
+ <translation>Peringatan</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Error</translation>
+ </message>
+</context>
+</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_id_ID.ts b/src/qt/locale/bitcoin_id_ID.ts
index 3c79d54e94..a487936fd2 100644
--- a/src/qt/locale/bitcoin_id_ID.ts
+++ b/src/qt/locale/bitcoin_id_ID.ts
@@ -326,6 +326,14 @@
<translation>Buka &amp;URI</translation>
</message>
<message>
+ <source>Wallet:</source>
+ <translation>Wallet:</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation>wallet default</translation>
+ </message>
+ <message>
<source>Click to disable network activity.</source>
<translation>Klik untuk menonaktifkan aktivitas jaringan.</translation>
</message>
@@ -346,6 +354,10 @@
<translation>Mengindex ulang blok di dalam disk...</translation>
</message>
<message>
+ <source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
+ <translation>Proxy di &lt;b&gt;aktifkan&lt;/b&gt;: %1</translation>
+ </message>
+ <message>
<source>Send coins to a Bitcoin address</source>
<translation>Kirim koin ke alamat Bitcoin</translation>
</message>
@@ -514,6 +526,12 @@
</translation>
</message>
<message>
+ <source>Wallet: %1
+</source>
+ <translation>Wallet: %1
+</translation>
+ </message>
+ <message>
<source>Type: %1
</source>
<translation>Tipe: %1
@@ -698,7 +716,15 @@
<source>(no label)</source>
<translation>(tidak ada label)</translation>
</message>
- </context>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>kembalian dari %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(kembalian)</translation>
+ </message>
+</context>
<context>
<name>EditAddressDialog</name>
<message>
@@ -738,6 +764,14 @@
<translation>Alamat yang dimasukkan "%1" bukanlah alamat Bitcoin yang valid.</translation>
</message>
<message>
+ <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source>
+ <translation>Alamat "%1" sudah ada sebagai alamat penerimaan dengan label "%2" sehingga tidak bisa ditambah sebagai alamat pengiriman.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book with label "%2".</source>
+ <translation>Alamat "%1" yang dimasukkan sudah ada di dalam buku alamat dengan label "%2".</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation>Tidak dapat membuka dompet.</translation>
</message>
@@ -870,6 +904,10 @@
<translation>Transaksi-transaksi terkini mungkin belum terlihat dan oleh karenanya, saldo dompet Anda mungkin tidak tepat. Informasi ini akan akurat ketika dompet Anda tersinkronisasi dengan jaringan Bitcoin, seperti rincian berikut.</translation>
</message>
<message>
+ <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source>
+ <translation>Usaha untuk menggunakan bitcoin yang dipengaruhi oleh transaksi yang belum terlihat tidak akan diterima oleh jaringan.</translation>
+ </message>
+ <message>
<source>Number of blocks left</source>
<translation>Jumlah blok tersisa</translation>
</message>
@@ -882,6 +920,14 @@
<translation>Waktu blok terakhir</translation>
</message>
<message>
+ <source>Progress</source>
+ <translation>Perkembangan</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation>Peningkatan perkembangan per jam</translation>
+ </message>
+ <message>
<source>calculating...</source>
<translation>menghitung...</translation>
</message>
@@ -916,7 +962,11 @@
<source>Select payment request file</source>
<translation>Pilih data permintaan pembayaran</translation>
</message>
- </context>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>Pilih data permintaan pembayaran yang akan dibuka</translation>
+ </message>
+</context>
<context>
<name>OptionsDialog</name>
<message>
@@ -952,10 +1002,22 @@
<translation>Alamat IP proxy (cth. IPv4: 127.0.0.1 / IPv6: ::1)</translation>
</message>
<message>
+ <source>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source>
+ <translation>Perlihatkan apabila proxy SOCKS5 default digunakan untuk berhungan dengan orang lain lewat tipe jaringan ini.</translation>
+ </message>
+ <message>
+ <source>Use separate SOCKS&amp;5 proxy to reach peers via Tor hidden services:</source>
+ <translation>Menggunakan proxy SOCKS5 tersendiri untuk berhubungan dengan orang lain melalui layanan Tor:</translation>
+ </message>
+ <message>
<source>Hide the icon from the system tray.</source>
<translation>Sembunyikan ikon dari system tray.</translation>
</message>
<message>
+ <source>&amp;Hide tray icon</source>
+ <translation>&amp;Sembunyikan ikon tray</translation>
+ </message>
+ <message>
<source>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source>
<translation>Minimalisasi aplikasi ketika jendela ditutup. Ketika pilihan ini dipilih, aplikasi akan menutup seluruhnya jika anda memilih Keluar di menu yang tersedia.</translation>
</message>
@@ -968,6 +1030,10 @@
<translation>Pilihan command-line yang aktif menimpa diatas opsi: </translation>
</message>
<message>
+ <source>Open the %1 configuration file from the working directory.</source>
+ <translation>Buka file konfigurasi %1 dari direktori kerja.</translation>
+ </message>
+ <message>
<source>Open Configuration File</source>
<translation>Buka Berkas Konfigurasi</translation>
</message>
@@ -984,6 +1050,18 @@
<translation>&amp;Jaringan</translation>
</message>
<message>
+ <source>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</source>
+ <translation>Menonaktifkan beberapa fitur canggih akan tetapi semua block akan tetap divalidasi seutuhnya. Mengembalikan pengaturan ini memerlukan untuk mengunduh seluruh blockchain. Penggunaan disk mungkin akan lebih tinggi.</translation>
+ </message>
+ <message>
+ <source>GB</source>
+ <translation>GB</translation>
+ </message>
+ <message>
+ <source>Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation>Mengembalikan pengaturan ini membutuhkan pengunduhan seluruh blockchain lagi. </translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation>(0 = auto, &lt;0 = leave that many cores free)</translation>
</message>
@@ -1028,6 +1106,10 @@
<translation>Hubungkan ke jaringan Bitcoin melalui SOCKS5 proxy.</translation>
</message>
<message>
+ <source>&amp;Connect through SOCKS5 proxy (default proxy):</source>
+ <translation>&amp;Hubungkan melalui proxy SOCKS5 (proxy default):</translation>
+ </message>
+ <message>
<source>Proxy &amp;IP:</source>
<translation>IP Proxy:</translation>
</message>
@@ -1040,6 +1122,10 @@
<translation>Port proxy (cth. 9050)</translation>
</message>
<message>
+ <source>Used for reaching peers via:</source>
+ <translation>Digunakan untuk berhubungan dengan peers melalui:</translation>
+ </message>
+ <message>
<source>IPv4</source>
<translation>IPv4</translation>
</message>
@@ -1052,6 +1138,10 @@
<translation>Tor</translation>
</message>
<message>
+ <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source>
+ <translation>Koneksi ke jaringan bitcoin melalui proxy SOCKS5 yang berbeda untuk layanan Tor tersembunyi.</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation>&amp;Jendela</translation>
</message>
@@ -1092,6 +1182,10 @@
<translation>Ingin menunjukkan cara pengaturan koin atau tidak.</translation>
</message>
<message>
+ <source>&amp;Third party transaction URLs</source>
+ <translation>&amp;URL transaksi pihak ketiga</translation>
+ </message>
+ <message>
<source>&amp;OK</source>
<translation>&amp;YA</translation>
</message>
@@ -1120,6 +1214,14 @@
<translation>Klien akan dimatikan, apakah anda hendak melanjutkan?</translation>
</message>
<message>
+ <source>Configuration options</source>
+ <translation>Konfigurasi pengaturan</translation>
+ </message>
+ <message>
+ <source>The configuration file is used to specify advanced user options which override GUI settings. Additionally, any command-line options will override this configuration file.</source>
+ <translation>File konfigurasi digunakan untuk menspesifikkan pilihan khusus pengguna yang akan menimpa pengaturan GUI. Sebagai tambahan, pengaturan command-line apapun akan menimpa file konfigurasi itu.</translation>
+ </message>
+ <message>
<source>Error</source>
<translation>Terjadi sebuah kesalahan</translation>
</message>
@@ -1147,6 +1249,10 @@
<translation>Informasi terlampir mungkin sudah kedaluwarsa. Dompet Anda secara otomatis mensinkronisasi dengan jaringan Bitcoin ketika sebuah hubungan terbentuk, namun proses ini belum selesai.</translation>
</message>
<message>
+ <source>Watch-only:</source>
+ <translation>Hanya lihat:</translation>
+ </message>
+ <message>
<source>Available:</source>
<translation>Tersedia:</translation>
</message>
@@ -1183,16 +1289,76 @@
<translation>Jumlah saldo Anda sekarang</translation>
</message>
<message>
+ <source>Your current balance in watch-only addresses</source>
+ <translation>Saldomu di alamat hanya lihat</translation>
+ </message>
+ <message>
+ <source>Spendable:</source>
+ <translation>Bisa digunakan:</translation>
+ </message>
+ <message>
<source>Recent transactions</source>
<translation>Transaksi-transaksi terkini</translation>
</message>
- </context>
+ <message>
+ <source>Unconfirmed transactions to watch-only addresses</source>
+ <translation>Transaksi yang belum terkonfirmasi ke alamat hanya lihat</translation>
+ </message>
+ <message>
+ <source>Mined balance in watch-only addresses that has not yet matured</source>
+ <translation>Saldo hasil mining di alamat hanya lihat yang belum bisa digunakan</translation>
+ </message>
+ <message>
+ <source>Current total balance in watch-only addresses</source>
+ <translation>Jumlah saldo di alamat hanya lihat</translation>
+ </message>
+</context>
<context>
<name>PaymentServer</name>
<message>
<source>Payment request error</source>
<translation>Terjadi kesalahan pada permintaan pembayaran</translation>
</message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>Tidak bisa memulai bitcoin: handler click-to-pay</translation>
+ </message>
+ <message>
+ <source>URI handling</source>
+ <translation>Pengelolaan URI</translation>
+ </message>
+ <message>
+ <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source>
+ <translation>'bitcoin://' bukanlah alamat URI yang valid. Silakan gunakan 'bitcoin:'.</translation>
+ </message>
+ <message>
+ <source>Payment request fetch URL is invalid: %1</source>
+ <translation>URL permintaan pembayaran tidak valid: %1</translation>
+ </message>
+ <message>
+ <source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
+ <translation>URI tidak bisa dimengerti! Hal ini bisa disebabkan karena alamat Bitcoin yang tidak sah atau parameter URI yang tidak tepat.</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</source>
+ <translation>Pengelolaan file permintaan pembayaran</translation>
+ </message>
+ <message>
+ <source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source>
+ <translation>File permintaan pembayaran tidak bisa dibaca! Hal ini bisa disebabkan karena file permintaan pembayaran tidak valid.</translation>
+ </message>
+ <message>
+ <source>Payment request rejected</source>
+ <translation>Permintaan pembayaran ditolak</translation>
+ </message>
+ <message>
+ <source>Payment request network doesn't match client network.</source>
+ <translation>Jaringan permintaan pembayaran tidak sesuai dengan jaringan klien.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Permintaan pembayaran telah kadaluarsa.</translation>
+ </message>
</context>
<context>
<name>PeerTableModel</name>
@@ -1375,6 +1541,10 @@
<translation>1 &amp;tahun</translation>
</message>
<message>
+ <source>default wallet</source>
+ <translation>wallet default</translation>
+ </message>
+ <message>
<source>Yes</source>
<translation>Ya</translation>
</message>
@@ -1631,6 +1801,10 @@
<translation>Biaya Transaksi</translation>
</message>
<message>
+ <source>Payment request expired.</source>
+ <translation>Permintaan pembayaran telah kadaluarsa.</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(tidak ada label)</translation>
</message>
diff --git a/src/qt/locale/bitcoin_is.ts b/src/qt/locale/bitcoin_is.ts
new file mode 100644
index 0000000000..6a4e26ac22
--- /dev/null
+++ b/src/qt/locale/bitcoin_is.ts
@@ -0,0 +1,997 @@
+<TS language="is" version="2.1">
+<context>
+ <name>AddressBookPage</name>
+ <message>
+ <source>Right-click to edit address or label</source>
+ <translation>Smelltu á hægri músatakka til að breyta færslugildi eða merkingu</translation>
+ </message>
+ <message>
+ <source>Create a new address</source>
+ <translation>Búa til nýtt færslugildi</translation>
+ </message>
+ <message>
+ <source>&amp;New</source>
+ <translation>&amp;Nýtt</translation>
+ </message>
+ <message>
+ <source>Copy the currently selected address to the system clipboard</source>
+ <translation>Afrita valið færslugildi í klemmuspjald</translation>
+ </message>
+ <message>
+ <source>&amp;Copy</source>
+ <translation>&amp;Afrita</translation>
+ </message>
+ <message>
+ <source>C&amp;lose</source>
+ <translation>&amp;Loka</translation>
+ </message>
+ <message>
+ <source>Delete the currently selected address from the list</source>
+ <translation>Eyða völdu færslugildi úr listanum</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Flytja gögn í flipanum í skrá</translation>
+ </message>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;Flytja út</translation>
+ </message>
+ <message>
+ <source>&amp;Delete</source>
+ <translation>&amp;Eyða</translation>
+ </message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Veldu færslugildi sem greiða skal til</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Veldu færslugildi sem á að taka við mynt</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>&amp;Veldu</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Færslugildi sem senda frá sér</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Færslugildi sem þiggja til sín</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
+ <translation>Þetta eru Bitcoin færslugildin sem senda greiðslur. Skoðið ævinlega vel upphæðina og færslugildin sem þiggja greiðslur áður en mynt er send.</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source>
+ <translation>Þetta eru Bitcoin færslugildin sem þiggja greiðslur. Mælt er með að nota aldrei sama færslugildið til að þiggja fleiri en eina greiðslu.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Afrita færslugildi</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Afrita og &amp;Merkja</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Breyta</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Flytja út færslulista</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Gildi aðskilin með kommu (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Útflutningur tókst ekki</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Ekki tókst að vista færslugildalistann á %1. Reyndu aftur.</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Merking</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Færslugildi</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(engin merking)</translation>
+ </message>
+</context>
+<context>
+ <name>AskPassphraseDialog</name>
+ <message>
+ <source>Passphrase Dialog</source>
+ <translation>Lykilsetning</translation>
+ </message>
+ <message>
+ <source>Enter passphrase</source>
+ <translation>Skráðu lykilsetningu</translation>
+ </message>
+ <message>
+ <source>New passphrase</source>
+ <translation>Ný lykilsetning</translation>
+ </message>
+ <message>
+ <source>Repeat new passphrase</source>
+ <translation>Endurtaktu nýja lykilsetningu</translation>
+ </message>
+ <message>
+ <source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;ten or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
+ <translation>Skráðu nýju lykilsetninguna í veskið. &lt;br/&gt;Vinsamlegast notaðu lykilsetningu með &lt;b&gt;tíu eða fleiri slembibókstöfum&lt;/b&gt;, eða &lt;b&gt;átta eða fleiri orðum&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Dulkóða veski</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Þessi aðgerð þarf að fá lykilsetninguna þína til að opna veskið.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Opna veskið</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Þessi aðgerð þarf lykilsetninguna þína til að dulráða veskið.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Dulráða veskið</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Breyta lykilsetningu</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Skráðu gömlu lykilsetninguna og þá nýju í veskið.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Staðfesta dulkóðun veskis</translation>
+ </message>
+ <message>
+ <source>Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
+ <translation>Viðvörun: Ef þú dulkóðar veskið og týnir lykilsetningunn þá munt þú &lt;b&gt;TAPA ALLRI ÞINNI BITCOIN MYNT&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Ertu viss um að þú viljir dulkóða veskið þitt?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Veski dulkóðað</translation>
+ </message>
+ <message>
+ <source>%1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
+ <translation>%1 lokast núna til að dulkóðun klárist. Mundu að dulkóðun veskis kemur ekki að fullu í veg fyrir að mynt verði stolið úr tölvunni þinni með aðstoð smitforrita. </translation>
+ </message>
+ <message>
+ <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
+ <translation>MIKILVÆGT: Nýja dulkóðaða veskisskráin þarf að koma í staðinn fyrir öll fyrri afrit sem þú hefur gert af upprunalegu veskisskránni. Af öryggisástæðum munu öll fyrri afrit af ódulkóðaða veskinu verða óvirk um leið og þú byrjar að nota nýja, dulkóðaða veskið.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Dulkóðun veskis mistókst</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Dulkóðun veskis mistóks vegna innri villu. Veskið þitt var ekki dulkóðað.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>Lykilsetningarnar eru ekki þær sömu.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Ekki tókst að opna veskið</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>Lykilsetningin sem notuð var til að dulráða veskið var ekki rétt.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Ekki tókst að dulráða veski</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>Það tókst að breyta lykilsetningu veskis.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Viðvörun: Kveikt er á HÁSTÖFUM!</translation>
+ </message>
+</context>
+<context>
+ <name>BanTableModel</name>
+ <message>
+ <source>IP/Netmask</source>
+ <translation>IP/Netgríma</translation>
+ </message>
+ <message>
+ <source>Banned Until</source>
+ <translation>Bannað til</translation>
+ </message>
+</context>
+<context>
+ <name>BitcoinGUI</name>
+ <message>
+ <source>Sign &amp;message...</source>
+ <translation>Undirrita &amp;skilaboð</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network...</source>
+ <translation>Samstilli við netið...</translation>
+ </message>
+ <message>
+ <source>&amp;Overview</source>
+ <translation>&amp;Yfirlit</translation>
+ </message>
+ <message>
+ <source>Node</source>
+ <translation>Hnútur</translation>
+ </message>
+ <message>
+ <source>Show general overview of wallet</source>
+ <translation>Sýna almennt yfirlit af veski</translation>
+ </message>
+ <message>
+ <source>&amp;Transactions</source>
+ <translation>&amp;Færslur</translation>
+ </message>
+ <message>
+ <source>Browse transaction history</source>
+ <translation>Skoða færslusögu</translation>
+ </message>
+ <message>
+ <source>E&amp;xit</source>
+ <translation>&amp;Hætta</translation>
+ </message>
+ <message>
+ <source>Quit application</source>
+ <translation>Hætta í forriti</translation>
+ </message>
+ <message>
+ <source>&amp;About %1</source>
+ <translation>&amp;Um %1</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation>Sýna upplýsingar um %1</translation>
+ </message>
+ <message>
+ <source>About &amp;Qt</source>
+ <translation>Um &amp;Qt</translation>
+ </message>
+ <message>
+ <source>Show information about Qt</source>
+ <translation>Sýna upplýsingar um Qt</translation>
+ </message>
+ <message>
+ <source>&amp;Options...</source>
+ <translation>&amp;Valkostir...</translation>
+ </message>
+ <message>
+ <source>Modify configuration options for %1</source>
+ <translation>Breyta samstillingum fyrir %1</translation>
+ </message>
+ <message>
+ <source>&amp;Encrypt Wallet...</source>
+ <translation>&amp;Dulkóða veski...</translation>
+ </message>
+ <message>
+ <source>&amp;Backup Wallet...</source>
+ <translation>&amp;Öryggisafrit á veski...</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase...</source>
+ <translation>&amp;Breyta lykilsetningu</translation>
+ </message>
+ <message>
+ <source>&amp;Sending addresses...</source>
+ <translation>&amp;Sendi færslugildi...</translation>
+ </message>
+ <message>
+ <source>&amp;Receiving addresses...</source>
+ <translation>&amp;Tek við færslugildum...</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI...</source>
+ <translation>Opna &amp;URL...</translation>
+ </message>
+ <message>
+ <source>Click to disable network activity.</source>
+ <translation>Smelltu til að loka fyrir netumferð.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Slökkt á netumferð.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>Smelltu til að hefja aftur netumferð.</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Samstilli hausa (%1%)...</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk...</source>
+ <translation>Endurraða blokkum á drifi...</translation>
+ </message>
+ <message>
+ <source>Send coins to a Bitcoin address</source>
+ <translation>Senda mynt í Bitcoin færslugildi</translation>
+ </message>
+ <message>
+ <source>Backup wallet to another location</source>
+ <translation>Öryggisafrita veski á annan stað</translation>
+ </message>
+ <message>
+ <source>Change the passphrase used for wallet encryption</source>
+ <translation>Breyta lykilsetningunni sem gildir um dulkóðun veskis</translation>
+ </message>
+ <message>
+ <source>&amp;Debug window</source>
+ <translation>&amp;Kembunargluggi</translation>
+ </message>
+ <message>
+ <source>Open debugging and diagnostic console</source>
+ <translation>Opna kembunar- og greiningarstjórnborð</translation>
+ </message>
+ <message>
+ <source>&amp;Verify message...</source>
+ <translation>&amp;Yfirfara skilaboð...</translation>
+ </message>
+ <message>
+ <source>Bitcoin</source>
+ <translation>Bitcoin</translation>
+ </message>
+ <message>
+ <source>Wallet</source>
+ <translation>Veski</translation>
+ </message>
+ <message>
+ <source>&amp;Send</source>
+ <translation>&amp;Senda</translation>
+ </message>
+ <message>
+ <source>&amp;Receive</source>
+ <translation>&amp;Taka við</translation>
+ </message>
+ <message>
+ <source>&amp;Show / Hide</source>
+ <translation>&amp;Sýna / Fela</translation>
+ </message>
+ <message>
+ <source>Show or hide the main Window</source>
+ <translation>Sýna eða fela megin glugga</translation>
+ </message>
+ <message>
+ <source>Encrypt the private keys that belong to your wallet</source>
+ <translation>Dulkóða einkalyklana sem tilheyra veskinu þínu</translation>
+ </message>
+ <message>
+ <source>Sign messages with your Bitcoin addresses to prove you own them</source>
+ <translation>Kvitta undir skilaboð með Bitcoin færslugildunum þínum til að sanna að þú eigir þau</translation>
+ </message>
+ <message>
+ <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
+ <translation>Yfirfara skilaboð til að tryggja að kvittað hafi verið fyrir þau með tilteknum Bitcoin færslugildum</translation>
+ </message>
+ <message>
+ <source>&amp;File</source>
+ <translation>&amp;Skrá</translation>
+ </message>
+ <message>
+ <source>&amp;Settings</source>
+ <translation>&amp;Stillingar</translation>
+ </message>
+ <message>
+ <source>&amp;Help</source>
+ <translation>&amp;Hjálp</translation>
+ </message>
+ <message>
+ <source>Tabs toolbar</source>
+ <translation>Tólaborð flipa</translation>
+ </message>
+ <message>
+ <source>Request payments (generates QR codes and bitcoin: URIs)</source>
+ <translation>Óska eftir greiðslum (býr til QR kóða og bitcoin: URI)</translation>
+ </message>
+ <message>
+ <source>Show the list of used sending addresses and labels</source>
+ <translation>Sýna lista yfir færslugildi sem notuð hafa verið til sendingar og merkingar þeirra</translation>
+ </message>
+ <message>
+ <source>Show the list of used receiving addresses and labels</source>
+ <translation>Sýna færslugildi sem notuð hafa verið til að taka við mynt og merkingar þeirra</translation>
+ </message>
+ <message>
+ <source>Open a bitcoin: URI or payment request</source>
+ <translation>Opna bitcoin: URI eða greiðslubeiðni</translation>
+ </message>
+ <message>
+ <source>Indexing blocks on disk...</source>
+ <translation>Raða blokkum á drifi</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk...</source>
+ <translation>Vinn úr blokkum á drifi...</translation>
+ </message>
+ <message>
+ <source>%1 behind</source>
+ <translation>%1 á eftir</translation>
+ </message>
+ <message>
+ <source>Last received block was generated %1 ago.</source>
+ <translation>Síðasta viðtekna blokk var búin til fyrir %1 síðan.</translation>
+ </message>
+ <message>
+ <source>Transactions after this will not yet be visible.</source>
+ <translation>Færslur á eftir þessari munu ekki sjást.</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Villa</translation>
+ </message>
+ <message>
+ <source>Warning</source>
+ <translation>Viðvörun</translation>
+ </message>
+ <message>
+ <source>Information</source>
+ <translation>Upplýsingar</translation>
+ </message>
+ <message>
+ <source>Up to date</source>
+ <translation>Uppfært</translation>
+ </message>
+ <message>
+ <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <translation>Sýna %1 hjálparskilaboðin til að fá lista yfir valkosti Bitcoin aðgerðir í skipanalínu</translation>
+ </message>
+ <message>
+ <source>%1 client</source>
+ <translation>%1 biðlarar</translation>
+ </message>
+ <message>
+ <source>Connecting to peers...</source>
+ <translation>Tengist jafningjum...</translation>
+ </message>
+ <message>
+ <source>Catching up...</source>
+ <translation>Færist nær...</translation>
+ </message>
+ <message>
+ <source>Date: %1
+</source>
+ <translation>Dagsetning: %1
+</translation>
+ </message>
+ <message>
+ <source>Amount: %1
+</source>
+ <translation>Upphæð: %1
+</translation>
+ </message>
+ <message>
+ <source>Type: %1
+</source>
+ <translation>Tegund: %1
+</translation>
+ </message>
+ <message>
+ <source>Label: %1
+</source>
+ <translation>Merki: %1
+</translation>
+ </message>
+ <message>
+ <source>Address: %1
+</source>
+ <translation>Færslugildi: %1
+</translation>
+ </message>
+ <message>
+ <source>Sent transaction</source>
+ <translation>Send færsla</translation>
+ </message>
+ <message>
+ <source>Incoming transaction</source>
+ <translation>Móttökufærsla</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation>HD lyklagerð er &lt;b&gt;virkjuð&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation>HD lyklagerð er &lt;b&gt;óvirk&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
+ <translation>Veskið er &lt;b&gt;dulkóðað&lt;/b&gt; og núna &lt;b&gt;ólæst&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
+ <translation>Veskið er &lt;b&gt;dulkóðað&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>Alvarleg villa átti sér stað. Bitcoin getur ekki haldið áfram með öruggum hætti og stoppar hér.</translation>
+ </message>
+</context>
+<context>
+ <name>CoinControlDialog</name>
+ <message>
+ <source>Coin Selection</source>
+ <translation>Myntval</translation>
+ </message>
+ <message>
+ <source>Quantity:</source>
+ <translation>Magn:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation>Bæti:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation>Upphæð:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation>Gjald:</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation>Ryk:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation>Eftirgjald:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation>Skiptimynt:</translation>
+ </message>
+ <message>
+ <source>(un)select all</source>
+ <translation>(af)velja allt</translation>
+ </message>
+ <message>
+ <source>Tree mode</source>
+ <translation>Hrísluhamur</translation>
+ </message>
+ <message>
+ <source>List mode</source>
+ <translation>Listahamur</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Upphæð</translation>
+ </message>
+ <message>
+ <source>Received with label</source>
+ <translation>Móttekið með merkingu</translation>
+ </message>
+ <message>
+ <source>Received with address</source>
+ <translation>Móttekið með færslugildi</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Afrita færslugildi</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Afrita merki</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation>Þetta merki verður rautt ef einhver viðtakandi tekur við upphæð sem er lægri en núgildandi þröskuldur.</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(ekkert merki)</translation>
+ </message>
+ </context>
+<context>
+ <name>EditAddressDialog</name>
+ <message>
+ <source>Edit Address</source>
+ <translation>Breyta færslugildi</translation>
+ </message>
+ <message>
+ <source>&amp;Label</source>
+ <translation>&amp;Merki</translation>
+ </message>
+ <message>
+ <source>The label associated with this address list entry</source>
+ <translation>Merking tengd þessu færslugildi</translation>
+ </message>
+ <message>
+ <source>The address associated with this address list entry. This can only be modified for sending addresses.</source>
+ <translation>Færslugildið sem tengt er þessari færslu. Þessu má einungis breyta þegar sent er.</translation>
+ </message>
+ <message>
+ <source>&amp;Address</source>
+ <translation>Nýtt móttökufærslugildi</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Nýtt sendingarfærslugildi</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Breyta móttökufærslugildi</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Breyta sendingarfærslugildi</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>Færslugildið sem slegið var inn "%1" er ekki leyfilegt Bitcoin færslugildi.</translation>
+ </message>
+ </context>
+<context>
+ <name>FreespaceChecker</name>
+ </context>
+<context>
+ <name>HelpMessageDialog</name>
+ </context>
+<context>
+ <name>Intro</name>
+ <message>
+ <source>Bitcoin</source>
+ <translation>Bitcoin</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Villa</translation>
+ </message>
+ </context>
+<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Number of blocks left</source>
+ <translation>Fjöldi blokka sem eftir eru</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Tími síðustu blokkar</translation>
+ </message>
+ </context>
+<context>
+ <name>OpenURIDialog</name>
+ </context>
+<context>
+ <name>OptionsDialog</name>
+ <message>
+ <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
+ <translation>IP tala staðgengils (t.d. IPv4: 127.0.0.1 / IPv6: ::1)</translation>
+ </message>
+ <message>
+ <source>Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source>
+ <translation>URL frá þriðja aðila (t.d. blokkarskoðari) sem birtast í færsluflipanum sem samhengisatriði. %s í URL-inu skipt út fyrir færslutvíkross. Mörg URL eru aðskilin með lóðréttu striki |.</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Villa</translation>
+ </message>
+ <message>
+ <source>The supplied proxy address is invalid.</source>
+ <translation>Uppgefið færslugildi staðgengils er ógilt.</translation>
+ </message>
+</context>
+<context>
+ <name>OverviewPage</name>
+ <message>
+ <source>Mined balance that has not yet matured</source>
+ <translation>Námuunnin innistæða sem hefur enn ekki komið fram</translation>
+ </message>
+ <message>
+ <source>Your current balance in watch-only addresses</source>
+ <translation>Innistæða færslugilda sem eru einungis til skoðunar</translation>
+ </message>
+ <message>
+ <source>Unconfirmed transactions to watch-only addresses</source>
+ <translation>Óstaðfestar færslur til færslugilda sem eru einungis til skoðunar</translation>
+ </message>
+ <message>
+ <source>Mined balance in watch-only addresses that has not yet matured</source>
+ <translation>Námuunnin innistæða á færslugildum sem eru einungis til skoðunar og hafa ekki komið fram</translation>
+ </message>
+ <message>
+ <source>Current total balance in watch-only addresses</source>
+ <translation>Innistæða á færslugildum sem eru einungis til skoðunar</translation>
+ </message>
+</context>
+<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>Invalid payment address %1</source>
+ <translation>Ógilt færslugildi til greiðslu %1</translation>
+ </message>
+ </context>
+<context>
+ <name>PeerTableModel</name>
+ </context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>Amount</source>
+ <translation>Upphæð</translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
+ <name>RPCConsole</name>
+ <message>
+ <source>Block chain</source>
+ <translation>Blokkarkeðja</translation>
+ </message>
+ <message>
+ <source>Current number of blocks</source>
+ <translation>Núverandi fjöldi blokka</translation>
+ </message>
+ <message>
+ <source>Starting Block</source>
+ <translation>Upphafsblokk</translation>
+ </message>
+ <message>
+ <source>Synced Blocks</source>
+ <translation>Samhæfðar blokkir</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Tími síðustu blokkar</translation>
+ </message>
+ </context>
+<context>
+ <name>ReceiveCoinsDialog</name>
+ <message>
+ <source>&amp;Label:</source>
+ <translation>&amp;Merki:</translation>
+ </message>
+ <message>
+ <source>An optional label to associate with the new receiving address.</source>
+ <translation>Valfrjálst merki sem tengist nýju móttökufærslutölunni.</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Afrita merki</translation>
+ </message>
+ </context>
+<context>
+ <name>ReceiveRequestDialog</name>
+ <message>
+ <source>Address</source>
+ <translation>Vistfang</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Upphæð</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Merki</translation>
+ </message>
+ <message>
+ <source>Wallet</source>
+ <translation>Veski</translation>
+ </message>
+ <message>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation>URI varð of langt, reyndu að minnka texta í merki / skilaboðum.</translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Merki</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(ekkert merki)</translation>
+ </message>
+ </context>
+<context>
+ <name>SendCoinsDialog</name>
+ <message>
+ <source>Quantity:</source>
+ <translation>Magn:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation>Bæti:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation>Upphæð:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation>Gjald:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation>Eftirgjald:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation>Skiptimynt:</translation>
+ </message>
+ <message>
+ <source>Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks. But be aware that this can end up in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source>
+ <translation>Það er í lagi að greiða einungis lágmarksupphæðina svo framarlega sem færslurúmtakið er minna en plássið í blokkunum. En gætið þess að þegar það er meiri eftirspurn eftir bitcoin færslum en netið getur unnið úr þá gæti svo farið að færslurnar verða aldrei samþykktar.</translation>
+ </message>
+ <message>
+ <source>(Smart fee not initialized yet. This usually takes a few blocks...)</source>
+ <translation>(Smart gjald er ekki gangsett ennþá. Þetta tekur venjulega nokkrar blokkir...)</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation>Ryk:</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(ekkert merki)</translation>
+ </message>
+</context>
+<context>
+ <name>SendCoinsEntry</name>
+ <message>
+ <source>&amp;Label:</source>
+ <translation>&amp;Merki:</translation>
+ </message>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
+ <name>ShutdownWindow</name>
+ </context>
+<context>
+ <name>SignVerifyMessageDialog</name>
+ </context>
+<context>
+ <name>SplashScreen</name>
+ </context>
+<context>
+ <name>TrafficGraphWidget</name>
+ </context>
+<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source>
+ <translation>Fullgerð mynt verður að nýta %1 blokkir. Þegar þú bjóst til þessa blokk, þá var jafnóðum tilkynnt á netinu að hún eigi að bætast við blokkakeðjuna. Ef hún kemst ekki í keðjuna þá mun staða hennar breytast í "ósamþykkt" og ekki verður hægt að nota hana. Þetta gerist annað slagið ef annar hnútpunktur klárar blokk nokkrum sekúndum á undan þinni.</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Upphæð</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionDescDialog</name>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Merki</translation>
+ </message>
+ <message>
+ <source>Mined</source>
+ <translation>Námuunnið</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(ekkert merki)</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Mined</source>
+ <translation>Námuunnið</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Afrita færslugildi</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Afrita merki</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Gildi aðskilin með kommu (*.csv)</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Merki</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Vistfang</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Útflutningur tókst ekki</translation>
+ </message>
+ </context>
+<context>
+ <name>UnitDisplayStatusBarControl</name>
+ </context>
+<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;Flytja út</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Flytja gögn í flipanum í skrá</translation>
+ </message>
+ </context>
+<context>
+ <name>bitcoin-core</name>
+ <message>
+ <source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source>
+ <translation>Villa við lestur %s! Allir lyklar fóru inn á réttan hátt, en færslugögn eða færslugildi gætu verið röng eða horfin.</translation>
+ </message>
+ <message>
+ <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
+ <translation>Viðvörun: Netið er ekki í fullu samræmi! Einhver námuvinnsla virðist í ólagi.</translation>
+ </message>
+ <message>
+ <source>Information</source>
+ <translation>Upplýsingar</translation>
+ </message>
+ <message>
+ <source>Warning</source>
+ <translation>Viðvörun</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source>
+ <translation>Viðvörun: Óþekkt blokkarútgáfa í námavinnslu! Það er mögulegt að óþekktum reglum sé fylgt</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Villa</translation>
+ </message>
+</context>
+</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_it.ts b/src/qt/locale/bitcoin_it.ts
index 5b24fcdf46..7513e3e30e 100644
--- a/src/qt/locale/bitcoin_it.ts
+++ b/src/qt/locale/bitcoin_it.ts
@@ -3169,6 +3169,10 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di "
<translation>Errore lettura %s! Tutte le chiavi sono state lette correttamente, ma i dati delle transazioni o della rubrica potrebbero essere mancanti o non corretti.</translation>
</message>
<message>
+ <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source>
+ <translation>Raggruppa gli output per indirizzo, selezionando tutti o nessuno, invece di selezionarli in base all'output. La privacy è migliorata in quanto un indirizzo viene usato una sola volta (a meno che qualcuno vi invii denaro dopo che avevate già speso da quell'indirizzo), ma può comportare commissioni leggermente più alte visto che le limitazioni aggiunte possono condurre a una selezione subottimale degli input da spendere (default: %u)</translation>
+ </message>
+ <message>
<source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source>
<translation>Per favore controllate che la data del computer e l'ora siano corrette! Se il vostro orologio è sbagliato %s non funzionerà correttamente.</translation>
</message>
@@ -3305,6 +3309,10 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di "
<translation>Importo non valido per -fallbackfee=&lt;amount&gt;: '%s'</translation>
</message>
<message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation>La cartella specificata "%s" non esiste.</translation>
+ </message>
+ <message>
<source>Upgrading txindex database</source>
<translation>Aggiornamento del database txindex</translation>
</message>
diff --git a/src/qt/locale/bitcoin_it_IT.ts b/src/qt/locale/bitcoin_it_IT.ts
index eccf015bf5..d97d888f23 100644
--- a/src/qt/locale/bitcoin_it_IT.ts
+++ b/src/qt/locale/bitcoin_it_IT.ts
@@ -232,7 +232,7 @@
</message>
<message>
<source>Banned Until</source>
- <translation>bannato fino </translation>
+ <translation>Bannato fino </translation>
</message>
</context>
<context>
@@ -760,7 +760,7 @@
</message>
<message>
<source>The wallet will also be stored in this directory.</source>
- <translation>Il portafoglio sara' </translation>
+ <translation>Il wallet verra' inoltre memorizzato su questa cartella.</translation>
</message>
<message>
<source>Error</source>
@@ -770,6 +770,14 @@
<context>
<name>ModalOverlay</name>
<message>
+ <source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source>
+ <translation>Le transazioni recenti potrebbero non essere ancora visibili, e quindi il saldo del wallet potrebbe essere incorretto. Questa informazione verra' corretta non appena il tuo wallet ha finito di sincronizzarsi con la rete bitcoin, come specificato di seguito.</translation>
+ </message>
+ <message>
+ <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source>
+ <translation>Tentare di spendere bitcoin che sono affetti da transazioni non ancora mostrate, non verra' accettato dal network.</translation>
+ </message>
+ <message>
<source>Number of blocks left</source>
<translation>Numero di blocchi rimanente</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ja.ts b/src/qt/locale/bitcoin_ja.ts
index 7650694e15..2ee78dbb29 100644
--- a/src/qt/locale/bitcoin_ja.ts
+++ b/src/qt/locale/bitcoin_ja.ts
@@ -3,11 +3,11 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation>右クリックでアドレスまたはラベルを編集します</translation>
+ <translation>右クリックでアドレスまたはラベルを編集</translation>
</message>
<message>
<source>Create a new address</source>
- <translation>新規アドレスの作成</translation>
+ <translation>新しいアドレスを作成</translation>
</message>
<message>
<source>&amp;New</source>
@@ -15,7 +15,7 @@
</message>
<message>
<source>Copy the currently selected address to the system clipboard</source>
- <translation>現在選択されているアドレスをシステムのクリップボードにコピーする</translation>
+ <translation>現在選択されているアドレスをシステムのクリップボードにコピー</translation>
</message>
<message>
<source>&amp;Copy</source>
@@ -27,15 +27,15 @@
</message>
<message>
<source>Delete the currently selected address from the list</source>
- <translation>選択されたアドレスを一覧から削除する</translation>
+ <translation>選択されたアドレスを一覧から削除</translation>
</message>
<message>
<source>Enter address or label to search</source>
- <translation>検索するアドレスまたはラベルを入力</translation>
+ <translation>検索したいアドレスまたはラベルを入力</translation>
</message>
<message>
<source>Export the data in the current tab to a file</source>
- <translation>ファイルに現在のタブのデータをエクスポート</translation>
+ <translation>このタブのデータをファイルにエクスポート</translation>
</message>
<message>
<source>&amp;Export</source>
@@ -47,11 +47,11 @@
</message>
<message>
<source>Choose the address to send coins to</source>
- <translation>送信先のアドレスを選択</translation>
+ <translation>コインを送りたいアドレスを選択</translation>
</message>
<message>
<source>Choose the address to receive coins with</source>
- <translation>支払いを受け取るアドレスを指定する</translation>
+ <translation>コインを受け取りたいアドレスを選択</translation>
</message>
<message>
<source>C&amp;hoose</source>
@@ -59,19 +59,19 @@
</message>
<message>
<source>Sending addresses</source>
- <translation>送金用</translation>
+ <translation>送金先アドレス</translation>
</message>
<message>
<source>Receiving addresses</source>
- <translation>受け取りアドレス</translation>
+ <translation>受取用アドレス</translation>
</message>
<message>
<source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
- <translation>これらは支払いを送信するためのあなたの Bitcoin アドレスです。コインを送信する前に、常に額と受信アドレスを確認してください。</translation>
+ <translation>これらは、あなたが知っている支払い送り先の Bitcoin アドレスです。コインを送る前に、必ず金額と送金先アドレスを確認してください。</translation>
</message>
<message>
<source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source>
- <translation>これらは支払いを受け取るためのビットコインアドレスです。トランザクションごとに新しい受け取り用アドレスを作成することが推奨されます。</translation>
+ <translation>これらは支払いを受け取るための、あなたの Bitcoin アドレスです。トランザクションごとに新しい受け取り用アドレスを作成することが推奨されます。</translation>
</message>
<message>
<source>&amp;Copy Address</source>
@@ -149,7 +149,7 @@
</message>
<message>
<source>This operation needs your wallet passphrase to unlock the wallet.</source>
- <translation>この操作はウォレットをアンロックするためにパスフレーズが必要です。</translation>
+ <translation>この操作を続行するには、ウォレットをアンロックするためのパスフレーズが必要です。</translation>
</message>
<message>
<source>Unlock wallet</source>
@@ -157,7 +157,7 @@
</message>
<message>
<source>This operation needs your wallet passphrase to decrypt the wallet.</source>
- <translation>この操作はウォレットの暗号化解除のためにパスフレーズが必要です。</translation>
+ <translation>この操作を続行するには、ウォレットの暗号化を解除するためのパスフレーズが必要です。</translation>
</message>
<message>
<source>Decrypt wallet</source>
@@ -177,7 +177,7 @@
</message>
<message>
<source>Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
- <translation>警告: もしもあなたのウォレットを暗号化してパスフレーズを失ってしまったなら、&lt;b&gt;あなたの Bitcoin はすべて失われます&lt;/b&gt;!</translation>
+ <translation>警告: もしもあなたのウォレットを暗号化してパスフレーズを忘れてしまったら、&lt;b&gt;あなたの Bitcoin はすべて失われます&lt;/b&gt;!</translation>
</message>
<message>
<source>Are you sure you wish to encrypt your wallet?</source>
@@ -189,11 +189,11 @@
</message>
<message>
<source>%1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
- <translation>暗号化処理を完了させるため %1 をいますぐ終了します。ウォレットの暗号化では、コンピュータに感染したマルウェアなどによるビットコインの盗難から完全に守ることはできないことにご注意ください。</translation>
+ <translation>暗号化処理を完了させるため %1 をいますぐ終了します。ウォレットを暗号化しても、コンピュータに感染したマルウェアなどによる Bitcoin の盗難を完全に防ぐことはできないことにご注意ください。</translation>
</message>
<message>
<source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
- <translation>重要: 過去のウォレット ファイルのバックアップは、暗号化された新しいウォレット ファイルに取り替える必要があります。セキュリティ上の理由により、暗号化された新しいウォレットを使い始めると、暗号化されていないウォレット ファイルのバックアップはすぐに使えなくなります。</translation>
+ <translation>重要: 今までに作成されたウォレット ファイルのバックアップは、暗号化された新しいウォレット ファイルに置き換える必要があります。セキュリティ上の理由により、暗号化された新しいウォレットを使い始めると、暗号化されていないウォレット ファイルのバックアップはすぐに使えなくなります。</translation>
</message>
<message>
<source>Wallet encryption failed</source>
@@ -225,7 +225,7 @@
</message>
<message>
<source>Warning: The Caps Lock key is on!</source>
- <translation>警告: Caps Lock キーがオンになっています!</translation>
+ <translation>警告: Caps Lock キーがオンになっています!</translation>
</message>
</context>
<context>
@@ -247,7 +247,7 @@
</message>
<message>
<source>Synchronizing with network...</source>
- <translation>ネットワークに同期中……</translation>
+ <translation>ネットワークと同期しています……</translation>
</message>
<message>
<source>&amp;Overview</source>
@@ -347,11 +347,11 @@
</message>
<message>
<source>Syncing Headers (%1%)...</source>
- <translation>未知。ヘッダを同期しています (%1%)...</translation>
+ <translation>ヘッダーを同期しています (%1%)...</translation>
</message>
<message>
<source>Reindexing blocks on disk...</source>
- <translation>ディスク上のブロックのインデックスを再作成中...</translation>
+ <translation>ディスク上のブロックのインデックスを再作成しています...</translation>
</message>
<message>
<source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
@@ -395,7 +395,7 @@
</message>
<message>
<source>&amp;Receive</source>
- <translation>入金 (&amp;R)</translation>
+ <translation>受取 (&amp;R)</translation>
</message>
<message>
<source>&amp;Show / Hide</source>
@@ -411,11 +411,11 @@
</message>
<message>
<source>Sign messages with your Bitcoin addresses to prove you own them</source>
- <translation>あなたが所有していることを証明するために、あなたの Bitcoin アドレスでメッセージに署名してください</translation>
+ <translation>Bitcoin アドレスをあなたが所有していることを証明するために、そのアドレスでメッセージに署名してください</translation>
</message>
<message>
<source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
- <translation>指定された Bitcoin アドレスで署名されたことを確認するためにメッセージを検証します</translation>
+ <translation>指定された Bitcoin アドレスで署名されたことを確認するために、メッセージを検証してください</translation>
</message>
<message>
<source>&amp;File</source>
@@ -435,15 +435,15 @@
</message>
<message>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
- <translation>支払いを要求する (QRコードとbitcoin:ではじまるURIを生成する)</translation>
+ <translation>支払いをリクエストする (QRコードとbitcoin:ではじまるURIを生成する)</translation>
</message>
<message>
<source>Show the list of used sending addresses and labels</source>
- <translation>使用済みの送金用アドレスとラベルの一覧を表示する</translation>
+ <translation>使用したことのある送金用アドレスとラベルの一覧を表示する</translation>
</message>
<message>
<source>Show the list of used receiving addresses and labels</source>
- <translation>支払いを受け取るアドレスとラベルのリストを表示する</translation>
+ <translation>使用したことのある受け取り用アドレスとラベルの一覧を表示する</translation>
</message>
<message>
<source>Open a bitcoin: URI or payment request</source>
@@ -455,7 +455,7 @@
</message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network</source>
- <translation><numerusform>%n の Bitcoin ネットワークへのアクティブな接続</numerusform></translation>
+ <translation><numerusform>Bitcoin ネットワークへのアクティブな接続は %n 個</numerusform></translation>
</message>
<message>
<source>Indexing blocks on disk...</source>
@@ -479,7 +479,7 @@
</message>
<message>
<source>Transactions after this will not yet be visible.</source>
- <translation>この後の取引はまだ表示されません。</translation>
+ <translation>この後の取引はまだ表示されていません。</translation>
</message>
<message>
<source>Error</source>
@@ -575,7 +575,7 @@
</message>
<message>
<source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
- <translation>致命的なエラーが発生しました。Bitcoin は安全に継続することができず終了するでしょう。</translation>
+ <translation>致命的なエラーが発生しました。Bitcoin を安全に動作し続けることができないため終了します。</translation>
</message>
</context>
<context>
@@ -710,7 +710,7 @@
</message>
<message>
<source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
- <translation>少なくともひとつの受取額が現在のダスト閾値を下回る場合にはこのラベルは赤くなります。</translation>
+ <translation>少なくともひとつの受取額が現在のダスト閾値を下回る場合に、このラベルは赤くなります。</translation>
</message>
<message>
<source>Can vary +/- %1 satoshi(s) per input.</source>
@@ -753,15 +753,15 @@
</message>
<message>
<source>New sending address</source>
- <translation>新しい送信アドレス</translation>
+ <translation>新しい送金用アドレス</translation>
</message>
<message>
<source>Edit receiving address</source>
- <translation>入金アドレスを編集</translation>
+ <translation>受け取り用アドレスを編集</translation>
</message>
<message>
<source>Edit sending address</source>
- <translation>送信アドレスを編集</translation>
+ <translation>送金用アドレスを編集</translation>
</message>
<message>
<source>The entered address "%1" is not a valid Bitcoin address.</source>
@@ -769,11 +769,11 @@
</message>
<message>
<source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source>
- <translation>アドレス "%1" は既に受取用アドレスにラベル "%2" として存在するので、送金用アドレスとしては追加できません。</translation>
+ <translation>アドレス "%1" は、既に受け取り用アドレスにラベル "%2" として存在するので、送金用アドレスとしては追加できません。</translation>
</message>
<message>
<source>The entered address "%1" is already in the address book with label "%2".</source>
- <translation>入力されたアドレス"%1"はすでにアドレス帳のラベル"%2"に存在します。</translation>
+ <translation>入力されたアドレス"%1"は、既にアドレス帳にラベル "%2" として存在します。</translation>
</message>
<message>
<source>Could not unlock wallet.</source>
@@ -796,7 +796,7 @@
</message>
<message>
<source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
- <translation>ディレクトリがもうあります。 新しいのディレクトリを作るつもりなら%1を書いてください。</translation>
+ <translation>ディレクトリが既に存在します。 新しいディレクトリを作成したい場合は %1 を追加してください。</translation>
</message>
<message>
<source>Path already exists, and is not a directory.</source>
@@ -846,19 +846,19 @@
</message>
<message>
<source>This initial synchronisation is very demanding, and may expose hardware problems with your computer that had previously gone unnoticed. Each time you run %1, it will continue downloading where it left off.</source>
- <translation>この初期同期には多大なリソースを消費し、あなたのコンピュータにこれまで見つからなかったハードウェア上の問題を露呈させるかもしれません。%1 を実行する度に、中断された時点からダウンロードを継続します。</translation>
+ <translation>この初期同期には多大なリソースを消費し、あなたのコンピュータでこれまで見つからなかったハードウェア上の問題が発生する場合があります。%1 を実行する度に、中断された時点からダウンロードを再開します。</translation>
</message>
<message>
<source>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</source>
- <translation>ブロックチェーンの保存容量に制限を設けることを選択した場合 (剪定) にも、過去のデータのダウンロードおよび処理が必要になります。しかしこれらのデータはディスク使用量を低く抑えるためにその後削除されるでしょう</translation>
+ <translation>ブロックチェーンの保存容量に制限を設けることを選択した場合 (剪定) にも、過去のデータのダウンロードおよび処理が必要になります。しかし、これらのデータはディスク使用量を低く抑えるために、後で削除されます。</translation>
</message>
<message>
<source>Use the default data directory</source>
- <translation>初期値のデータ ディレクトリを使用</translation>
+ <translation>既定のデータ ディレクトリを使用</translation>
</message>
<message>
<source>Use a custom data directory:</source>
- <translation>任意のデータ ディレクトリを使用:</translation>
+ <translation>カスタムのデータ ディレクトリを使用:</translation>
</message>
<message>
<source>Bitcoin</source>
@@ -905,11 +905,11 @@
</message>
<message>
<source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source>
- <translation>確認できない最近のトランザクションがあるかもしれません。これによりウォレットの残高は不正確なものである可能性があります。この情報はウォレットが一度ビットコインネットワークへの同期が完了すると正確なものとなります。詳細は下記を参照してください。</translation>
+ <translation>最近のトランザクションがまだ表示されていない可能性があります。そのため、ウォレットの残高が正しく表示されていないかもしれません。この情報は、ウォレットが Bitcoin ネットワークへの同期が完了すると正確なものとなります。詳細は下記を参照してください。</translation>
</message>
<message>
<source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source>
- <translation>まだ表示されていないトランザクションが影響するビットコインを使用しようとすると、ネットワークから認証がなされないでしょう。</translation>
+ <translation>まだ表示されていないトランザクションが影響する Bitcoin を使用しようとすると、ネットワークから認証を受けられません。</translation>
</message>
<message>
<source>Number of blocks left</source>
@@ -3200,6 +3200,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p
<translation>%s の読み込みエラー! すべてのキーは正しく読み取れますが、取引データやアドレス帳のエントリが失われたか、正しくない可能性があります。</translation>
</message>
<message>
+ <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source>
+ <translation>出力ごとではなく、アドレス単位に出力をまとめて選択します。(後からまたそのアドレスに支払われない限り)アドレスが一度しか使用されないためプライバシーが向上します。ただし追加の制限により最適ではないコイン選択が発生した場合に、わずかに高い手数料となる可能性があります。(初期値: %u)</translation>
+ </message>
+ <message>
<source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source>
<translation>あなたのPCの日付と時刻が正しいことを確認して下さい! もしあなたの時計が正しくなければ %s が正確に動作しません。</translation>
</message>
@@ -3341,6 +3345,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p
<translation>不正な額 -fallbackfee=&lt;amount&gt;: '%s'</translation>
</message>
<message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation>指定のブロックディレクトリ"%s"は存在しません。</translation>
+ </message>
+ <message>
<source>Upgrading txindex database</source>
<translation>txindex データベースを更新しています</translation>
</message>
@@ -3481,12 +3489,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p
<translation>取引の署名に失敗しました</translation>
</message>
<message>
- <source>Specified blocks directory "%s" does not exist.
-</source>
- <translation>指定のブロックディレクトリ"%s"が存在しません。
-</translation>
- </message>
- <message>
<source>The transaction amount is too small to pay the fee</source>
<translation>トランザクションの金額が小さすぎて手数料を支払えません</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ka.ts b/src/qt/locale/bitcoin_ka.ts
index 3fd95eb6f5..57053ac62d 100644
--- a/src/qt/locale/bitcoin_ka.ts
+++ b/src/qt/locale/bitcoin_ka.ts
@@ -200,6 +200,14 @@
<translation>საფულის დაშიფვრა წარუმატებით დამთვრდა</translation>
</message>
<message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>საფულის დაშიფრვა ვერ მოხდა შიდა შეცდომის გამო. თქვენი საფულე არ არის დაშიფრული.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>მოწოდებული ფრაზა-პაროლები არ ემთხვევა ერთმანეთს.</translation>
+ </message>
+ <message>
<source>Wallet unlock failed</source>
<translation>საფულის გახსნა წარუმატებლად შესრულდა</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ko.ts b/src/qt/locale/bitcoin_ko.ts
new file mode 100644
index 0000000000..aa05383a83
--- /dev/null
+++ b/src/qt/locale/bitcoin_ko.ts
@@ -0,0 +1,471 @@
+<TS language="ko" version="2.1">
+<context>
+ <name>AddressBookPage</name>
+ <message>
+ <source>Right-click to edit address or label</source>
+ <translation>마우스 오른쪽 클릭을 해서 라벨이나 주소를 편집할 수 있습니다</translation>
+ </message>
+ <message>
+ <source>Create a new address</source>
+ <translation>새로운 주소 발급받기</translation>
+ </message>
+ <message>
+ <source>&amp;New</source>
+ <translation>&amp;발급받기</translation>
+ </message>
+ <message>
+ <source>Copy the currently selected address to the system clipboard</source>
+ <translation>선택된 주소 클립보드에 붙여넣기</translation>
+ </message>
+ <message>
+ <source>&amp;Copy</source>
+ <translation>&amp;복사</translation>
+ </message>
+ <message>
+ <source>C&amp;lose</source>
+ <translation>&amp;닫기</translation>
+ </message>
+ <message>
+ <source>Delete the currently selected address from the list</source>
+ <translation>선택한 주소 리스트에서 삭제</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation>검색할 주소나 라벨을 입력하세요</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>현재 탭의 데이터를 파일로 내보냅니다</translation>
+ </message>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;내보내기</translation>
+ </message>
+ <message>
+ <source>&amp;Delete</source>
+ <translation>&amp;삭제하기</translation>
+ </message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>코인을 보낼 주소를 선택하세요</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>코인을 받을 주소를 선택하세요</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>&amp;선택하기</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>보낼 주소</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>받을 주소</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
+ <translation>이것은 비트코인 전송을 위한 주소입니다. 코인을 보내기 전에 항상 받는 주소와 수량을 확인하세요</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source>
+ <translation>이것은 비트코인 수신을 위한 주소입니다. 코인을 받을 때 마다 항상 다른 주소를 사용 하시는 것을 권장합니다.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;주소 복사</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>&amp;라벨 복사</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;편집</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>주소 목록 내보내기</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>내보내기 실패</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>주소 목록을 %1 로 저장하는 작업이 실패했습니다. 다시 시도해 주세요.</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ </context>
+<context>
+ <name>AskPassphraseDialog</name>
+ <message>
+ <source>Enter passphrase</source>
+ <translation>암호문 입력</translation>
+ </message>
+ <message>
+ <source>New passphrase</source>
+ <translation>새 암호문</translation>
+ </message>
+ <message>
+ <source>Repeat new passphrase</source>
+ <translation>새 암호문 다시 입력</translation>
+ </message>
+ <message>
+ <source>Show password</source>
+ <translation>비밀번호 보이기</translation>
+ </message>
+ <message>
+ <source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;ten or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
+ <translation>새 암호문을 지갑에 입력합니다. &lt;br/&gt;이러한 형식의 암호문을 사용해 주십시요.&lt;b&gt;10개 이상의 임의 문자&lt;/b&gt; 또는 &lt;b&gt;8개 이상의 단어&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>지갑 암호화</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>이 작업을 수행하려면 지갑을 잠금 해제 할 암호문이 필요합니다.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>지갑 잠금 해제</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>이 작업을 수행하려면 지갑을 복호화할 암호문이 필요합니다.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>지갑 복호화</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>암호문 변경</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>예전 암호문과 변경할 암호문을 입력하십시요.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>지갑 암호화 확인</translation>
+ </message>
+ <message>
+ <source>Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
+ <translation>경고: 지갑이 암호화된 상태로 당신의 암호문을 잃어버리셨다면, 당신은 &lt;b&gt;모든 비트코인을 잃게됩니다&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>진짜로 지갑을 암호화 할까요?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>지갑 암호화</translation>
+ </message>
+ <message>
+ <source>%1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
+ <translation>%1 이(가) 암호화 작업을 위해 종료됩니다. 이 암호화 작업이 바이러스로부터 비트코인을 완전히 지키지 못한다는 점을 기억하십시요.</translation>
+ </message>
+ <message>
+ <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
+ <translation>중요: 예전에 만들었던 모든 백업 파일은 새로 만들어진 암호화된 지갑 파일으로 교체됩니다. 보안을 위해서 예전에 만들었던 암호화 되지 않은 백업 파일은 당신이 새로 암호화된 지갑을 사용하고 사용할 수 없게 됩니다. </translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>지갑 암호화 실패</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>내부 오류로 인해 지갑 암호화가 실패했습니다. 지갑이 암호화 되지 않았습니다.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>입력한 암호문이 일치하지 않습니다.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>지갑 잠금 해제 실패</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>지갑 복호화를 위한 암호문이 일치하지 않습니다.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>지갑 복호화 실패</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>지갑 암호문이 성공적으로 변경되었습니다.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>주의: Caps Lock이 켜져있습니다!</translation>
+ </message>
+</context>
+<context>
+ <name>BanTableModel</name>
+ <message>
+ <source>IP/Netmask</source>
+ <translation>IP/Netmask</translation>
+ </message>
+ <message>
+ <source>Banned Until</source>
+ <translation>특정 시점까지 차단</translation>
+ </message>
+</context>
+<context>
+ <name>BitcoinGUI</name>
+ <message>
+ <source>Sign &amp;message...</source>
+ <translation>&amp;메시지에 서명하기...</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network...</source>
+ <translation>네트워크와 동기화중...</translation>
+ </message>
+ <message>
+ <source>&amp;Overview</source>
+ <translation>&amp;개요</translation>
+ </message>
+ <message>
+ <source>Node</source>
+ <translation>노드</translation>
+ </message>
+ <message>
+ <source>Show general overview of wallet</source>
+ <translation>지갑의 일반적인 개요 표시</translation>
+ </message>
+ <message>
+ <source>&amp;Transactions</source>
+ <translation>&amp;거래</translation>
+ </message>
+ <message>
+ <source>Browse transaction history</source>
+ <translation>거래 기록 보기</translation>
+ </message>
+ <message>
+ <source>E&amp;xit</source>
+ <translation>&amp;나가기</translation>
+ </message>
+ <message>
+ <source>Quit application</source>
+ <translation>애플리케이션 종료</translation>
+ </message>
+ <message>
+ <source>&amp;About %1</source>
+ <translation>&amp;%1에 대해</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation>%1에 대한 정보 표시</translation>
+ </message>
+ <message>
+ <source>About &amp;Qt</source>
+ <translation>&amp;Qt에 대해</translation>
+ </message>
+ <message>
+ <source>Show information about Qt</source>
+ <translation>Qt에 대한 정보 표시</translation>
+ </message>
+ <message>
+ <source>&amp;Options...</source>
+ <translation>&amp;설정...</translation>
+ </message>
+ <message>
+ <source>Modify configuration options for %1</source>
+ <translation>%1에 대한 구성 수정</translation>
+ </message>
+ <message>
+ <source>&amp;Encrypt Wallet...</source>
+ <translation>&amp;지갑 암호화...</translation>
+ </message>
+ <message>
+ <source>&amp;Backup Wallet...</source>
+ <translation>&amp;지갑 백업...</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase...</source>
+ <translation>&amp;암호문 변경...</translation>
+ </message>
+ <message>
+ <source>&amp;Sending addresses...</source>
+ <translation>&amp;보낼 주소...</translation>
+ </message>
+ <message>
+ <source>&amp;Receiving addresses...</source>
+ <translation>&amp;받을 주소...</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI...</source>
+ <translation>&amp;URL 열기</translation>
+ </message>
+ <message>
+ <source>Wallet:</source>
+ <translation>지갑:</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation>기본 지갑</translation>
+ </message>
+ <message>
+ <source>Click to disable network activity.</source>
+ <translation>클릭해서 네트워크 활동 중지</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>네트워크 활동 중지</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>클릭해서 네트워크 활동 활성화</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>헤더 동기화 (%1%)...</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk...</source>
+ <translation>디스크에서 블럭 불러오는 중</translation>
+ </message>
+ <message>
+ <source>Send coins to a Bitcoin address</source>
+ <translation>비트코인 주소로 코인 보내기</translation>
+ </message>
+ <message>
+ <source>Backup wallet to another location</source>
+ <translation>이 지갑을 다른 곳으로 백업</translation>
+ </message>
+ <message>
+ <source>Change the passphrase used for wallet encryption</source>
+ <translation>지갑 암호화에 사용될 암호문 바꾸기</translation>
+ </message>
+ </context>
+<context>
+ <name>CoinControlDialog</name>
+ </context>
+<context>
+ <name>EditAddressDialog</name>
+ </context>
+<context>
+ <name>FreespaceChecker</name>
+ </context>
+<context>
+ <name>HelpMessageDialog</name>
+ </context>
+<context>
+ <name>Intro</name>
+ </context>
+<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
+ <name>OpenURIDialog</name>
+ </context>
+<context>
+ <name>OptionsDialog</name>
+ </context>
+<context>
+ <name>OverviewPage</name>
+ </context>
+<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
+ <name>PeerTableModel</name>
+ </context>
+<context>
+ <name>QObject</name>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
+ <name>RPCConsole</name>
+ <message>
+ <source>default wallet</source>
+ <translation>기본 지갑</translation>
+ </message>
+ </context>
+<context>
+ <name>ReceiveCoinsDialog</name>
+ </context>
+<context>
+ <name>ReceiveRequestDialog</name>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ </context>
+<context>
+ <name>SendCoinsDialog</name>
+ </context>
+<context>
+ <name>SendCoinsEntry</name>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
+ <name>ShutdownWindow</name>
+ </context>
+<context>
+ <name>SignVerifyMessageDialog</name>
+ </context>
+<context>
+ <name>SplashScreen</name>
+ </context>
+<context>
+ <name>TrafficGraphWidget</name>
+ </context>
+<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
+ <name>TransactionDescDialog</name>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>내보내기 실패</translation>
+ </message>
+ </context>
+<context>
+ <name>UnitDisplayStatusBarControl</name>
+ </context>
+<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;내보내기</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>현재 탭의 데이터를 파일로 내보냅니다</translation>
+ </message>
+ </context>
+<context>
+ <name>bitcoin-core</name>
+ <message>
+ <source>Transaction amounts must not be negative</source>
+ <translation>송금액은 마이너스가 될 수 없습니다</translation>
+ </message>
+ </context>
+</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_ko_KR.ts b/src/qt/locale/bitcoin_ko_KR.ts
index a7a0767464..76ac713e05 100644
--- a/src/qt/locale/bitcoin_ko_KR.ts
+++ b/src/qt/locale/bitcoin_ko_KR.ts
@@ -3108,7 +3108,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p
</message>
<message>
<source>Could not commit transaction</source>
- <translation>트랜잭션을 커밋 할 수 없습니다.</translation>
+ <translation>거래를 커밋 할 수 없습니다.</translation>
</message>
</context>
<context>
@@ -3337,6 +3337,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p
<translation>유효하지 않은 금액 -fallbackfee=&lt;amount&gt;: '%s'</translation>
</message>
<message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation>디렉토리 "%s"에 지정한 블록들이 존재하지 않습니다.</translation>
+ </message>
+ <message>
<source>Upgrading txindex database</source>
<translation>txindex 데이터베이스 업테이트중</translation>
</message>
@@ -3489,11 +3493,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p
<translation>애러: 지정한 지갑 폴더 "%s"은 디렉토리가 아닙니다.</translation>
</message>
<message>
- <source>Specified blocks directory "%s" does not exist.
-</source>
- <translation>지정한 블록 폴더 "%s"는 존재하지 않습니다.</translation>
- </message>
- <message>
<source>The transaction amount is too small to pay the fee</source>
<translation>거래액이 수수료를 지불하기엔 너무 작습니다</translation>
</message>
diff --git a/src/qt/locale/bitcoin_lt.ts b/src/qt/locale/bitcoin_lt.ts
index b4207524c9..26d89de8e9 100644
--- a/src/qt/locale/bitcoin_lt.ts
+++ b/src/qt/locale/bitcoin_lt.ts
@@ -3,7 +3,7 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation>Spustelėkite dešinįjį klavišą norint keisti adresą arba etiketę</translation>
+ <translation>Spustelėkite dešinįjį klaviša norint keisti adresą arba etiketę</translation>
</message>
<message>
<source>Create a new address</source>
@@ -49,14 +49,74 @@
<source>Choose the address to send coins to</source>
<translation>Pasirinkite adresą, kuriam siūsite monetas</translation>
</message>
- </context>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Pasirinkite adresą su kuriuo gauti monetas</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>P&amp;asirinkti</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Išsiuntimo adresai</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Gavimo adresai</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
+ <translation>Tai yra jūsų Bitcoin adresai išeinantiems mokėjimams. Visada pasitikrinkite sumą ir gavėjo adresą prieš siunčiant lėšas. </translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source>
+ <translation>Tai yra Jūsų Bitcoin adresai įeinantiems mokėjimams. Kiekvienam mokėjimui rekomenduojama naudoti naują adresą. </translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Kopijuoti adresą</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Kopijuoti &amp;Žymę</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Keisti</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Eksportuoti adresų sąrašą</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Kableliais atskirtų duomenų failas (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Eksportavimas nepavyko</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Bandant išsaugoti adresų sąrašą - įvyko klaida keliant į %1. Prašome bandyti dar kartą.</translation>
+ </message>
+</context>
<context>
<name>AddressTableModel</name>
<message>
+ <source>Label</source>
+ <translation>Žymė</translation>
+ </message>
+ <message>
<source>Address</source>
<translation>Adresas</translation>
</message>
- </context>
+ <message>
+ <source>(no label)</source>
+ <translation>(nėra žymės)</translation>
+ </message>
+</context>
<context>
<name>AskPassphraseDialog</name>
<message>
@@ -75,7 +135,95 @@
<source>Repeat new passphrase</source>
<translation>Pakartokite naują slaptafrazę</translation>
</message>
- </context>
+ <message>
+ <source>Show password</source>
+ <translation>Rodyti slaptažodį</translation>
+ </message>
+ <message>
+ <source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;ten or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
+ <translation>Įveskite naują piniginės slaptafrazę.&lt;br/&gt;Prašome naudoti slaptafrazę iš &lt;b&gt; 10 ar daugiau atsitiktinių simbolių&lt;/b&gt; arba &lt;b&gt;aštuonių ar daugiau žodžių&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Užšifruoti piniginę</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Ši operacija reikalauja jūsų piniginės slaptafrazės jai atrakinti.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Atrakinti piniginę</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Ši operacija reikalauja jūsų piniginės slaptafrazės jai iššifruoti.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Iššifruoti piniginę</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Pakeisti slaptafrazę</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Įveskite seną ir naują piniginės slaptafrazes.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Patvirtinkite piniginės užšifravimą</translation>
+ </message>
+ <message>
+ <source>Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
+ <translation>Dėmesio: jei užšifruosite savo piniginę ir pamesite slaptafrazę, jūs&lt;b&gt;PRARASITE VISUS SAVO BITCOINUS&lt;/b&gt;! </translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Ar tikrai norite šifruoti savo piniginę?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Piniginė užšifruota</translation>
+ </message>
+ <message>
+ <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
+ <translation>SVARBU: Betkokios ankstesnės jūsų piniginės atsarginės kopijos turėtų būti pakeistos naujai sugeneruotu, užšifruotu piniginės failu. Dėl saugumo sumetimų, anstesnės neužšifruotos piniginės kopijos failas taps nenaudingu nuo momento, kai nauja ir užšifruota piniginė bus pradėta naudoti. </translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Nepavyko užšifruoti piniginę</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Dėl vidinės klaidos nepavyko užšifruoti piniginę.Piniginė neužšifruota.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>Įvestos slaptafrazės nesutampa.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Nepavyko atrakinti piniginę</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>Neteisingai įvestas slaptažodis piniginės iššifravimui.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Nepavyko iššifruoti piniginės</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>Piniginės slaptažodis sėkmingai pakeistas.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Įspėjimas: įjungtas Caps Lock klavišas!</translation>
+ </message>
+</context>
<context>
<name>BanTableModel</name>
<message>
@@ -142,6 +290,10 @@
<translation>&amp;Parinktys...</translation>
</message>
<message>
+ <source>Modify configuration options for %1</source>
+ <translation>Keisti %1 konfigūracijos galimybes</translation>
+ </message>
+ <message>
<source>&amp;Encrypt Wallet...</source>
<translation>&amp;Užšifruoti piniginę...</translation>
</message>
@@ -166,6 +318,30 @@
<translation>Atidaryti &amp;URI...</translation>
</message>
<message>
+ <source>Wallet:</source>
+ <translation>Piniginė</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation>numatyta piniginė</translation>
+ </message>
+ <message>
+ <source>Click to disable network activity.</source>
+ <translation>Spauskite norėdami išjungti tinklo veiklą.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Tinklo veikla išjungta.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>Spauskite norėdami įjungti tinklo veiklą.</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Sinchronizuojamos Antraštės (%1%)...</translation>
+ </message>
+ <message>
<source>Reindexing blocks on disk...</source>
<translation>Blokai iš naujo indeksuojami...</translation>
</message>
@@ -222,6 +398,14 @@
<translation>Užšifruoti privačius raktus, kurie priklauso jūsų piniginei</translation>
</message>
<message>
+ <source>Sign messages with your Bitcoin addresses to prove you own them</source>
+ <translation>Pasirašydami žinutes su savo Bitcoin adresais įrodysite jog esate jų savininkas </translation>
+ </message>
+ <message>
+ <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
+ <translation>Patikrinkite žinutę, jog įsitikintumėte, kad ją pasirašė nurodytas Bitcoin adresas</translation>
+ </message>
+ <message>
<source>&amp;File</source>
<translation>&amp;Failas</translation>
</message>
@@ -242,6 +426,18 @@
<translation>Komandinės eilutės parametrai</translation>
</message>
<message>
+ <source>Processing blocks on disk...</source>
+ <translation>Blokai apdirbami diske...</translation>
+ </message>
+ <message>
+ <source>Last received block was generated %1 ago.</source>
+ <translation>Paskutinis gautas blokas buvo sukurtas prieš %1.</translation>
+ </message>
+ <message>
+ <source>Transactions after this will not yet be visible.</source>
+ <translation>Sekančios operacijos dar nebus matomos. </translation>
+ </message>
+ <message>
<source>Error</source>
<translation>Klaida</translation>
</message>
@@ -258,6 +454,10 @@
<translation>Atnaujinta</translation>
</message>
<message>
+ <source>%1 client</source>
+ <translation>%1 klientas</translation>
+ </message>
+ <message>
<source>Catching up...</source>
<translation>Vejamasi...</translation>
</message>
@@ -268,6 +468,36 @@
</translation>
</message>
<message>
+ <source>Amount: %1
+</source>
+ <translation>Suma: %1
+</translation>
+ </message>
+ <message>
+ <source>Wallet: %1
+</source>
+ <translation>Piniginė: %1
+</translation>
+ </message>
+ <message>
+ <source>Type: %1
+</source>
+ <translation>Spausti: %1
+</translation>
+ </message>
+ <message>
+ <source>Label: %1
+</source>
+ <translation>Antraštė: %1
+</translation>
+ </message>
+ <message>
+ <source>Address: %1
+</source>
+ <translation>Adresas: %1
+</translation>
+ </message>
+ <message>
<source>Sent transaction</source>
<translation>Sandoris nusiųstas</translation>
</message>
@@ -342,6 +572,50 @@
<source>Confirmed</source>
<translation>Patvirtintas</translation>
</message>
+ <message>
+ <source>Copy address</source>
+ <translation>Kopijuoti adresą</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopijuoti žymę</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopijuoti sumą</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Sandorio ID</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Kopijuoti mokestį</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Kopijuoti po mokesčio</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Kopijuoti baitus</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Kopijuoti keisti</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>taip</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>ne</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(nėra žymės)</translation>
+ </message>
</context>
<context>
<name>EditAddressDialog</name>
@@ -387,6 +661,10 @@
<translation>Bitcoin</translation>
</message>
<message>
+ <source>The wallet will also be stored in this directory.</source>
+ <translation>Piniginė taip pat bus saugojama šiame direktyve.</translation>
+ </message>
+ <message>
<source>Error</source>
<translation>Klaida</translation>
</message>
@@ -701,6 +979,10 @@
<translation>Išvalyti konsolę</translation>
</message>
<message>
+ <source>default wallet</source>
+ <translation>numatyta piniginė</translation>
+ </message>
+ <message>
<source>never</source>
<translation>Niekada</translation>
</message>
@@ -731,7 +1013,15 @@
<source>Clear</source>
<translation>Išvalyti</translation>
</message>
- </context>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopijuoti žymę</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopijuoti sumą</translation>
+ </message>
+</context>
<context>
<name>ReceiveRequestDialog</name>
<message>
@@ -747,12 +1037,24 @@
<translation>Adresas</translation>
</message>
<message>
+ <source>Label</source>
+ <translation>Žymė</translation>
+ </message>
+ <message>
<source>Wallet</source>
<translation>Piniginė</translation>
</message>
</context>
<context>
<name>RecentRequestsTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Žymė</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(nėra žymės)</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -817,10 +1119,34 @@
<translation>&amp;Siųsti</translation>
</message>
<message>
+ <source>Copy amount</source>
+ <translation>Kopijuoti sumą</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Kopijuoti mokestį</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Kopijuoti po mokesčio</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Kopijuoti baitus</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Kopijuoti keisti</translation>
+ </message>
+ <message>
<source>Transaction fee</source>
<translation>Sandorio mokestis</translation>
</message>
- </context>
+ <message>
+ <source>(no label)</source>
+ <translation>(nėra žymės)</translation>
+ </message>
+</context>
<context>
<name>SendCoinsEntry</name>
<message>
@@ -935,13 +1261,49 @@
</context>
<context>
<name>TransactionTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Žymė</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(nėra žymės)</translation>
+ </message>
</context>
<context>
<name>TransactionView</name>
<message>
+ <source>Copy address</source>
+ <translation>Kopijuoti adresą</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopijuoti žymę</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopijuoti sumą</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Sandorio ID</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Kableliais atskirtų duomenų failas (*.csv)</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Žymė</translation>
+ </message>
+ <message>
<source>Address</source>
<translation>Adresas</translation>
</message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Eksportavimas nepavyko</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
diff --git a/src/qt/locale/bitcoin_ml.ts b/src/qt/locale/bitcoin_ml.ts
new file mode 100644
index 0000000000..fdd3bd74bd
--- /dev/null
+++ b/src/qt/locale/bitcoin_ml.ts
@@ -0,0 +1,336 @@
+<TS language="ml" version="2.1">
+<context>
+ <name>AddressBookPage</name>
+ <message>
+ <source>Right-click to edit address or label</source>
+ <translation>വിലാസം അല്ലെങ്കിൽ ലേബൽ എഡിറ്റുചെയ്യാൻ വലത് ക്ലിക്കുചെയ്യുക</translation>
+ </message>
+ <message>
+ <source>Create a new address</source>
+ <translation>ഒരു പുതിയ വിലാസം സൃഷ്ടിക്കുക</translation>
+ </message>
+ <message>
+ <source>&amp;New</source>
+ <translation>&amp;പുതിയത്</translation>
+ </message>
+ <message>
+ <source>Copy the currently selected address to the system clipboard</source>
+ <translation>നിലവിൽ തിരഞ്ഞെടുത്ത വിലാസം സിസ്റ്റം ക്ലിപ്പ്ബോർഡിലേക്ക് പകർത്തുക</translation>
+ </message>
+ <message>
+ <source>&amp;Copy</source>
+ <translation>&amp; പകർത്തുക
+</translation>
+ </message>
+ <message>
+ <source>C&amp;lose</source>
+ <translation>അ&amp;ടയ്ക്കുക</translation>
+ </message>
+ <message>
+ <source>Delete the currently selected address from the list</source>
+ <translation>പട്ടികയിൽ നിന്ന് നിലവിൽ തിരഞ്ഞെടുത്ത വിലാസം ഇല്ലാതാക്കുക</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>നിലവിലെ ടാബിൽ ഒരു ഫയലിൽ ഡാറ്റ എക്സ്പോർട്ട് ചെയ്യുക</translation>
+ </message>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp; കയറ്റുമതി ചെയ്യുക</translation>
+ </message>
+ <message>
+ <source>&amp;Delete</source>
+ <translation>&amp;ഇല്ലാതാക്കുക</translation>
+ </message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>നാണയങ്ങൾ അയയ്ക്കാനുള്ള വിലാസം തിരഞ്ഞെടുക്കുക</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>നാണയങ്ങൾ സ്വീകരിക്കാൻ വിലാസം തിരഞ്ഞെടുക്കുക</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>തി&amp;രഞ്ഞെടുക്കുക</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>വിലാസങ്ങൾ അയയ്ക്കുന്നു</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>സ്വീകരിക്കുന്ന വിലാസങ്ങൾ</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
+ <translation>പേയ്മെന്റുകൾ അയയ്ക്കുന്നതിനുള്ള നിങ്ങളുടെ ബിറ്റ്കോയിൻ വിലാസങ്ങളാണ് ഇവ. നാണയങ്ങൾ അയയ്ക്കുന്നതിനുമുമ്പ് എല്ലായ്പ്പോഴും തുകയും സ്വീകരിക്കുന്ന വിലാസവും പരിശോധിക്കുക.</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source>
+ <translation>പേയ്മെന്റ് സ്വീകരിക്കുന്നതിന് നിങ്ങളുടെ ബിറ്റ്കോയിൻ വിലാസങ്ങളാണ് ഇവ. ഓരോ ഇടപാടിനും പുതിയ സ്വീകരിക്കുന്ന വിലാസം ഉപയോഗിക്കുന്നതാണ് ഉചിതം.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;വിലാസം പകർത്തുക</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>പകർത്തുക &amp;ലേബൽ</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;ചിട്ടപ്പെടുത്തുക</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>കയറ്റുമതി വിലാസ ലിസ്റ്റ്</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>കോമയാൽ വേർതിരിച്ച ഫയൽ (* .csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>കയറ്റുമതി പരാജയപ്പെട്ടു</translation>
+ </message>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>ലേബൽ</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>വിലാസം</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(ലേബൽ ഇല്ല)</translation>
+ </message>
+</context>
+<context>
+ <name>AskPassphraseDialog</name>
+ <message>
+ <source>Passphrase Dialog</source>
+ <translation>രഹസ്യപദപ്രയോഗ സംഭാഷണം</translation>
+ </message>
+ <message>
+ <source>Enter passphrase</source>
+ <translation>രഹസ്യപദപ്രയോഗം നൽകുക</translation>
+ </message>
+ <message>
+ <source>New passphrase</source>
+ <translation>പുതിയ രഹസ്യപദപ്രയോഗം</translation>
+ </message>
+ <message>
+ <source>Repeat new passphrase</source>
+ <translation>പുതിയ രഹസ്യപദപ്രയോഗം ആവർത്തിക്കുക</translation>
+ </message>
+ <message>
+ <source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;ten or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
+ <translation>വാലറ്റിൽ പുതിയ രഹസ്യപദപ്രയോഗം നൽകുക. &lt;br/&gt; &lt;b&gt; പത്തോ അതിലധികമോ റാൻഡം പ്രതീകങ്ങൾ &lt;/ b&gt; അല്ലെങ്കിൽ &lt;b&gt; എട്ട് അല്ലെങ്കിൽ അതിൽ കൂടുതൽ വാക്കുകൾ &lt;/ b&gt; ഒരു രഹസ്യപദപ്രയോഗം ഉപയോഗിക്കുക.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>വാലറ്റ് എൻക്രിപ്റ്റ് ചെയ്യുക</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>നിങ്ങളുടെ വാലറ്റ് അൺലോക്കുചെയ്യാൻ ഈ പ്രവർത്തനത്തിന് നിങ്ങളുടെ വാലറ്റ് രഹസ്യപദപ്രയോഗം ആവശ്യമാണ്.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>വാലറ്റ് അൺലോക്ക് ചെയ്യുക</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>ഈ പ്രവർത്തനത്തിന് വാലറ്റ് ഡീക്രിപ്റ്റ് ചെയ്യുന്നതിന് നിങ്ങളുടെ വാലറ്റ് പാസ്ഫ്രെയ്സ് ആവശ്യമാണ്.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>വാലറ്റ് ഡീക്രിപ്റ്റ് ചെയ്യുക</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>പാസ്ഫ്രെയ്സ് മാറ്റുക</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>പഴയ രഹസ്യപദപ്രയോഗം പുതിയ രഹസ്യപദപ്രയോഗം വാലറ്റിൽ നൽകുക.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>വാലറ്റ് എൻക്രിപ്ഷൻ സ്ഥിരീകരിക്കുക</translation>
+ </message>
+ <message>
+ <source>Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
+ <translation>മുന്നറിയിപ്പ്: നിങ്ങളുടെ വാലറ്റ് എൻക്രിപ്റ്റ് ചെയ്ത് പാസ്ഫ്രെയ്സ് നഷ്ടപ്പെടുകയാണെങ്കിൽ, നിങ്ങളുടെ എല്ലാ ബിറ്റ്കൊയിനുകളും നഷ്ടപ്പെടും!</translation>
+ </message>
+ </context>
+<context>
+ <name>BanTableModel</name>
+ </context>
+<context>
+ <name>BitcoinGUI</name>
+ </context>
+<context>
+ <name>CoinControlDialog</name>
+ <message>
+ <source>(no label)</source>
+ <translation>(ലേബൽ ഇല്ല)</translation>
+ </message>
+ </context>
+<context>
+ <name>EditAddressDialog</name>
+ </context>
+<context>
+ <name>FreespaceChecker</name>
+ </context>
+<context>
+ <name>HelpMessageDialog</name>
+ </context>
+<context>
+ <name>Intro</name>
+ </context>
+<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
+ <name>OpenURIDialog</name>
+ </context>
+<context>
+ <name>OptionsDialog</name>
+ </context>
+<context>
+ <name>OverviewPage</name>
+ </context>
+<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
+ <name>PeerTableModel</name>
+ </context>
+<context>
+ <name>QObject</name>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
+ <name>RPCConsole</name>
+ </context>
+<context>
+ <name>ReceiveCoinsDialog</name>
+ </context>
+<context>
+ <name>ReceiveRequestDialog</name>
+ <message>
+ <source>Address</source>
+ <translation>വിലാസം</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>ലേബൽ</translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>ലേബൽ</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(ലേബൽ ഇല്ല)</translation>
+ </message>
+ </context>
+<context>
+ <name>SendCoinsDialog</name>
+ <message>
+ <source>(no label)</source>
+ <translation>(ലേബൽ ഇല്ല)</translation>
+ </message>
+</context>
+<context>
+ <name>SendCoinsEntry</name>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
+ <name>ShutdownWindow</name>
+ </context>
+<context>
+ <name>SignVerifyMessageDialog</name>
+ </context>
+<context>
+ <name>SplashScreen</name>
+ </context>
+<context>
+ <name>TrafficGraphWidget</name>
+ </context>
+<context>
+ <name>TransactionDesc</name>
+ </context>
+<context>
+ <name>TransactionDescDialog</name>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>ലേബൽ</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(ലേബൽ ഇല്ല)</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>കോമയാൽ വേർതിരിച്ച ഫയൽ (* .csv)</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>ലേബൽ</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>വിലാസം</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>കയറ്റുമതി പരാജയപ്പെട്ടു</translation>
+ </message>
+ </context>
+<context>
+ <name>UnitDisplayStatusBarControl</name>
+ </context>
+<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp; കയറ്റുമതി ചെയ്യുക</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>നിലവിലെ ടാബിൽ ഒരു ഫയലിൽ ഡാറ്റ എക്സ്പോർട്ട് ചെയ്യുക</translation>
+ </message>
+ </context>
+<context>
+ <name>bitcoin-core</name>
+ </context>
+</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_nl.ts b/src/qt/locale/bitcoin_nl.ts
index b495eeaf51..152d89f878 100644
--- a/src/qt/locale/bitcoin_nl.ts
+++ b/src/qt/locale/bitcoin_nl.ts
@@ -3200,6 +3200,10 @@ Notitie: Omdat de vergoeding per byte wordt gerekend, zal een vergoeding van "10
<translation>Waarschuwing: Fout bij het lezen van %s! Alle sleutels zijn in goede orde uitgelezen, maar transactiedata of adresboeklemma's zouden kunnen ontbreken of fouten bevatten.</translation>
</message>
<message>
+ <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source>
+ <translation>Groepeer outputs per adres, alles of niets selecterend, in plaats van per output. Privacy wordt verbeterd omdat een adres slechts één keer wordt gebruikt (tenzij iemand ernaar stuurt na ermee te betalen), maar kan resulteren in iets hogere fees, als gevolg van suboptimale coin selectie ten gevolge van de toegevoegde beperking (standaard: %u)</translation>
+ </message>
+ <message>
<source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source>
<translation>Waarschuwing: Controleer dat de datum en tijd van uw computer correct zijn ingesteld! Bij een onjuist ingestelde klok zal %s niet goed werken.</translation>
</message>
@@ -3340,6 +3344,10 @@ Notitie: Omdat de vergoeding per byte wordt gerekend, zal een vergoeding van "10
<translation>Ongeldig bedrag voor -fallbackfee=&lt;bedrag&gt;: '%s'</translation>
</message>
<message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation>Opgegeven blocks map "%s" bestaat niet.</translation>
+ </message>
+ <message>
<source>Upgrading txindex database</source>
<translation>Upgraden txindex database</translation>
</message>
@@ -3492,12 +3500,6 @@ Notitie: Omdat de vergoeding per byte wordt gerekend, zal een vergoeding van "10
<translation>Opgegeven -walletdir "%s" is geen map</translation>
</message>
<message>
- <source>Specified blocks directory "%s" does not exist.
-</source>
- <translation>Opgegeven blocks map "%s" bestaat niet.
-</translation>
- </message>
- <message>
<source>The transaction amount is too small to pay the fee</source>
<translation>Het transactiebedrag is te klein om transactiekosten in rekening te brengen</translation>
</message>
diff --git a/src/qt/locale/bitcoin_pl.ts b/src/qt/locale/bitcoin_pl.ts
index 0026841975..03474f4df5 100644
--- a/src/qt/locale/bitcoin_pl.ts
+++ b/src/qt/locale/bitcoin_pl.ts
@@ -3342,6 +3342,11 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>Nieprawidłowa kwota dla -fallbackfee=&lt;amount&gt;: '%s'</translation>
</message>
<message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation>Podany folder bloków "%s" nie istnieje.
+</translation>
+ </message>
+ <message>
<source>Upgrading txindex database</source>
<translation>Aktualizowanie bazy txindex</translation>
</message>
@@ -3494,12 +3499,6 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>Podany -walletdir "%s" nie jest katalogiem</translation>
</message>
<message>
- <source>Specified blocks directory "%s" does not exist.
-</source>
- <translation>Podany folder bloków "%s" nie istnieje.
-</translation>
- </message>
- <message>
<source>The transaction amount is too small to pay the fee</source>
<translation>Zbyt niska kwota transakcji by zapłacić opłatę</translation>
</message>
diff --git a/src/qt/locale/bitcoin_pt_BR.ts b/src/qt/locale/bitcoin_pt_BR.ts
index 3877fee25d..9fa0f88ac3 100644
--- a/src/qt/locale/bitcoin_pt_BR.ts
+++ b/src/qt/locale/bitcoin_pt_BR.ts
@@ -3,7 +3,7 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation>Clique com o botão direito para editar o endereço ou rótulo</translation>
+ <translation>Clique com o botão direito para editar o endereço ou rótulo </translation>
</message>
<message>
<source>Create a new address</source>
@@ -3336,6 +3336,11 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por
<translation>Quantidade inválida para -fallbackfee=&lt;amount&gt;: '%s'</translation>
</message>
<message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation>
+Diretório de blocos especificados "%s" não existe.</translation>
+ </message>
+ <message>
<source>Upgrading txindex database</source>
<translation>Atualizando banco de dados txindex</translation>
</message>
@@ -3488,12 +3493,6 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por
<translation>O -walletdir "%s" especificado não é um diretório</translation>
</message>
<message>
- <source>Specified blocks directory "%s" does not exist.
-</source>
- <translation>O diretório de blocos especificado "%s" não existe.
-</translation>
- </message>
- <message>
<source>The transaction amount is too small to pay the fee</source>
<translation>A quantidade da transação é pequena demais para pagar a taxa</translation>
</message>
diff --git a/src/qt/locale/bitcoin_pt_PT.ts b/src/qt/locale/bitcoin_pt_PT.ts
index 48068409be..d203c490e9 100644
--- a/src/qt/locale/bitcoin_pt_PT.ts
+++ b/src/qt/locale/bitcoin_pt_PT.ts
@@ -71,7 +71,7 @@
</message>
<message>
<source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source>
- <translation>Estes são os seus endereços Bitcoin para receber pagamentos. É recomendado que utilize um endereço novo para cada transacção.</translation>
+ <translation>Estes são os seus endereços Bitcoin para receber pagamentos. É recomendado que utilize um endereço novo para cada transação.</translation>
</message>
<message>
<source>&amp;Copy Address</source>
@@ -189,7 +189,7 @@
</message>
<message>
<source>%1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
- <translation>%1 irá agora ser fechado para terminar o processo de encriptação. Recorde que a encriptação da sua carteira não protegerá totalmente os seus bitcoins de serem roubados por programas maliciosos que infectem o seu computador.</translation>
+ <translation>%1 irá agora ser fechado para terminar o processo de encriptação. Recorde que a encriptação da sua carteira não protegerá totalmente os seus bitcoins de serem roubados por programas maliciosos que infetem o seu computador.</translation>
</message>
<message>
<source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
@@ -780,7 +780,7 @@
<name>FreespaceChecker</name>
<message>
<source>A new data directory will be created.</source>
- <translation>Será criada uma nova diretoria de dados.</translation>
+ <translation>Será criada uma nova pasta de dados.</translation>
</message>
<message>
<source>name</source>
@@ -792,11 +792,11 @@
</message>
<message>
<source>Path already exists, and is not a directory.</source>
- <translation>O caminho já existe, e este não é uma pasta.</translation>
+ <translation>O caminho já existe, e não é uma pasta.</translation>
</message>
<message>
<source>Cannot create data directory here.</source>
- <translation>Não é possível criar aqui uma diretoria de dados.</translation>
+ <translation>Não é possível criar aqui uma pasta de dados.</translation>
</message>
</context>
<context>
@@ -854,11 +854,11 @@
</message>
<message>
<source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
- <translation>No mínimo %1 GB de dados irão ser armazenados neste diretório. </translation>
+ <translation>No mínimo %1 GB de dados irão ser armazenados nesta pasta. </translation>
</message>
<message>
<source>Approximately %1 GB of data will be stored in this directory.</source>
- <translation>Aproximadamente %1 GB de dados irão ser guardados nesta directoria. </translation>
+ <translation>Aproximadamente %1 GB de dados irão ser guardados nesta pasta. </translation>
</message>
<message>
<source>%1 will download and store a copy of the Bitcoin block chain.</source>
@@ -866,7 +866,7 @@
</message>
<message>
<source>The wallet will also be stored in this directory.</source>
- <translation>A carteira também será guardada nesta directoria.</translation>
+ <translation>A carteira também será guardada nesta pasta.</translation>
</message>
<message>
<source>Error: Specified data directory "%1" cannot be created.</source>
@@ -1024,7 +1024,7 @@
</message>
<message>
<source>Open the %1 configuration file from the working directory.</source>
- <translation>Abrir o ficheiro de configuração %1 da directoria aberta.</translation>
+ <translation>Abrir o ficheiro de configuração %1 da pasta aberta.</translation>
</message>
<message>
<source>Open Configuration File</source>
@@ -1100,11 +1100,11 @@
</message>
<message>
<source>&amp;Port:</source>
- <translation>&amp;Porto:</translation>
+ <translation>&amp;Porta:</translation>
</message>
<message>
<source>Port of the proxy (e.g. 9050)</source>
- <translation>Porto do proxy (p.ex. 9050)</translation>
+ <translation>Porta do proxy (por ex. 9050)</translation>
</message>
<message>
<source>Used for reaching peers via:</source>
@@ -1235,7 +1235,7 @@
</message>
<message>
<source>Watch-only:</source>
- <translation>Modo-verificação:</translation>
+ <translation>Apenas vigiar:</translation>
</message>
<message>
<source>Available:</source>
@@ -1263,7 +1263,7 @@
</message>
<message>
<source>Balances</source>
- <translation>Balanços</translation>
+ <translation>Saldos</translation>
</message>
<message>
<source>Total:</source>
@@ -1271,11 +1271,11 @@
</message>
<message>
<source>Your current total balance</source>
- <translation>O seu saldo total actual</translation>
+ <translation>O seu saldo total atual</translation>
</message>
<message>
<source>Your current balance in watch-only addresses</source>
- <translation>O seu balanço atual em endereços de apenas observação</translation>
+ <translation>O seu balanço atual em endereços de apenas vigiar</translation>
</message>
<message>
<source>Spendable:</source>
@@ -1287,15 +1287,15 @@
</message>
<message>
<source>Unconfirmed transactions to watch-only addresses</source>
- <translation>Transações não confirmadas para endereços modo-verificação</translation>
+ <translation>Transações não confirmadas para endereços de apenas vigiar</translation>
</message>
<message>
<source>Mined balance in watch-only addresses that has not yet matured</source>
- <translation>Saldo minado ainda não disponivél de endereços modo-verificação</translation>
+ <translation>Saldo minado ainda não disponível de endereços de apenas vigiar</translation>
</message>
<message>
<source>Current total balance in watch-only addresses</source>
- <translation>Saldo disponivél em enderços modo-verificação</translation>
+ <translation>Saldo disponível em endereços de apenas vigiar</translation>
</message>
</context>
<context>
@@ -1326,7 +1326,7 @@
</message>
<message>
<source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
- <translation>URI não foi lido correctamente! Isto pode ser causado por um endereço Bitcoin inválido ou por parâmetros URI malformados.</translation>
+ <translation>URI não foi lido corretamente! Isto pode ser causado por um endereço Bitcoin inválido ou por parâmetros URI malformados.</translation>
</message>
<message>
<source>Payment request file handling</source>
@@ -1428,7 +1428,7 @@
</message>
<message>
<source>Enter a Bitcoin address (e.g. %1)</source>
- <translation>Entre um endereço Bitcoin (ex. %1)</translation>
+ <translation>Introduza um endereço Bitcoin (ex. %1)</translation>
</message>
<message>
<source>%1 d</source>
@@ -1519,7 +1519,7 @@
</message>
<message>
<source>Error: Specified data directory "%1" does not exist.</source>
- <translation>Erro: Pasta de dados especificada "%1" não existe.</translation>
+ <translation>Erro: a pasta de dados especificada "%1" não existe.</translation>
</message>
<message>
<source>Error: Cannot parse configuration file: %1.</source>
@@ -1601,7 +1601,7 @@
</message>
<message>
<source>Current number of blocks</source>
- <translation>Número actual de blocos</translation>
+ <translation>Número atual de blocos</translation>
</message>
<message>
<source>Memory Pool</source>
@@ -1609,7 +1609,7 @@
</message>
<message>
<source>Current number of transactions</source>
- <translation>Número actual de transacções</translation>
+ <translation>Número atual de transações</translation>
</message>
<message>
<source>Memory usage</source>
@@ -1653,7 +1653,7 @@
</message>
<message>
<source>Direction</source>
- <translation>Direcção</translation>
+ <translation>Direção</translation>
</message>
<message>
<source>Version</source>
@@ -1677,7 +1677,7 @@
</message>
<message>
<source>Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</source>
- <translation>Abrir o ficheiro de registo de depuração %1 da pasta de dados actual. Isto pode demorar alguns segundos para ficheiros de registo maiores.</translation>
+ <translation>Abrir o ficheiro de registo de depuração %1 da pasta de dados atual. Isto pode demorar alguns segundos para ficheiros de registo maiores.</translation>
</message>
<message>
<source>Decrease font size</source>
@@ -1701,11 +1701,11 @@
</message>
<message>
<source>Last Send</source>
- <translation>Ultimo Envio</translation>
+ <translation>Último Envio</translation>
</message>
<message>
<source>Last Receive</source>
- <translation>Ultimo Recebimento</translation>
+ <translation>Último Recebimento</translation>
</message>
<message>
<source>Ping Time</source>
@@ -1809,7 +1809,7 @@
</message>
<message>
<source>WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.</source>
- <translation>AVISO: Burlões têm estado activos, dizendo a utilizadores para digitar comandos aqui, roubando assim os conteúdos das suas carteiras. Não utilize esta consola sem perceber perfeitamente as ramificações de um comando.</translation>
+ <translation>AVISO: alguns burlões têm estado ativos, dizendo a utilizadores para digitarem comandos aqui, roubando assim os conteúdos das suas carteiras. Não utilize esta consola sem perceber perfeitamente as ramificações de um comando.</translation>
</message>
<message>
<source>Network activity disabled</source>
@@ -1896,7 +1896,7 @@
</message>
<message>
<source>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</source>
- <translation>Endereços nativos SegWit (também conhecidos como Bech32 ou BIP-173) reduzem as taxas da sua transação mais tarde e oferecem melhor protecção contra erros, mas carteiras antigas não os suportam. Quando não selecionado, um endereço compatível com carteiras antigas irá ser criado em vez.</translation>
+ <translation>Endereços nativos SegWit (também conhecidos como Bech32 ou BIP-173) reduzem as taxas da sua transação mais tarde e oferecem melhor proteção contra erros, mas carteiras antigas não os suportam. Quando não selecionado, um endereço compatível com carteiras antigas irá ser criado em vez.</translation>
</message>
<message>
<source>Generate native segwit (Bech32) address</source>
@@ -1912,7 +1912,7 @@
</message>
<message>
<source>Show the selected request (does the same as double clicking an entry)</source>
- <translation>Mostrar o pedido seleccionado (faz o mesmo que clicar 2 vezes numa entrada)</translation>
+ <translation>Mostrar o pedido selecionado (faz o mesmo que clicar 2 vezes numa entrada)</translation>
</message>
<message>
<source>Show</source>
@@ -1920,7 +1920,7 @@
</message>
<message>
<source>Remove the selected entries from the list</source>
- <translation>Remover as entradas seleccionadas da lista</translation>
+ <translation>Remover as entradas selecionadas da lista</translation>
</message>
<message>
<source>Remove</source>
@@ -2113,7 +2113,7 @@
</message>
<message>
<source>Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks. But be aware that this can end up in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source>
- <translation>Pode pagar somente a taxa minima desde que haja um volume de transações inferior ao espaço nos blocos. No entanto tenha em atenção que esta opção poderá acabar em uma transação nunca confirmada assim que os pedidos de transações excedam a capacidade de processamento da rede.</translation>
+ <translation>Pode pagar somente a taxa mínima desde que haja um volume de transações inferior ao espaço nos blocos. No entanto tenha em atenção que esta opção poderá acabar em uma transação nunca confirmada assim que os pedidos de transações excedam a capacidade de processamento da rede.</translation>
</message>
<message>
<source>(read the tooltip)</source>
@@ -2125,7 +2125,7 @@
</message>
<message>
<source>Custom:</source>
- <translation>Uso:</translation>
+ <translation>Personalizado:</translation>
</message>
<message>
<source>(Smart fee not initialized yet. This usually takes a few blocks...)</source>
@@ -2442,7 +2442,7 @@
</message>
<message>
<source>Copy the current signature to the system clipboard</source>
- <translation>Copiar a assinatura actual para a área de transferência</translation>
+ <translation>Copiar a assinatura atual para a área de transferência</translation>
</message>
<message>
<source>Sign the message to prove you own this Bitcoin address</source>
@@ -2466,7 +2466,7 @@
</message>
<message>
<source>Enter the receiver's address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction!</source>
- <translation>Introduza o endereço de assinatura, mensagem (assegure-se que copia quebras de linha, espaços, tabulações, etc. exactamente) e assinatura abaixo para verificar a mensagem. Tenha atenção para não ler mais na assinatura do que o que estiver na mensagem assinada, para evitar ser enganado por um atacante que se encontre entre si e quem assinou a mensagem.</translation>
+ <translation>Introduza o endereço de assinatura, mensagem (assegure-se que copia quebras de linha, espaços, tabulações, etc. exatamente) e assinatura abaixo para verificar a mensagem. Tenha atenção para não ler mais na assinatura do que o que estiver na mensagem assinada, para evitar ser enganado por um atacante que se encontre entre si e quem assinou a mensagem.</translation>
</message>
<message>
<source>The Bitcoin address the message was signed with</source>
@@ -2615,7 +2615,7 @@
</message>
<message>
<source>watch-only</source>
- <translation>vigiar apenas</translation>
+ <translation>apenas vigiar</translation>
</message>
<message>
<source>label</source>
@@ -2793,7 +2793,7 @@
</message>
<message>
<source>watch-only</source>
- <translation>vigiar apenas</translation>
+ <translation>apenas vigiar</translation>
</message>
<message>
<source>(n/a)</source>
@@ -2817,7 +2817,7 @@
</message>
<message>
<source>Whether or not a watch-only address is involved in this transaction.</source>
- <translation>Se um endereço de monitoração está ou não envolvido nesta transação.</translation>
+ <translation>Se um endereço de apenas vigiar está ou não envolvido nesta transação.</translation>
</message>
<message>
<source>User-defined intent/purpose of the transaction.</source>
@@ -2940,7 +2940,7 @@
</message>
<message>
<source>Watch-only</source>
- <translation>Vigiar apenas</translation>
+ <translation>Apenas vigiar</translation>
</message>
<message>
<source>Date</source>
@@ -3118,6 +3118,10 @@
<translation>Os programadores de %s</translation>
</message>
<message>
+ <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source>
+ <translation>Não foi possível obter o bloqueio de escrita no da pasta de dados %s. %s provavelmente já está a ser executado.</translation>
+ </message>
+ <message>
<source>Cannot provide specific connections and have addrman find outgoing connections at the same.</source>
<translation>Não é possível fornecer conexões específicas e ter o addrman a procurar conexões de saída ao mesmo tempo.</translation>
</message>
@@ -3131,7 +3135,7 @@
</message>
<message>
<source>The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct</source>
- <translation>A base de dados de blocos contém um bloco que aparenta ser do futuro. Isto pode ser causado por uma data incorrecta definida no seu computador. Reconstrua apenas a base de dados de blocos caso tenha a certeza de que a data e hora do seu computador estão correctos.</translation>
+ <translation>A base de dados de blocos contém um bloco que aparenta ser do futuro. Isto pode ser causado por uma data incorreta definida no seu computador. Reconstrua apenas a base de dados de blocos caso tenha a certeza de que a data e hora do seu computador estão corretos.</translation>
</message>
<message>
<source>This is the transaction fee you may discard if change is smaller than dust at this level</source>
@@ -3167,7 +3171,7 @@
</message>
<message>
<source>Corrupted block database detected</source>
- <translation>Cadeia de blocos corrompida detectada</translation>
+ <translation>Detetada cadeia de blocos corrompida</translation>
</message>
<message>
<source>Do you want to rebuild the block database now?</source>
@@ -3234,6 +3238,11 @@
<translation>Valor inválido para -fallbackfee=&lt;amount&gt;: '%s'</translation>
</message>
<message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation>
+A pasta de blocos especificados "%s" não existe.</translation>
+ </message>
+ <message>
<source>Loading P2P addresses...</source>
<translation>A carregar endereços de P2P...</translation>
</message>
@@ -3307,7 +3316,7 @@
</message>
<message>
<source>The transaction amount is too small to send after the fee has been deducted</source>
- <translation>O montante da transacção é demasiado baixo após a dedução da taxa</translation>
+ <translation>O montante da transação é demasiado baixo após a dedução da taxa</translation>
</message>
<message>
<source>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source>
@@ -3346,8 +3355,12 @@
<translation>Falhou assinatura da transação</translation>
</message>
<message>
+ <source>Specified -walletdir "%s" is not a directory</source>
+ <translation>O -walletdir "%s" especificado não é uma pasta</translation>
+ </message>
+ <message>
<source>The transaction amount is too small to pay the fee</source>
- <translation>O montante da transacção é demasiado baixo para pagar a taxa</translation>
+ <translation>O montante da transação é demasiado baixo para pagar a taxa</translation>
</message>
<message>
<source>This is experimental software.</source>
@@ -3359,7 +3372,7 @@
</message>
<message>
<source>Transaction too large for fee policy</source>
- <translation>Transacção demasiado grande para a política de taxas</translation>
+ <translation>Transação demasiado grande para a política de taxas</translation>
</message>
<message>
<source>Transaction too large</source>
@@ -3378,6 +3391,10 @@
<translation>A verificar a(s) carteira(s)...</translation>
</message>
<message>
+ <source>Wallet %s resides outside wallet directory %s</source>
+ <translation>A carteira %s reside fora da pasta da carteira %s</translation>
+ </message>
+ <message>
<source>Warning</source>
<translation>Aviso</translation>
</message>
@@ -3391,7 +3408,7 @@
</message>
<message>
<source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
- <translation>-maxtxfee está definido com um valor muito alto! Taxas desta magnitude podem ser pagas numa única transacção.</translation>
+ <translation>-maxtxfee está definido com um valor muito alto! Taxas desta magnitude podem ser pagas numa única transação.</translation>
</message>
<message>
<source>This is the transaction fee you may pay when fee estimates are not available.</source>
@@ -3454,6 +3471,10 @@
<translation>Fundos insuficientes</translation>
</message>
<message>
+ <source>Cannot write to data directory '%s'; check permissions.</source>
+ <translation>Não foi possível escrever na pasta de dados '%s': verifique as permissões.</translation>
+ </message>
+ <message>
<source>Loading block index...</source>
<translation>A carregar o índice de blocos...</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ro.ts b/src/qt/locale/bitcoin_ro.ts
index b5a478c611..bef83e831a 100644
--- a/src/qt/locale/bitcoin_ro.ts
+++ b/src/qt/locale/bitcoin_ro.ts
@@ -501,6 +501,10 @@
<translation>Schimbă:</translation>
</message>
<message>
+ <source>(un)select all</source>
+ <translation>(de)selectează tot</translation>
+ </message>
+ <message>
<source>Tree mode</source>
<translation>Mod arbore</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ro_RO.ts b/src/qt/locale/bitcoin_ro_RO.ts
index 3ca1878067..e5b17cfbad 100644
--- a/src/qt/locale/bitcoin_ro_RO.ts
+++ b/src/qt/locale/bitcoin_ro_RO.ts
@@ -23,7 +23,7 @@
</message>
<message>
<source>C&amp;lose</source>
- <translation>Închide</translation>
+ <translation>Î&amp;nchide</translation>
</message>
<message>
<source>Delete the currently selected address from the list</source>
@@ -326,6 +326,14 @@
<translation>Deschide &amp;URI...</translation>
</message>
<message>
+ <source>Wallet:</source>
+ <translation>Portofel:</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation>portofel implicit</translation>
+ </message>
+ <message>
<source>Click to disable network activity.</source>
<translation>Click pentru a opri activitatea retelei.</translation>
</message>
@@ -346,6 +354,10 @@
<translation>Se reindexează blocurile pe disc...</translation>
</message>
<message>
+ <source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
+ <translation>Proxy este&lt;b&gt;activat&lt;/b&gt;:%1</translation>
+ </message>
+ <message>
<source>Send coins to a Bitcoin address</source>
<translation>Trimite monede către o adresă Bitcoin</translation>
</message>
@@ -514,6 +526,12 @@
</translation>
</message>
<message>
+ <source>Wallet: %1
+</source>
+ <translation>Portofel: %1
+</translation>
+ </message>
+ <message>
<source>Type: %1
</source>
<translation>Tip: %1
@@ -746,6 +764,14 @@
<translation>Adresa introdusă "%1" nu este o adresă Bitcoin validă.</translation>
</message>
<message>
+ <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source>
+ <translation>Adresa "%1" exista deja ca si adresa de primire cu eticheta "%2" si deci nu poate fi folosita ca si adresa de trimitere.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book with label "%2".</source>
+ <translation>Adresa introdusa "%1" este deja in lista de adrese cu eticheta "%2"</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation>Portofelul nu a putut fi deblocat.</translation>
</message>
@@ -1024,6 +1050,22 @@
<translation>Reţea</translation>
</message>
<message>
+ <source>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</source>
+ <translation>Dezactiveaza unele caracteristici avansate insa toate blocurile vor fi validate pe deplin. Inversarea acestei setari necesita re-descarcarea intregului blockchain. Utilizarea reala a discului poate fi ceva mai mare.</translation>
+ </message>
+ <message>
+ <source>Prune &amp;block storage to</source>
+ <translation>Reductie &amp;block storage la </translation>
+ </message>
+ <message>
+ <source>GB</source>
+ <translation>GB</translation>
+ </message>
+ <message>
+ <source>Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation> Inversarea acestei setari necesita re-descarcarea intregului blockchain.</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation>(0 = automat, &lt;0 = lasă atîtea nuclee libere)</translation>
</message>
@@ -1290,6 +1332,10 @@
<translation>Gestionare URI</translation>
</message>
<message>
+ <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source>
+ <translation>'bitcoin://' nu este un URI valid. Folositi 'bitcoin:' in loc.</translation>
+ </message>
+ <message>
<source>Payment request fetch URL is invalid: %1</source>
<translation>URL-ul cererii de plată preluat nu este valid: %1</translation>
</message>
@@ -1487,10 +1533,18 @@
<context>
<name>QObject::QObject</name>
<message>
+ <source>Error parsing command line arguments: %1.</source>
+ <translation>Eroare la analiza argumentelor linie de comanda: %1</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
<translation>Eroare: Directorul de date specificat "%1" nu există.</translation>
</message>
<message>
+ <source>Error: Cannot parse configuration file: %1.</source>
+ <translation>Eroare: Nu se poate analiza fişierul de configuraţie: %1.</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation>Eroare: %1</translation>
</message>
@@ -1581,6 +1635,14 @@
<translation>Memorie folosită</translation>
</message>
<message>
+ <source>Wallet: </source>
+ <translation>Portofel:</translation>
+ </message>
+ <message>
+ <source>(none)</source>
+ <translation>(nimic)</translation>
+ </message>
+ <message>
<source>&amp;Reset</source>
<translation>&amp;Resetare</translation>
</message>
@@ -1749,6 +1811,10 @@
<translation>&amp;Unban</translation>
</message>
<message>
+ <source>default wallet</source>
+ <translation>portofel implicit</translation>
+ </message>
+ <message>
<source>Welcome to the %1 RPC console.</source>
<translation>Bun venit la consola %1 RPC.</translation>
</message>
@@ -1773,6 +1839,14 @@
<translation>Activitatea retelei a fost oprita.</translation>
</message>
<message>
+ <source>Executing command without any wallet</source>
+ <translation>Executarea comenzii fara nici un portofel.</translation>
+ </message>
+ <message>
+ <source>Executing command using "%1" wallet</source>
+ <translation>Executarea comenzii folosind portofelul "%1"</translation>
+ </message>
+ <message>
<source>(node id: %1)</source>
<translation>(node id: %1)</translation>
</message>
@@ -2057,6 +2131,14 @@
<translation>inchide setarile de taxare</translation>
</message>
<message>
+ <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size.
+
+Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis per kB" for a transaction size of 500 bytes (half of 1 kB) would ultimately yield a fee of only 50 satoshis.</source>
+ <translation>Specificati o taxa anume pe kB (1000 byte) din marimea virtuala a tranzactiei.
+
+Nota: Cum taxa este calculata per byte, o taxa de "100 satoshi per kB" pentru o tranzactie de 500 byte (jumatate de kB) va produce o taxa de doar 50 satoshi.</translation>
+ </message>
+ <message>
<source>per kilobyte</source>
<translation>per kilooctet</translation>
</message>
@@ -2177,6 +2259,14 @@
<translation>Puteti creste taxa mai tarziu (semnaleaza Replace-By-Fee, BIP-125).</translation>
</message>
<message>
+ <source>from wallet %1</source>
+ <translation>de la portofelul %1</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction.</source>
+ <translation>Va rugam sa revizuiti tranzactia.</translation>
+ </message>
+ <message>
<source>Transaction fee</source>
<translation>Taxă tranzacţie</translation>
</message>
@@ -2185,6 +2275,10 @@
<translation>Nu se semnalizeaza Replace-By-Fee, BIP-125</translation>
</message>
<message>
+ <source>Total Amount</source>
+ <translation>Suma totală</translation>
+ </message>
+ <message>
<source>Confirm send coins</source>
<translation>Confirmă trimiterea monedelor</translation>
</message>
@@ -2638,6 +2732,10 @@
<translation>Dimensiune totala tranzacţie</translation>
</message>
<message>
+ <source>Transaction virtual size</source>
+ <translation>Dimensiune virtuala a tranzactiei</translation>
+ </message>
+ <message>
<source>Output index</source>
<translation>Index debit</translation>
</message>
@@ -3038,7 +3136,11 @@
<source>The wallet data was successfully saved to %1.</source>
<translation>Datele portofelului s-au salvat cu succes la %1.</translation>
</message>
- </context>
+ <message>
+ <source>Cancel</source>
+ <translation>Anulare</translation>
+ </message>
+</context>
<context>
<name>bitcoin-core</name>
<message>
@@ -3090,6 +3192,10 @@
<translation>Eroare la citirea %s! Toate cheile sînt citite corect, dar datele tranzactiei sau anumite intrări din agenda sînt incorecte sau lipsesc.</translation>
</message>
<message>
+ <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source>
+ <translation>Gruparea a iesirilor pe adrese, selectand totul sau nimic, in loc de selectarea bazata per-iesire. Intimitatea este imbunatatita deoarece o adresa este folosita doar o singura data (cu exceptia cuiva care trimite catre aceiasi adresa dup ce cheltuie din ea), dar se pot genera taxe mai mari deoarece poate rezulta o selectare suboptimala a monedelor datorata limitarii impuse (implicit: %u)</translation>
+ </message>
+ <message>
<source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source>
<translation>Vă rugăm verificaţi dacă data/timpul calculatorului dvs. sînt corecte! Dacă ceasul calcultorului este gresit, %s nu va funcţiona corect.</translation>
</message>
@@ -3174,6 +3280,10 @@
<translation>Eroare la încărcarea %s</translation>
</message>
<message>
+ <source>Error loading %s: Private keys can only be disabled during creation</source>
+ <translation>Eroare la incarcarea %s: Cheile private pot fi dezactivate doar in momentul crearii</translation>
+ </message>
+ <message>
<source>Error loading %s: Wallet corrupted</source>
<translation>Eroare la încărcarea %s: Portofel corupt</translation>
</message>
@@ -3226,6 +3336,14 @@
<translation>Suma nevalidă pentru -fallbackfee=&lt;amount&gt;: '%s'</translation>
</message>
<message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation>Directorul de blocuri "%s" specificat nu exista.</translation>
+ </message>
+ <message>
+ <source>Upgrading txindex database</source>
+ <translation>Actualizarea bazei de date txindex</translation>
+ </message>
+ <message>
<source>Loading P2P addresses...</source>
<translation>Încărcare adrese P2P...</translation>
</message>
@@ -3266,6 +3384,10 @@
<translation>Nu se poate efectua legatura la %s pe acest computer. %s probabil ruleaza deja.</translation>
</message>
<message>
+ <source>Unable to generate keys</source>
+ <translation>Nu s-au putut genera cheile</translation>
+ </message>
+ <message>
<source>Unsupported argument -benchmark ignored, use -debug=bench.</source>
<translation>Argumentul nesuportat -benchmark este ignorat, folositi debug=bench.</translation>
</message>
@@ -3494,6 +3616,22 @@
<translation>Fonduri insuficiente</translation>
</message>
<message>
+ <source>Can't generate a change-address key. Private keys are disabled for this wallet.</source>
+ <translation>Nu se poate genera o adresa pentru rest. Cheile private sunt dezactivate pentru acest portofel.</translation>
+ </message>
+ <message>
+ <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
+ <translation>Estimarea taxei a esuat. Taxa implicita este dezactivata. Asteptati cateva blocuri, sau activati -fallbackfee.</translation>
+ </message>
+ <message>
+ <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source>
+ <translation>Atentie: S-au detectat chei private in portofelul {%s} cu cheile private dezactivate</translation>
+ </message>
+ <message>
+ <source>Cannot write to data directory '%s'; check permissions.</source>
+ <translation>Nu se poate scrie in directorul de date '%s"; verificati permisiunile.</translation>
+ </message>
+ <message>
<source>Loading block index...</source>
<translation>Încărcare index bloc...</translation>
</message>
@@ -3518,4 +3656,4 @@
<translation>Eroare</translation>
</message>
</context>
-</TS> \ No newline at end of file
+</TS>
diff --git a/src/qt/locale/bitcoin_ru.ts b/src/qt/locale/bitcoin_ru.ts
index 0cbee61fc5..9c81fe9cdb 100644
--- a/src/qt/locale/bitcoin_ru.ts
+++ b/src/qt/locale/bitcoin_ru.ts
@@ -337,6 +337,10 @@
</context>
<context>
<name>ReceiveCoinsDialog</name>
+ <message>
+ <source>Clear</source>
+ <translation>Очистить</translation>
+ </message>
</context>
<context>
<name>ReceiveRequestDialog</name>
diff --git a/src/qt/locale/bitcoin_ru_RU.ts b/src/qt/locale/bitcoin_ru_RU.ts
index ea30f39969..430f2e4191 100644
--- a/src/qt/locale/bitcoin_ru_RU.ts
+++ b/src/qt/locale/bitcoin_ru_RU.ts
@@ -15,7 +15,7 @@
</message>
<message>
<source>Copy the currently selected address to the system clipboard</source>
- <translation>Скопировать текущий выбранный адрес в буфер обмена системы</translation>
+ <translation>Скопировать выбранный адрес в буфер обмена</translation>
</message>
<message>
<source>&amp;Copy</source>
@@ -55,7 +55,7 @@
</message>
<message>
<source>C&amp;hoose</source>
- <translation>В&amp;ыбрать</translation>
+ <translation>Выбрать</translation>
</message>
<message>
<source>Sending addresses</source>
@@ -67,11 +67,11 @@
</message>
<message>
<source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
- <translation>Это ваши биткойн адреса для отправки платежа. Всегда проверяйте сумму и адрес получателя перед отправкой платежа.</translation>
+ <translation>Это ваши Bitcoin адреса для отправки платежа. Всегда проверяйте сумму и адрес получателя перед отправкой платежа.</translation>
</message>
<message>
<source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source>
- <translation>Это ваши биткойн адреса для получения платежей. Настоятельно рекомендуем использовать новые адреса для получения каждой транзакции.</translation>
+ <translation>Это ваши Bitcoin адреса для получения платежей. Настоятельно рекомендуем использовать новые адреса для получения каждой транзакции.</translation>
</message>
<message>
<source>&amp;Copy Address</source>
@@ -137,19 +137,19 @@
</message>
<message>
<source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;ten or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
- <translation>Введите новый пароль для кошелька.&lt;br/&gt; Пожалуйста используйте пароль из &lt;b&gt; десяти или более произвольных символов&lt;/b&gt;, или &lt;b&gt;восемь или боле слов&lt;/b&gt;</translation>
+ <translation>Введите новый пароль для кошелька.&lt;br/&gt; Пожалуйста используйте пароль из &lt;b&gt; десяти или более произвольных символов&lt;/b&gt;, или &lt;b&gt;восемь или более слов&lt;/b&gt;</translation>
</message>
<message>
<source>Encrypt wallet</source>
- <translation>Зашифровать бумажник</translation>
+ <translation>Зашифровать кошелек</translation>
</message>
<message>
<source>This operation needs your wallet passphrase to unlock the wallet.</source>
- <translation>Эта операция требует вашего пароля для разблокировки бумажника</translation>
+ <translation>Эта операция требует вашего пароля для разблокировки кошелька</translation>
</message>
<message>
<source>Unlock wallet</source>
- <translation>Разблокировать бумажник</translation>
+ <translation>Разблокировать кошелек</translation>
</message>
<message>
<source>This operation needs your wallet passphrase to decrypt the wallet.</source>
@@ -157,7 +157,7 @@
</message>
<message>
<source>Decrypt wallet</source>
- <translation>Расшифровать бумажник</translation>
+ <translation>Расшифровать кошелек</translation>
</message>
<message>
<source>Change passphrase</source>
@@ -165,11 +165,11 @@
</message>
<message>
<source>Enter the old passphrase and new passphrase to the wallet.</source>
- <translation>Введите старый и новый пароль для кошелька.</translation>
+ <translation>Введите старый и новый пароль к кошельку.</translation>
</message>
<message>
<source>Confirm wallet encryption</source>
- <translation>Подтвердите шифрование бумажника</translation>
+ <translation>Подтвердите шифрование кошелька</translation>
</message>
<message>
<source>Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
@@ -181,7 +181,7 @@
</message>
<message>
<source>Wallet encrypted</source>
- <translation>Бумажник зашифрован</translation>
+ <translation>Кошелек зашифрован</translation>
</message>
<message>
<source>%1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
@@ -200,6 +200,10 @@
<translation>Шифрование кошелька завершилось неудачно из-за внутренней ошибки. Ваш кошелек не был зашифрован.</translation>
</message>
<message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>Пароли не совпадают.</translation>
+ </message>
+ <message>
<source>Wallet unlock failed</source>
<translation>Ошибка разблокировки кошелька</translation>
</message>
@@ -251,7 +255,7 @@
</message>
<message>
<source>Show general overview of wallet</source>
- <translation>Отобразить общий обзор кошелька</translation>
+ <translation>Отобразить главное окно кошелька</translation>
</message>
<message>
<source>&amp;Transactions</source>
@@ -299,7 +303,7 @@
</message>
<message>
<source>&amp;Backup Wallet...</source>
- <translation>&amp;Создать резервную копию бумажника</translation>
+ <translation>&amp;Создать резервную копию кошелька</translation>
</message>
<message>
<source>&amp;Change Passphrase...</source>
@@ -346,6 +350,10 @@
<translation>Реиндексация блоков на диске...</translation>
</message>
<message>
+ <source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
+ <translation>Прокси &lt;b&gt;включен&lt;/b&gt;: %1</translation>
+ </message>
+ <message>
<source>Send coins to a Bitcoin address</source>
<translation>Послать средства на биткойн адрес</translation>
</message>
@@ -422,6 +430,10 @@
<translation>Панель вкладок</translation>
</message>
<message>
+ <source>Request payments (generates QR codes and bitcoin: URIs)</source>
+ <translation>Запросить платеж</translation>
+ </message>
+ <message>
<source>Show the list of used sending addresses and labels</source>
<translation>Показать список использованных адресов и меток получателей</translation>
</message>
@@ -437,6 +449,10 @@
<source>&amp;Command-line options</source>
<translation>Опции командной строки</translation>
</message>
+ <message numerus="yes">
+ <source>%n active connection(s) to Bitcoin network</source>
+ <translation><numerusform>%n активное подключение к сети Bitcoin</numerusform><numerusform>%n активных подключения к сети Bitcoin</numerusform><numerusform>%n активных подключений к сети Bitcoin</numerusform><numerusform>%n активных подключений к сети Bitcoin</numerusform></translation>
+ </message>
<message>
<source>Indexing blocks on disk...</source>
<translation>Выполняется индексирование блоков на диске...</translation>
@@ -445,6 +461,10 @@
<source>Processing blocks on disk...</source>
<translation>Выполняется обработка блоков на диске...</translation>
</message>
+ <message numerus="yes">
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation><numerusform>Обработан %n блок истории транзакций.</numerusform><numerusform>Обработано %n блока истории транзакций.</numerusform><numerusform>Обработано %n блоков истории транзакций.</numerusform><numerusform>Обработано %n блоков истории транзакций.</numerusform></translation>
+ </message>
<message>
<source>%1 behind</source>
<translation>Выполнено %1</translation>
@@ -573,6 +593,10 @@
<translation>Сдача:</translation>
</message>
<message>
+ <source>(un)select all</source>
+ <translation>Выбрать все</translation>
+ </message>
+ <message>
<source>Tree mode</source>
<translation>Режим дерева</translation>
</message>
@@ -696,10 +720,18 @@
<translation>Изменить адрес отправки</translation>
</message>
<message>
+ <source>The entered address "%1" is already in the address book with label "%2".</source>
+ <translation>Введённый адрес "%1" уже существует в адресной книге с меткой "%2".</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation>Невозможно разблокировать кошелек.</translation>
</message>
- </context>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Произошла ошибка при генерации нового ключа.</translation>
+ </message>
+</context>
<context>
<name>FreespaceChecker</name>
<message>
@@ -711,6 +743,14 @@
<translation>имя</translation>
</message>
<message>
+ <source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
+ <translation>Каталог уже существует. Добавьте %1, если хотите создать новую директорию здесь.</translation>
+ </message>
+ <message>
+ <source>Path already exists, and is not a directory.</source>
+ <translation>Данный путь уже существует и это не каталог.</translation>
+ </message>
+ <message>
<source>Cannot create data directory here.</source>
<translation>Невозможно создать директорию данных здесь.</translation>
</message>
@@ -741,6 +781,14 @@
<translation>Добро пожаловать в %1.</translation>
</message>
<message>
+ <source>As this is the first time the program is launched, you can choose where %1 will store its data.</source>
+ <translation>Поскольку программа запущена впервые, вы должны указать где %1 будет хранить данные.</translation>
+ </message>
+ <message>
+ <source>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</source>
+ <translation>Если вы указали сокращать объём хранимого блокчейна (pruning), все исторические данные все равно должны быть скачаны и обработаны, но впоследствии они будут удалены для экономии места на диске.</translation>
+ </message>
+ <message>
<source>Use the default data directory</source>
<translation>Использовать стандартную директорию данных</translation>
</message>
@@ -866,6 +914,10 @@
<translation>IP-адрес прокси-сервера (к примеру, IPv4: 127.0.0.1 / IPv6: ::1)</translation>
</message>
<message>
+ <source>Use separate SOCKS&amp;5 proxy to reach peers via Tor hidden services:</source>
+ <translation>Использовать отдельные SOCKS&amp;5 прокси для подключения к пирам через Tor hidden services:</translation>
+ </message>
+ <message>
<source>Hide the icon from the system tray.</source>
<translation>Убрать значок с области уведомлений.</translation>
</message>
@@ -890,10 +942,18 @@
<translation>&amp;Сеть</translation>
</message>
<message>
+ <source>Prune &amp;block storage to</source>
+ <translation>Сокращать объём хранимого блокчейна до</translation>
+ </message>
+ <message>
<source>GB</source>
<translation>ГБ</translation>
</message>
<message>
+ <source>Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation>Отмена этой настройки требует повторного скачивания всего блокчейна.</translation>
+ </message>
+ <message>
<source>W&amp;allet</source>
<translation>К&amp;ошелёк</translation>
</message>
@@ -902,6 +962,10 @@
<translation>Эксперт</translation>
</message>
<message>
+ <source>Enable coin &amp;control features</source>
+ <translation>Включить возможность &amp;управления монетами</translation>
+ </message>
+ <message>
<source>&amp;Spend unconfirmed change</source>
<translation>&amp;Тратить неподтвержденную сдачу</translation>
</message>
@@ -938,6 +1002,10 @@
<translation>Порт прокси: (напр. 9050)</translation>
</message>
<message>
+ <source>Used for reaching peers via:</source>
+ <translation>Используется для подключения к пирам по:</translation>
+ </message>
+ <message>
<source>IPv4</source>
<translation>IPv4</translation>
</message>
@@ -950,6 +1018,10 @@
<translation>Tor</translation>
</message>
<message>
+ <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source>
+ <translation>Соединяться к Биткоин-сети через отдельные SOCKS5 прокси через Tor hidden services:</translation>
+ </message>
+ <message>
<source>&amp;Window</source>
<translation>&amp;Окно</translation>
</message>
@@ -958,6 +1030,10 @@
<translation>Отобразить только значок в области уведомлений после сворачивания окна.</translation>
</message>
<message>
+ <source>M&amp;inimize on close</source>
+ <translation>З&amp;акрыть при сворачивании</translation>
+ </message>
+ <message>
<source>User Interface &amp;language:</source>
<translation>Язык пользовательского интерфейса:</translation>
</message>
@@ -1021,6 +1097,14 @@
<translation>Форма</translation>
</message>
<message>
+ <source>Watch-only:</source>
+ <translation>Только просмотр:</translation>
+ </message>
+ <message>
+ <source>Available:</source>
+ <translation>Доступно:</translation>
+ </message>
+ <message>
<source>Your current spendable balance</source>
<translation>Ваш доступный баланс</translation>
</message>
@@ -1064,6 +1148,10 @@
<translation>Ошибка запроса платежа</translation>
</message>
<message>
+ <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source>
+ <translation>'bitcoin://' не верный URI. Используйте 'bitcoin:' вместо этого.</translation>
+ </message>
+ <message>
<source>Invalid payment address %1</source>
<translation>Неверный адрес %1</translation>
</message>
@@ -1235,6 +1323,10 @@
<translation>Количество соединений</translation>
</message>
<message>
+ <source>Block chain</source>
+ <translation>Блокчейн</translation>
+ </message>
+ <message>
<source>Current number of blocks</source>
<translation>Текущее количество блоков</translation>
</message>
@@ -1275,6 +1367,10 @@
<translation>Заблокированные пиры</translation>
</message>
<message>
+ <source>Select a peer to view detailed information.</source>
+ <translation>Выберите пира для просмотра детальной информации.</translation>
+ </message>
+ <message>
<source>Version</source>
<translation>Версия</translation>
</message>
@@ -1406,6 +1502,14 @@
<translation>Отчистить</translation>
</message>
<message>
+ <source>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</source>
+ <translation>"Родные" segwit адреса (Bech32 или BIP-173) в дальнейшем уменьшат комиссии ваших транзакций и предоставят улучшенную защиту от опечаток, однако старые кошельки не поддерживают эти адреса. Если не выбрано, будет создан совместимый со старыми кошелёк.</translation>
+ </message>
+ <message>
+ <source>Generate native segwit (Bech32) address</source>
+ <translation>Создать "родной" segwit (Bech32) адрес </translation>
+ </message>
+ <message>
<source>Requested payments history</source>
<translation>История платежных запросов</translation>
</message>
@@ -1639,6 +1743,10 @@
<translation>Баланс:</translation>
</message>
<message>
+ <source>Confirm the send action</source>
+ <translation>Подтвердить отправку</translation>
+ </message>
+ <message>
<source>Copy quantity</source>
<translation>Копировать количество</translation>
</message>
@@ -1707,6 +1815,14 @@
<translation>Истекло время ожидания запроса платежа</translation>
</message>
<message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>Предупреждение: Неверный Bitcoin адрес</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation>Предупреждение: Неизвестный адрес сдачи</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(нет метки)</translation>
</message>
@@ -2240,6 +2356,10 @@
<translation>Предупреждение</translation>
</message>
<message>
+ <source>Starting network threads...</source>
+ <translation>Запуск сетевых потоков...</translation>
+ </message>
+ <message>
<source>This is the minimum transaction fee you pay on every transaction.</source>
<translation>Это минимальная комиссия, которую вы платите для любой транзакции</translation>
</message>
diff --git a/src/qt/locale/bitcoin_sk.ts b/src/qt/locale/bitcoin_sk.ts
index 86c5c8abda..89ed850da3 100644
--- a/src/qt/locale/bitcoin_sk.ts
+++ b/src/qt/locale/bitcoin_sk.ts
@@ -768,6 +768,14 @@
<translation>Vložená adresa "%1" nieje platnou adresou Bitcoin.</translation>
</message>
<message>
+ <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source>
+ <translation>Adresa "%1" už existuje ako prijímacia adresa s označením "%2" .Nemôže tak byť pridaná ako odosielacia adresa.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book with label "%2".</source>
+ <translation>Zadaná adresa "%1" sa už nachádza v zozname adries s označením "%2".</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation>Nepodarilo sa odomknúť peňaženku.</translation>
</message>
@@ -1046,10 +1054,22 @@
<translation>&amp;Sieť</translation>
</message>
<message>
+ <source>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</source>
+ <translation>Zakáže niektoré pokročilé funkcie, ale všetky bloky budú stále plne overené. Obnovenie tohto nastavenia vyžaduje opätovné prevzatie celého blockchainu. Skutočné využitie disku môže byť o niečo vyššie.</translation>
+ </message>
+ <message>
+ <source>Prune &amp;block storage to</source>
+ <translation>Redukovať priestor pre &amp;bloky na</translation>
+ </message>
+ <message>
<source>GB</source>
<translation>GB</translation>
</message>
<message>
+ <source>Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation>Obnovenie tohto nastavenia vyžaduje opätovné prevzatie celého blockchainu.</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation>(0 = auto, &lt;0 = nechať toľko jadier voľných)</translation>
</message>
@@ -1517,10 +1537,18 @@
<context>
<name>QObject::QObject</name>
<message>
+ <source>Error parsing command line arguments: %1.</source>
+ <translation>Chyba pri spracovaní argumentov príkazového riadku: %1.</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
<translation>Chyba: Zadaný adresár pre dáta „%1“ neexistuje.</translation>
</message>
<message>
+ <source>Error: Cannot parse configuration file: %1.</source>
+ <translation>Chyba: Konfiguračný súbor sa nedá spracovať: %1.</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation>Chyba: %1</translation>
</message>
@@ -1816,6 +1844,14 @@
<translation>Sieťová aktivita zakázaná</translation>
</message>
<message>
+ <source>Executing command without any wallet</source>
+ <translation>Príkaz sa vykonáva bez peňaženky</translation>
+ </message>
+ <message>
+ <source>Executing command using "%1" wallet</source>
+ <translation>Príkaz sa vykonáva s použitím peňaženky "%1"</translation>
+ </message>
+ <message>
<source>(node id: %1)</source>
<translation>(ID uzlu: %1)</translation>
</message>
@@ -2100,6 +2136,14 @@
<translation>zbaliť nastavenia poplatkov</translation>
</message>
<message>
+ <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size.
+
+Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis per kB" for a transaction size of 500 bytes (half of 1 kB) would ultimately yield a fee of only 50 satoshis.</source>
+ <translation>Špecifikujte vlastný poplatok za kB (1000 bajtov) virtuálnej veľkosti transakcie.
+
+Poznámka: Keďže poplatok je počítaný za bajt, poplatok o hodnote "100 satoshi za kB" a veľkosti transakcie 500 bajtov (polovica z 1 kB) by stál len 50 satoshi.</translation>
+ </message>
+ <message>
<source>per kilobyte</source>
<translation>za kilobajt</translation>
</message>
@@ -2224,6 +2268,10 @@
<translation>z peňaženky %1</translation>
</message>
<message>
+ <source>Please, review your transaction.</source>
+ <translation>Prosím, skontrolujte Vašu transakciu.</translation>
+ </message>
+ <message>
<source>Transaction fee</source>
<translation>Transakčný poplatok</translation>
</message>
@@ -2689,6 +2737,10 @@
<translation>Celková veľkosť transakcie</translation>
</message>
<message>
+ <source>Transaction virtual size</source>
+ <translation>Virtuálna veľkosť transakcie</translation>
+ </message>
+ <message>
<source>Output index</source>
<translation>Index výstupu</translation>
</message>
@@ -3149,6 +3201,10 @@
<translation>Nastala chyba pri čítaní súboru %s! Všetkz kľúče sa prečítali správne, ale dáta o transakcíách alebo záznamy v adresári môžu chýbať alebo byť nesprávne.</translation>
</message>
<message>
+ <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source>
+ <translation>Zoskupenie výstupov podľa adresy, pri vybratí všetkých alebo žiadnych, namiesto vybratia na báze za výstup. Zlepší sa súkromie, keďže adresa je použitá len raz (pokiaľ nikto na túto adresu už nič nepošle po minutí), ale môže vyústiť v trochu väčšie poplatky keďže ne-optimalizovaný výber mincí môže vyústiť v pridané obmedzenia (predvolené: %u)</translation>
+ </message>
+ <message>
<source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source>
<translation>Prosím skontrolujte systémový čas a dátum. Keď je váš čas nesprávny, %s nebude fungovať správne.</translation>
</message>
@@ -3233,6 +3289,10 @@
<translation>Chyba načítania %s</translation>
</message>
<message>
+ <source>Error loading %s: Private keys can only be disabled during creation</source>
+ <translation>Chyba pri načítaní %s: Súkromné kľúče môžu byť zakázané len počas vytvárania</translation>
+ </message>
+ <message>
<source>Error loading %s: Wallet corrupted</source>
<translation>Chyba načítania %s: Peňaženka je poškodená</translation>
</message>
@@ -3285,6 +3345,10 @@
<translation>Neplatná suma pre -fallbackfee=&lt;amount&gt;: '%s'</translation>
</message>
<message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation>Zadaný adresár blokov "%s" neexistuje.</translation>
+ </message>
+ <message>
<source>Upgrading txindex database</source>
<translation>Inovuje sa txindex databáza</translation>
</message>
@@ -3437,12 +3501,6 @@
<translation>Uvedený -walletdir "%s" nie je priečinok</translation>
</message>
<message>
- <source>Specified blocks directory "%s" does not exist.
-</source>
- <translation>Uvedený priečinok s dátami "%s" neexistuje.
-</translation>
- </message>
- <message>
<source>The transaction amount is too small to pay the fee</source>
<translation>Suma transakcie je príliš malá na zaplatenie poplatku</translation>
</message>
@@ -3575,6 +3633,22 @@
<translation>Nedostatok prostriedkov</translation>
</message>
<message>
+ <source>Can't generate a change-address key. Private keys are disabled for this wallet.</source>
+ <translation>Nie je možné vygenerovať kľúč na zmenu adresy. Súkromné kľúče sú pre túto peňaženku zakázané.</translation>
+ </message>
+ <message>
+ <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use -upgradewallet=169900 or -upgradewallet with no version specified.</source>
+ <translation>Nie je možné vylepšiť peňaženku bez HD bez aktualizácie, ktorá podporuje delenie keypoolu. Použite prosím -upgradewallet=169900 alebo -upgradewallet bez špecifikovania verzie.</translation>
+ </message>
+ <message>
+ <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
+ <translation>Odhad poplatku sa nepodaril. Fallbackfee je zakázaný. Počkajte niekoľko blokov alebo povoľte -fallbackfee.</translation>
+ </message>
+ <message>
+ <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source>
+ <translation>Upozornenie: Boli zistené súkromné kľúče v peňaženke {%s} so zakázanými súkromnými kľúčmi.</translation>
+ </message>
+ <message>
<source>Loading block index...</source>
<translation>Načítavanie zoznamu blokov...</translation>
</message>
diff --git a/src/qt/locale/bitcoin_sl_SI.ts b/src/qt/locale/bitcoin_sl_SI.ts
index 91080a774a..08b00984c0 100644
--- a/src/qt/locale/bitcoin_sl_SI.ts
+++ b/src/qt/locale/bitcoin_sl_SI.ts
@@ -1874,6 +1874,10 @@
<translation>Brišem vse transakcije iz denarnice ...</translation>
</message>
<message>
+ <source>Transaction must have at least one recipient</source>
+ <translation>Transakcija mora imeti vsaj enega prejemnika.</translation>
+ </message>
+ <message>
<source>Unknown network specified in -onlynet: '%s'</source>
<translation>Neznano omrežje določeno v -onlynet: '%s'.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_sn.ts b/src/qt/locale/bitcoin_sn.ts
new file mode 100644
index 0000000000..895962cb45
--- /dev/null
+++ b/src/qt/locale/bitcoin_sn.ts
@@ -0,0 +1,367 @@
+<TS language="sn" version="2.1">
+<context>
+ <name>AddressBookPage</name>
+ <message>
+ <source>Create a new address</source>
+ <translation>Gadzira Kero Itsva</translation>
+ </message>
+ <message>
+ <source>&amp;New</source>
+ <translation>Itsva</translation>
+ </message>
+ <message>
+ <source>&amp;Copy</source>
+ <translation>&amp;Kopera</translation>
+ </message>
+ <message>
+ <source>C&amp;lose</source>
+ <translation>Vhara</translation>
+ </message>
+ <message>
+ <source>&amp;Delete</source>
+ <translation>Dzima</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Makero ekutumira</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Makero ekutambira</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>Kopera Kero</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Gadzirisa</translation>
+ </message>
+ </context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Zita</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Kero</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(hapana zita)</translation>
+ </message>
+</context>
+<context>
+ <name>AskPassphraseDialog</name>
+ </context>
+<context>
+ <name>BanTableModel</name>
+ <message>
+ <source>Banned Until</source>
+ <translation>Wakavharirwa Kusvika</translation>
+ </message>
+</context>
+<context>
+ <name>BitcoinGUI</name>
+ <message>
+ <source>E&amp;xit</source>
+ <translation>Buda</translation>
+ </message>
+ <message>
+ <source>Quit application</source>
+ <translation>Vhara Application</translation>
+ </message>
+ <message>
+ <source>&amp;About %1</source>
+ <translation>&amp;Kuma %1</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation>Taridza ruzivo rwekuma %1</translation>
+ </message>
+ <message>
+ <source>Show information about Qt</source>
+ <translation>Taridza ruzivo rwe Qt</translation>
+ </message>
+ <message>
+ <source>&amp;Sending addresses...</source>
+ <translation>&amp;Makero ekutumira nawo</translation>
+ </message>
+ <message>
+ <source>&amp;Receiving addresses...</source>
+ <translation>&amp;Makero ekutambira nawo</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI...</source>
+ <translation>Vhura &amp;URI</translation>
+ </message>
+ <message>
+ <source>Bitcoin</source>
+ <translation>Bitcoin</translation>
+ </message>
+ <message>
+ <source>Wallet</source>
+ <translation>Chikwama</translation>
+ </message>
+ <message>
+ <source>&amp;Send</source>
+ <translation>&amp;Tumira</translation>
+ </message>
+ <message>
+ <source>&amp;Receive</source>
+ <translation>&amp;Tambira</translation>
+ </message>
+ <message>
+ <source>&amp;Show / Hide</source>
+ <translation>&amp;Taridza/Usataridza</translation>
+ </message>
+ <message>
+ <source>&amp;File</source>
+ <translation>&amp;Faira</translation>
+ </message>
+ <message>
+ <source>&amp;Help</source>
+ <translation>&amp;Rubatsiro</translation>
+ </message>
+ <message>
+ <source>%1 behind</source>
+ <translation>%1 kumashure</translation>
+ </message>
+ <message>
+ <source>Warning</source>
+ <translation>Hokoyo</translation>
+ </message>
+ <message>
+ <source>Information</source>
+ <translation>Ruzivo</translation>
+ </message>
+ </context>
+<context>
+ <name>CoinControlDialog</name>
+ <message>
+ <source>Amount</source>
+ <translation>Marii </translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Zuva</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(hapana zita)</translation>
+ </message>
+ </context>
+<context>
+ <name>EditAddressDialog</name>
+ </context>
+<context>
+ <name>FreespaceChecker</name>
+ </context>
+<context>
+ <name>HelpMessageDialog</name>
+ </context>
+<context>
+ <name>Intro</name>
+ <message>
+ <source>Bitcoin</source>
+ <translation>Bitcoin</translation>
+ </message>
+ </context>
+<context>
+ <name>ModalOverlay</name>
+ </context>
+<context>
+ <name>OpenURIDialog</name>
+ </context>
+<context>
+ <name>OptionsDialog</name>
+ </context>
+<context>
+ <name>OverviewPage</name>
+ </context>
+<context>
+ <name>PaymentServer</name>
+ </context>
+<context>
+ <name>PeerTableModel</name>
+ </context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>Amount</source>
+ <translation>Marii </translation>
+ </message>
+ <message>
+ <source>Enter a Bitcoin address (e.g. %1)</source>
+ <translation>Nyora kero ye Bitcoin (sekuti %1)</translation>
+ </message>
+ <message>
+ <source>%1 d</source>
+ <translation>%1 d</translation>
+ </message>
+ <message>
+ <source>%1 h</source>
+ <translation>%1 h</translation>
+ </message>
+ <message>
+ <source>%1 m</source>
+ <translation>%1 m</translation>
+ </message>
+ <message>
+ <source>%1 s</source>
+ <translation>%1 s</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>Hapana</translation>
+ </message>
+ <message>
+ <source>N/A</source>
+ <translation>Hapana </translation>
+ </message>
+ </context>
+<context>
+ <name>QObject::QObject</name>
+ </context>
+<context>
+ <name>QRImageWidget</name>
+ </context>
+<context>
+ <name>RPCConsole</name>
+ <message>
+ <source>N/A</source>
+ <translation>Hapana </translation>
+ </message>
+ </context>
+<context>
+ <name>ReceiveCoinsDialog</name>
+ </context>
+<context>
+ <name>ReceiveRequestDialog</name>
+ <message>
+ <source>Address</source>
+ <translation>Kero</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Marii </translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Zita</translation>
+ </message>
+ <message>
+ <source>Wallet</source>
+ <translation>Chikwama</translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Zuva</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Zita</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(hapana zita)</translation>
+ </message>
+ </context>
+<context>
+ <name>SendCoinsDialog</name>
+ <message>
+ <source>(no label)</source>
+ <translation>(hapana zita)</translation>
+ </message>
+</context>
+<context>
+ <name>SendCoinsEntry</name>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ </context>
+<context>
+ <name>ShutdownWindow</name>
+ </context>
+<context>
+ <name>SignVerifyMessageDialog</name>
+ </context>
+<context>
+ <name>SplashScreen</name>
+ </context>
+<context>
+ <name>TrafficGraphWidget</name>
+ </context>
+<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Date</source>
+ <translation>Zuva</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Marii </translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionDescDialog</name>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Zuva</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Zita</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(hapana zita)</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>Date</source>
+ <translation>Zuva</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Zita</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Kero</translation>
+ </message>
+ </context>
+<context>
+ <name>UnitDisplayStatusBarControl</name>
+ </context>
+<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ </context>
+<context>
+ <name>WalletView</name>
+ </context>
+<context>
+ <name>bitcoin-core</name>
+ <message>
+ <source>Information</source>
+ <translation>Ruzivo</translation>
+ </message>
+ <message>
+ <source>Warning</source>
+ <translation>Hokoyo</translation>
+ </message>
+ </context>
+</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_sv.ts b/src/qt/locale/bitcoin_sv.ts
index d0fcef9297..405cde3c99 100644
--- a/src/qt/locale/bitcoin_sv.ts
+++ b/src/qt/locale/bitcoin_sv.ts
@@ -327,6 +327,14 @@ Var vänlig och försök igen.</translation>
<translation>Öppna &amp;URI...</translation>
</message>
<message>
+ <source>Wallet:</source>
+ <translation>Plånbok:</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation>Standardplånbok</translation>
+ </message>
+ <message>
<source>Click to disable network activity.</source>
<translation>Klicka för att inaktivera nätverksaktivitet.</translation>
</message>
@@ -347,6 +355,10 @@ Var vänlig och försök igen.</translation>
<translation>Återindexerar block på disken...</translation>
</message>
<message>
+ <source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
+ <translation>Proxy är &lt;b&gt; aktiverad &lt;/b&gt;: %1</translation>
+ </message>
+ <message>
<source>Send coins to a Bitcoin address</source>
<translation>Skicka bitcoin till en Bitcoin-adress</translation>
</message>
@@ -515,6 +527,12 @@ Var vänlig och försök igen.</translation>
</translation>
</message>
<message>
+ <source>Wallet: %1
+</source>
+ <translation>Plånbok: %1
+</translation>
+ </message>
+ <message>
<source>Type: %1
</source>
<translation>Typ: %1
@@ -751,6 +769,14 @@ Var vänlig och försök igen.</translation>
<translation>Den angivna adressen "%1" är inte en giltig Bitcoin-adress.</translation>
</message>
<message>
+ <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source>
+ <translation>Adress "%1" finns redan som en mottagande adress med etikett "%2" och kan därför anges som utgående adress.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book with label "%2".</source>
+ <translation>Den angivna adressen "%1" finns redan i adressboken med etikett "%2".</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation>Kunde inte låsa upp plånboken.</translation>
</message>
@@ -824,6 +850,10 @@ Var vänlig och försök igen.</translation>
<translation>Denna första synkronisering är väldigt krävande, och kan påvisa hårdvaruproblem med din dator som tidigare inte visats sig. Varje gång du kör %1, kommer nerladdningen att fortsätta där den avslutades.</translation>
</message>
<message>
+ <source>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</source>
+ <translation>Om du valt att begränsa storleken på blockkedjan (pruning), måste historisk data fortfarande bli nedladdad och processerad, men kommer bli borttagen för att minimera hårddiskutrymme.</translation>
+ </message>
+ <message>
<source>Use the default data directory</source>
<translation>Använd den förvalda datakatalogen</translation>
</message>
@@ -1025,6 +1055,22 @@ Var vänlig och försök igen.</translation>
<translation>&amp;Nätverk</translation>
</message>
<message>
+ <source>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</source>
+ <translation>Stänger av en del avancerade funktioner, men samtliga block kommer fortfarande verifieras. Vid avstängning av denna inställning kommer den fullständiga blockkedjan behövas laddas ned igen. Det använda hårddiskutrymmet kan öka något.</translation>
+ </message>
+ <message>
+ <source>Prune &amp;block storage to</source>
+ <translation>Trim- &amp; block-utrymme till</translation>
+ </message>
+ <message>
+ <source>GB</source>
+ <translation>GB</translation>
+ </message>
+ <message>
+ <source>Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation>Vid avstängning av denna inställning kommer den fullständiga blockkedjan behövas laddas ned igen.</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation>(0 = auto, &lt;0 = lämna så många kärnor lediga)</translation>
</message>
@@ -1291,6 +1337,10 @@ Var vänlig och försök igen.</translation>
<translation>URI-hantering</translation>
</message>
<message>
+ <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source>
+ <translation>'bitcoin://' är inte en accepterad URI. Använd 'bitcoin:' istället.</translation>
+ </message>
+ <message>
<source>Payment request fetch URL is invalid: %1</source>
<translation>Hämtningsadressen för betalningsbegäran är ogiltig: %1</translation>
</message>
@@ -1488,10 +1538,18 @@ Var vänlig och försök igen.</translation>
<context>
<name>QObject::QObject</name>
<message>
+ <source>Error parsing command line arguments: %1.</source>
+ <translation>Kunde inte tolka argumentet: %1.</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
<translation>Fel: Angiven datakatalog "%1" finns inte.</translation>
</message>
<message>
+ <source>Error: Cannot parse configuration file: %1.</source>
+ <translation>Fel: Kan inte tolka konfigurationsfil: %1.</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation>Fel: %1</translation>
</message>
@@ -1582,6 +1640,14 @@ Var vänlig och försök igen.</translation>
<translation>Minnesåtgång</translation>
</message>
<message>
+ <source>Wallet: </source>
+ <translation>Plånbok:</translation>
+ </message>
+ <message>
+ <source>(none)</source>
+ <translation>(ingen)</translation>
+ </message>
+ <message>
<source>&amp;Reset</source>
<translation>&amp;Återställ</translation>
</message>
@@ -1750,6 +1816,10 @@ Var vänlig och försök igen.</translation>
<translation>&amp;Ta bort blockering</translation>
</message>
<message>
+ <source>default wallet</source>
+ <translation>Standardplånbok</translation>
+ </message>
+ <message>
<source>Welcome to the %1 RPC console.</source>
<translation>Välkommen till %1 RPC-konsolen.</translation>
</message>
@@ -1774,6 +1844,14 @@ Var vänlig och försök igen.</translation>
<translation>Nätverksaktivitet inaktiverad</translation>
</message>
<message>
+ <source>Executing command without any wallet</source>
+ <translation>Utför instruktion utan plånbok</translation>
+ </message>
+ <message>
+ <source>Executing command using "%1" wallet</source>
+ <translation>Utför instruktion med plånbok "%1"</translation>
+ </message>
+ <message>
<source>(node id: %1)</source>
<translation>(nod-id: %1)</translation>
</message>
@@ -1845,6 +1923,14 @@ Var vänlig och försök igen.</translation>
<translation>Rensa</translation>
</message>
<message>
+ <source>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</source>
+ <translation>Bech32-addresser (BIP-173) är billigare att spendera från och har bättre skytt mot skrivfel mot konstnaden att äldre plånböcker inte förstår dem. När inte valet är gjort kommer en address som är kompatibel med äldre plånböcker att skapas istället.</translation>
+ </message>
+ <message>
+ <source>Generate native segwit (Bech32) address</source>
+ <translation>Skapa Bech32-adress</translation>
+ </message>
+ <message>
<source>Requested payments history</source>
<translation>Historik för begärda betalningar</translation>
</message>
@@ -2050,6 +2136,14 @@ Var vänlig och försök igen.</translation>
<translation>Fäll ihop avgiftsinställningarna</translation>
</message>
<message>
+ <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size.
+
+Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis per kB" for a transaction size of 500 bytes (half of 1 kB) would ultimately yield a fee of only 50 satoshis.</source>
+ <translation>Ange en egen avgift per kB (1 000 bytes) av transaktionens virtuella storlek.
+
+Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut för en transaktion på 500 bytes (en halv kB) om man valt "100 satoshi per kB" som egen avgift.</translation>
+ </message>
+ <message>
<source>per kilobyte</source>
<translation>per kilobyte</translation>
</message>
@@ -2170,6 +2264,14 @@ Var vänlig och försök igen.</translation>
<translation>Du kan välja att höja avgiften senare (med ersättande avgift, BIP-125).</translation>
</message>
<message>
+ <source>from wallet %1</source>
+ <translation>från plånbok: %1</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction.</source>
+ <translation>Var vänlig se över din transaktion.</translation>
+ </message>
+ <message>
<source>Transaction fee</source>
<translation>Transaktionsavgift</translation>
</message>
@@ -2178,6 +2280,10 @@ Var vänlig och försök igen.</translation>
<translation>Använder inte ersättande avgift, BIP-125.</translation>
</message>
<message>
+ <source>Total Amount</source>
+ <translation>Totalt</translation>
+ </message>
+ <message>
<source>Confirm send coins</source>
<translation>Bekräfta att mynt ska skickas</translation>
</message>
@@ -2631,6 +2737,10 @@ Var vänlig och försök igen.</translation>
<translation>Transaktionens totala storlek</translation>
</message>
<message>
+ <source>Transaction virtual size</source>
+ <translation>Transaktionens virtuella storlek</translation>
+ </message>
+ <message>
<source>Output index</source>
<translation>Utmatningsindex</translation>
</message>
@@ -2965,6 +3075,10 @@ Var vänlig och försök igen.</translation>
<translation>Skicka Bitcoins</translation>
</message>
<message>
+ <source>Fee bump error</source>
+ <translation>Avgiftsökningsfel</translation>
+ </message>
+ <message>
<source>Increasing transaction fee failed</source>
<translation>Ökning av avgiften lyckades inte</translation>
</message>
@@ -3031,7 +3145,11 @@ Var vänlig och försök igen.</translation>
<source>The wallet data was successfully saved to %1.</source>
<translation>Plånbokens data sparades till %1.</translation>
</message>
- </context>
+ <message>
+ <source>Cancel</source>
+ <translation>Avbryt</translation>
+ </message>
+</context>
<context>
<name>bitcoin-core</name>
<message>
@@ -3075,10 +3193,18 @@ Var vänlig och försök igen.</translation>
<translation>Kan inte låsa data-mappen %s. %s körs förmodligen redan.</translation>
</message>
<message>
+ <source>Cannot provide specific connections and have addrman find outgoing connections at the same.</source>
+ <translation>Kan inte låta addrman hitta utgående uppkopplingar samtidigt som specifika uppkopplingar skapas</translation>
+ </message>
+ <message>
<source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source>
<translation>Fel vid läsning av %s! Alla nycklar lästes korrekt, men transaktionsdata eller poster i adressboken kanske saknas eller är felaktiga.</translation>
</message>
<message>
+ <source>Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)</source>
+ <translation>Gruppera utgående transaktioner med adress, där samtliga eller inga används, istället för att välja vid varje utgående transaktion. Detta ökar din integritet genom att en adress enbart används en gång (om inte någon skickar till den efteråt), men kan öka dina utgifter då valet av ingående transaktioner görs suboptimalt (standardvärde: %u)</translation>
+ </message>
+ <message>
<source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source>
<translation>Vänligen kolla så att din dators datum och tid är korrekt! Om din klocka går fel kommer %s inte att fungera korrekt.</translation>
</message>
@@ -3095,6 +3221,10 @@ Var vänlig och försök igen.</translation>
<translation>Detta är ett förhandstestbygge - använd på egen risk - använd inte för brytning eller handelsapplikationer</translation>
</message>
<message>
+ <source>This is the transaction fee you may discard if change is smaller than dust at this level</source>
+ <translation>Detta är transaktionsavgiften som slängs borta om det är mindre än damm på denna nivå</translation>
+ </message>
+ <message>
<source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source>
<translation>Kunde inte spela om block. Du kommer att behöva bygga om databasen med -reindex-chainstate.</translation>
</message>
@@ -3143,6 +3273,10 @@ Var vänlig och försök igen.</translation>
<translation>Vill du bygga om blockdatabasen nu?</translation>
</message>
<message>
+ <source>Error creating %s: You can't create non-HD wallets with this version.</source>
+ <translation>Fel vid skapande av %s: Det är inte möjligt att skapa icke-HD plånböcker med denna version.</translation>
+ </message>
+ <message>
<source>Error initializing block database</source>
<translation>Fel vid initiering av blockdatabasen</translation>
</message>
@@ -3155,6 +3289,10 @@ Var vänlig och försök igen.</translation>
<translation>Fel vid inläsning av %s</translation>
</message>
<message>
+ <source>Error loading %s: Private keys can only be disabled during creation</source>
+ <translation>Fel vid laddning av %s: Privata nycklar kan enbart bli avstängda vid skapelsen</translation>
+ </message>
+ <message>
<source>Error loading %s: Wallet corrupted</source>
<translation>Fel vid inläsning av %s: Plånboken är korrupt</translation>
</message>
@@ -3207,6 +3345,14 @@ Var vänlig och försök igen.</translation>
<translation>Ogiltigt belopp för -fallbackfee=&lt;amount&gt;: '%s'</translation>
</message>
<message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation>Den specificerade mappen för block "%s" existerar inte.</translation>
+ </message>
+ <message>
+ <source>Upgrading txindex database</source>
+ <translation>Uppgraderar databas för txindex</translation>
+ </message>
+ <message>
<source>Loading P2P addresses...</source>
<translation>Läser in P2P-adresser...</translation>
</message>
@@ -3247,6 +3393,10 @@ Var vänlig och försök igen.</translation>
<translation>Det går inte att binda till %s på den här datorn. %s är förmodligen redan igång.</translation>
</message>
<message>
+ <source>Unable to generate keys</source>
+ <translation>Lyckas inte generera nycklar</translation>
+ </message>
+ <message>
<source>Unsupported argument -benchmark ignored, use -debug=bench.</source>
<translation>Argumentet -benchmark stöds inte och ignoreras, använd -debug=bench.</translation>
</message>
@@ -3383,6 +3533,10 @@ Var vänlig och försök igen.</translation>
<translation>Verifierar plånbok(er)...</translation>
</message>
<message>
+ <source>Wallet %s resides outside wallet directory %s</source>
+ <translation>Plånbok %s är lokaliserad utanför plånboksmappen %s</translation>
+ </message>
+ <message>
<source>Warning</source>
<translation>Varning</translation>
</message>
@@ -3439,6 +3593,10 @@ Var vänlig och försök igen.</translation>
<translation>Fel vid inläsningen av plånbok %s. Dublett -wallet filnamn angavs.</translation>
</message>
<message>
+ <source>Keypool ran out, please call keypoolrefill first</source>
+ <translation>Nyckelpoolen har tagit slut, var vänlig anropa keypoolrefill först.</translation>
+ </message>
+ <message>
<source>Starting network threads...</source>
<translation>Startar nätverkstrådar...</translation>
</message>
@@ -3475,6 +3633,26 @@ Var vänlig och försök igen.</translation>
<translation>Otillräckligt med bitcoins</translation>
</message>
<message>
+ <source>Can't generate a change-address key. Private keys are disabled for this wallet.</source>
+ <translation>Kan inte generera en nyckel för växeladress. Privata nycklar är avstängda för denna plånboken.</translation>
+ </message>
+ <message>
+ <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use -upgradewallet=169900 or -upgradewallet with no version specified.</source>
+ <translation>Kan inte uppgradera till en icke-HD delad plånbok utan att uppgradera till att stödja nyckelpoolen innan splittring. Var vänlig använd -upgradewallet=169900 eller -upgradewallet utan version specificerad.</translation>
+ </message>
+ <message>
+ <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
+ <translation>Avgiftsestimering misslyckades. Fallbackfee är avstänt. Var vänlig vänta några block, alternativt aktivera -fallbackfee.</translation>
+ </message>
+ <message>
+ <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source>
+ <translation>Varning: Privata nycklar upptäckta i plånbok (%s) vilken har dessa inaktiverade</translation>
+ </message>
+ <message>
+ <source>Cannot write to data directory '%s'; check permissions.</source>
+ <translation>Kan inte skriva till mapp "%s", var vänlig se över filbehörigheter.</translation>
+ </message>
+ <message>
<source>Loading block index...</source>
<translation>Laddar blockindex...</translation>
</message>
diff --git a/src/qt/locale/bitcoin_szl.ts b/src/qt/locale/bitcoin_szl.ts
new file mode 100644
index 0000000000..9559df2a7d
--- /dev/null
+++ b/src/qt/locale/bitcoin_szl.ts
@@ -0,0 +1,2123 @@
+<TS language="szl" version="2.1">
+<context>
+ <name>AddressBookPage</name>
+ <message>
+ <source>Right-click to edit address or label</source>
+ <translation>Kliknij prawy knefel mysze, coby edytować adresã abo etyketã</translation>
+ </message>
+ <message>
+ <source>Create a new address</source>
+ <translation>Zrychtuj nowõ adresã</translation>
+ </message>
+ <message>
+ <source>&amp;New</source>
+ <translation>&amp;Nowy</translation>
+ </message>
+ <message>
+ <source>Copy the currently selected address to the system clipboard</source>
+ <translation>Skopiyruj aktualnie ôbranõ adresã do skrytki</translation>
+ </message>
+ <message>
+ <source>&amp;Copy</source>
+ <translation>&amp;Kopiyruj</translation>
+ </message>
+ <message>
+ <source>C&amp;lose</source>
+ <translation>&amp;Zawrzij</translation>
+ </message>
+ <message>
+ <source>Delete the currently selected address from the list</source>
+ <translation>Wychrōń zaznaczōnõ adresã z brify</translation>
+ </message>
+ <message>
+ <source>Enter address or label to search</source>
+ <translation>Wkludź adresã abo etyketã coby wyszukać</translation>
+ </message>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Eksportuj dane z aktywnyj szkarty do zbioru</translation>
+ </message>
+ <message>
+ <source>&amp;Export</source>
+ <translation>&amp;Eksportuj</translation>
+ </message>
+ <message>
+ <source>&amp;Delete</source>
+ <translation>&amp;Wychrōń</translation>
+ </message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Ôbier adresã, na kerõ chcesz posłać mōnety</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>Ôbier adresã, na kerõ chcesz dostać mōnety</translation>
+ </message>
+ <message>
+ <source>C&amp;hoose</source>
+ <translation>Ô&amp;bier</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>Adresy posyłaniŏ</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>Adresy ôdbiyraniŏ</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
+ <translation>Tukej sōm adresy Bitcoin na kere posyłŏsz płaty. Dycki wybaduj wielość i adresã ôdbiyrŏcza przed posłaniym mōnet.</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source>
+ <translation>Tukej sōm adresy Bitcoin do ôdbiyraniŏ płatōw. Zalycŏ sie używaniŏ nowych adres ôdbiorczych dlŏ kożdyj transakcyje.</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;Kopiyruj Adresã</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Kopiyruj &amp;Etyketã</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;Edytuj</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>Eksportuj wykŏz adres</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Zbiōr *.CSV (daty rozdzielane kōmami)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Eksportowanie niy podarziło sie</translation>
+ </message>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Przitrefiōł sie feler w czasie spamiyntowaniŏ brify adres do %1. Proszã sprōbować zaś.</translation>
+ </message>
+</context>
+<context>
+ <name>AddressTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>Etyketa</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adresa</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(chyba etykety)</translation>
+ </message>
+</context>
+<context>
+ <name>AskPassphraseDialog</name>
+ <message>
+ <source>Passphrase Dialog</source>
+ <translation>Ôkiynko Hasła</translation>
+ </message>
+ <message>
+ <source>Enter passphrase</source>
+ <translation>Wkludź hasło</translation>
+ </message>
+ <message>
+ <source>New passphrase</source>
+ <translation>Nowe hasło</translation>
+ </message>
+ <message>
+ <source>Repeat new passphrase</source>
+ <translation>Powtōrz nowe hasło</translation>
+ </message>
+ <message>
+ <source>Show password</source>
+ <translation>Pokŏż hasło</translation>
+ </message>
+ <message>
+ <source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;ten or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
+ <translation>Wkludź nowe hasło do portmanyja.&lt;br/&gt;Proszã używać hasła słożōnego z &lt;b&gt;10 abo wiyncyj losowych liter&lt;/b&gt; abo &lt;b&gt;8 abo wiyncyj słōw.&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Encrypt wallet</source>
+ <translation>Zaszyfruj portmanyj</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to unlock the wallet.</source>
+ <translation>Ta ôperacyjŏ wymŏgŏ hasła do portmanyja coby ôdszperować portmanyj.</translation>
+ </message>
+ <message>
+ <source>Unlock wallet</source>
+ <translation>Ôdszperuj portmanyj.</translation>
+ </message>
+ <message>
+ <source>This operation needs your wallet passphrase to decrypt the wallet.</source>
+ <translation>Ta ôperacyjŏ wymŏgŏ hasła do portmanyja coby ôdszyfrować portmanyj.</translation>
+ </message>
+ <message>
+ <source>Decrypt wallet</source>
+ <translation>Ôdszyfruj portmanyj</translation>
+ </message>
+ <message>
+ <source>Change passphrase</source>
+ <translation>Pōmiyń hasło</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Podej stare i nowe hasło do portmanyja.</translation>
+ </message>
+ <message>
+ <source>Confirm wallet encryption</source>
+ <translation>Przituplikuj szyfrowanie portmanyja</translation>
+ </message>
+ <message>
+ <source>Warning: If you encrypt your wallet and lose your passphrase, you will &lt;b&gt;LOSE ALL OF YOUR BITCOINS&lt;/b&gt;!</source>
+ <translation>Pozōr: jeźli zaszyfrujesz swōj portmanyj i stracisz hasło &lt;b&gt;STRACISZ WSZYJSKE SWOJE BITCOINY&lt;/b&gt;!</translation>
+ </message>
+ <message>
+ <source>Are you sure you wish to encrypt your wallet?</source>
+ <translation>Na isto chcesz zaszyfrować swōj portmanyj?</translation>
+ </message>
+ <message>
+ <source>Wallet encrypted</source>
+ <translation>Portmanyj zaszyfrowany</translation>
+ </message>
+ <message>
+ <source>%1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
+ <translation>%1 zawrzi sie coby dokōńczyć proces szyfrowaniŏ. Pamiyntej, iże szyfrowanie portmanyja ganc niy zabezpieczŏ Twojich bitcoinów przed chabiyniym bez wirusy abo trojany mogōnce zakażać Twōj kōmputer.</translation>
+ </message>
+ <message>
+ <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
+ <translation>WŎŻNE: Wszyjske wykōnane wczaśnij kopije zbioru portmanyja winny być umiyniōne na nowe, szyfrowane zbiory. Z powodōw bezpiyczyństwa, piyrwyjsze kopije niyszyfrowanych zbiorōw portmanyja stōnõ sie bezużyteczne jak ino zaczniesz używać nowego, szyfrowanego portmanyja.</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed</source>
+ <translation>Zaszyfrowanie portmanyja niy podarziło sie</translation>
+ </message>
+ <message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Zaszyfrowanie portmanyja niy podarziło sie bez wnyntrzny feler. Twōj portmanyj niy ôstoł zaszyfrowany.</translation>
+ </message>
+ <message>
+ <source>The supplied passphrases do not match.</source>
+ <translation>Podane hasła niy sōm take same.</translation>
+ </message>
+ <message>
+ <source>Wallet unlock failed</source>
+ <translation>Ôdszperowanie portmanyja niy podarziło sie</translation>
+ </message>
+ <message>
+ <source>The passphrase entered for the wallet decryption was incorrect.</source>
+ <translation>Wkludzōne hasło do ôdszyfrowaniŏ portmanyja je niynŏleżne.</translation>
+ </message>
+ <message>
+ <source>Wallet decryption failed</source>
+ <translation>Ôdszyfrowanie portmanyja niy podarziło sie</translation>
+ </message>
+ <message>
+ <source>Wallet passphrase was successfully changed.</source>
+ <translation>Hasło do portmanyja ôstało sprŏwnie pōmiyniōne.</translation>
+ </message>
+ <message>
+ <source>Warning: The Caps Lock key is on!</source>
+ <translation>Pozōr: Caps Lock je zapuszczōny!</translation>
+ </message>
+</context>
+<context>
+ <name>BanTableModel</name>
+ <message>
+ <source>IP/Netmask</source>
+ <translation>IP/Maska necu</translation>
+ </message>
+ <message>
+ <source>Banned Until</source>
+ <translation>Szpera do</translation>
+ </message>
+</context>
+<context>
+ <name>BitcoinGUI</name>
+ <message>
+ <source>Sign &amp;message...</source>
+ <translation>Szkryftnij &amp;wiadōmość</translation>
+ </message>
+ <message>
+ <source>Synchronizing with network...</source>
+ <translation>Synchrōnizacyjŏ z necym...</translation>
+ </message>
+ <message>
+ <source>&amp;Overview</source>
+ <translation>&amp;Podsumowanie</translation>
+ </message>
+ <message>
+ <source>Show general overview of wallet</source>
+ <translation>Pokazuje ôgōlny widok portmanyja</translation>
+ </message>
+ <message>
+ <source>&amp;Transactions</source>
+ <translation>&amp;Transakcyje</translation>
+ </message>
+ <message>
+ <source>Browse transaction history</source>
+ <translation>Przeglōndej historyjõ transakcyji</translation>
+ </message>
+ <message>
+ <source>E&amp;xit</source>
+ <translation>&amp;Zakōńcz</translation>
+ </message>
+ <message>
+ <source>Quit application</source>
+ <translation>Zawrzij aplikacyjõ</translation>
+ </message>
+ <message>
+ <source>&amp;About %1</source>
+ <translation>&amp;Ô %1</translation>
+ </message>
+ <message>
+ <source>Show information about %1</source>
+ <translation>Pokŏż informacyje ô %1</translation>
+ </message>
+ <message>
+ <source>About &amp;Qt</source>
+ <translation>Ô &amp;Qt</translation>
+ </message>
+ <message>
+ <source>Show information about Qt</source>
+ <translation>Pokŏż informacyje ô Qt</translation>
+ </message>
+ <message>
+ <source>&amp;Options...</source>
+ <translation>Ô&amp;pcyje...</translation>
+ </message>
+ <message>
+ <source>Modify configuration options for %1</source>
+ <translation>Zmiyń ôpcyje kōnfiguracyje dlŏ %1</translation>
+ </message>
+ <message>
+ <source>&amp;Encrypt Wallet...</source>
+ <translation>&amp;Zaszyfruj Portmanyj...</translation>
+ </message>
+ <message>
+ <source>&amp;Backup Wallet...</source>
+ <translation>Zrychtuj kopijõ ibrycznõ</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase...</source>
+ <translation>Pōmiyń &amp;hasło</translation>
+ </message>
+ <message>
+ <source>&amp;Sending addresses...</source>
+ <translation>&amp;Adresy posyłaniŏ</translation>
+ </message>
+ <message>
+ <source>&amp;Receiving addresses...</source>
+ <translation>Ad&amp;resy ôdbiyraniŏ</translation>
+ </message>
+ <message>
+ <source>Open &amp;URI...</source>
+ <translation>Ôdewrzij &amp;URI...</translation>
+ </message>
+ <message>
+ <source>Wallet:</source>
+ <translation>Portmanyj:</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation>wychodny portmanyj</translation>
+ </message>
+ <message>
+ <source>Click to disable network activity.</source>
+ <translation>Kliknij coby zastawić aktywność necowõ.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled.</source>
+ <translation>Aktywność necowŏ ôstała zastawiōnŏ.</translation>
+ </message>
+ <message>
+ <source>Click to enable network activity again.</source>
+ <translation>Kliknij, coby zaś zapuścić aktywność necowõ.</translation>
+ </message>
+ <message>
+ <source>Syncing Headers (%1%)...</source>
+ <translation>Synchrōnizowanie nŏgōwkōw (%1%)...</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk...</source>
+ <translation>Pōnowne indeksowanie blokōw na dysku...</translation>
+ </message>
+ <message>
+ <source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
+ <translation>Proxy je &lt;b&gt;zapuszczone&lt;/b&gt;: %1</translation>
+ </message>
+ <message>
+ <source>Send coins to a Bitcoin address</source>
+ <translation>Poślij mōnety na adresã Bitcoin</translation>
+ </message>
+ <message>
+ <source>Backup wallet to another location</source>
+ <translation>Ibryczny portmanyj w inkszyj lokalizacyje</translation>
+ </message>
+ <message>
+ <source>Change the passphrase used for wallet encryption</source>
+ <translation>Pōmiyń hasło użyte do szyfrowaniŏ portmanyja</translation>
+ </message>
+ <message>
+ <source>&amp;Debug window</source>
+ <translation>Ôkno &amp;debugowaniŏ</translation>
+ </message>
+ <message>
+ <source>Open debugging and diagnostic console</source>
+ <translation>Ôdewrzij kōnsolã debugowaniŏ i diagnostyki</translation>
+ </message>
+ <message>
+ <source>&amp;Verify message...</source>
+ <translation>&amp;Weryfikuj wiadōmość...</translation>
+ </message>
+ <message>
+ <source>Bitcoin</source>
+ <translation>Bitcoin</translation>
+ </message>
+ <message>
+ <source>Wallet</source>
+ <translation>Portmanyj</translation>
+ </message>
+ <message>
+ <source>&amp;Send</source>
+ <translation>&amp;Poślij</translation>
+ </message>
+ <message>
+ <source>&amp;Receive</source>
+ <translation>Ôd&amp;bier</translation>
+ </message>
+ <message>
+ <source>&amp;Show / Hide</source>
+ <translation>Pokŏż / &amp;Skryj</translation>
+ </message>
+ <message>
+ <source>Show or hide the main Window</source>
+ <translation>Pokazuje abo skrywŏ bazowe ôkno</translation>
+ </message>
+ <message>
+ <source>Encrypt the private keys that belong to your wallet</source>
+ <translation>Szyfruj klucze prywatne, kere sōm we twojim portmanyju</translation>
+ </message>
+ <message>
+ <source>Sign messages with your Bitcoin addresses to prove you own them</source>
+ <translation>Podpisz wiadōmości swojōm adresōm coby dowiyść jejich posiadanie</translation>
+ </message>
+ <message>
+ <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
+ <translation>Zweryfikuj wiadōmość, coby wejzdrzeć sie, iże ôstała podpisanŏ podanōm adresōm Bitcoin.</translation>
+ </message>
+ <message>
+ <source>&amp;File</source>
+ <translation>&amp;Zbiōr</translation>
+ </message>
+ <message>
+ <source>&amp;Settings</source>
+ <translation>&amp;Nasztalowania</translation>
+ </message>
+ <message>
+ <source>&amp;Help</source>
+ <translation>Pō&amp;moc</translation>
+ </message>
+ <message>
+ <source>Tabs toolbar</source>
+ <translation>Lajsta szkart</translation>
+ </message>
+ <message>
+ <source>Request payments (generates QR codes and bitcoin: URIs)</source>
+ <translation>Żōndej płatu (gyneruje kod QR jak tyż URI bitcoin:)</translation>
+ </message>
+ <message>
+ <source>Show the list of used sending addresses and labels</source>
+ <translation>Pokŏż wykŏz adres i etyket użytych do posyłaniŏ</translation>
+ </message>
+ <message>
+ <source>Show the list of used receiving addresses and labels</source>
+ <translation>Pokŏż wykŏz adres i etyket użytych do ôdbiyraniŏ</translation>
+ </message>
+ <message>
+ <source>Open a bitcoin: URI or payment request</source>
+ <translation>Ôdewrzij URI bitcoin: abo żōndanie płatu</translation>
+ </message>
+ <message>
+ <source>&amp;Command-line options</source>
+ <translation>Ôp&amp;cyje piski kōmynd</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n active connection(s) to Bitcoin network</source>
+ <translation><numerusform>%n aktywne połōnczynie do necu Bitcoin</numerusform><numerusform>%n aktywnych połōnczyń do necu Bitcoin</numerusform><numerusform>%n aktywnych skuplowań do necu Bitcoin</numerusform></translation>
+ </message>
+ <message>
+ <source>Indexing blocks on disk...</source>
+ <translation>Indeksowanie blokōw na dysku...</translation>
+ </message>
+ <message>
+ <source>Processing blocks on disk...</source>
+ <translation>Przetwŏrzanie blokōw na dysku...</translation>
+ </message>
+ <message numerus="yes">
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation><numerusform>Przetworzōno %n blok historyji transakcyji.</numerusform><numerusform>Przetworzōno %n blokōw historyji transakcyji.</numerusform><numerusform>Przetworzōno %n blokōw historyji transakcyji.</numerusform></translation>
+ </message>
+ <message>
+ <source>%1 behind</source>
+ <translation>%1 za</translation>
+ </message>
+ <message>
+ <source>Last received block was generated %1 ago.</source>
+ <translation>Ôstatni dostany blok ôstoł wygynerowany %1 tymu.</translation>
+ </message>
+ <message>
+ <source>Transactions after this will not yet be visible.</source>
+ <translation>Transakcyje po tym mōmyncie niy bydōm jeszcze widzialne.</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Feler</translation>
+ </message>
+ <message>
+ <source>Warning</source>
+ <translation>Pozōr</translation>
+ </message>
+ <message>
+ <source>Information</source>
+ <translation>Informacyjŏ</translation>
+ </message>
+ <message>
+ <source>Up to date</source>
+ <translation>Terŏźny</translation>
+ </message>
+ <message>
+ <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <translation>Pokŏż pōmoc %1 coby zobŏczyć wykŏz wszyjskich ôpcyji piski nakŏzań.</translation>
+ </message>
+ <message>
+ <source>%1 client</source>
+ <translation>%1 klijynt</translation>
+ </message>
+ <message>
+ <source>Catching up...</source>
+ <translation>Trwŏ synchrōnizacyjŏ...</translation>
+ </message>
+ <message>
+ <source>Date: %1
+</source>
+ <translation>Datōm: %1
+</translation>
+ </message>
+ <message>
+ <source>Amount: %1
+</source>
+ <translation>Kwota: %1
+</translation>
+ </message>
+ <message>
+ <source>Wallet: %1
+</source>
+ <translation>Portmanyj: %1
+</translation>
+ </message>
+ <message>
+ <source>Type: %1
+</source>
+ <translation>Zorta: %1
+</translation>
+ </message>
+ <message>
+ <source>Label: %1
+</source>
+ <translation>Etyketa: %1
+</translation>
+ </message>
+ <message>
+ <source>Address: %1
+</source>
+ <translation>Adresa: %1
+</translation>
+ </message>
+ <message>
+ <source>Sent transaction</source>
+ <translation>Transakcyjŏ wysłanŏ</translation>
+ </message>
+ <message>
+ <source>Incoming transaction</source>
+ <translation>Transakcyjŏ przichodzōncŏ</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
+ <translation>Gynerowanie kluczy HD je &lt;b&gt;zapuszczone&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
+ <translation>Gynerowanie kluczy HD je &lt;b&gt;zastawiōne&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
+ <translation>Portmanyj je &lt;b&gt;zaszyfrowany&lt;/b&gt; i terŏźnie &lt;b&gt;ôdszperowany&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
+ <translation>Portmanyj je &lt;b&gt;zaszyfrowany&lt;/b&gt; i terŏźnie &lt;b&gt;zaszperowany&lt;/b&gt;</translation>
+ </message>
+ <message>
+ <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
+ <translation>Przitrefiōł sie krytyczny feler. Bitcoin niy poradzi kōntynuować bezpiycznie i ôstanie zawrzity.</translation>
+ </message>
+</context>
+<context>
+ <name>CoinControlDialog</name>
+ <message>
+ <source>Coin Selection</source>
+ <translation>Ôbiōr mōnet</translation>
+ </message>
+ <message>
+ <source>Quantity:</source>
+ <translation>Wielość:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation>Bajtōw:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation>Kwota:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation>Ôpłŏcka:</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation>Sztaub:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation>Po ôpłŏcce:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation>Wydŏwka:</translation>
+ </message>
+ <message>
+ <source>(un)select all</source>
+ <translation>Zaznacz/Ôdznacz wszyjsko</translation>
+ </message>
+ <message>
+ <source>Tree mode</source>
+ <translation>Tryb strōma</translation>
+ </message>
+ <message>
+ <source>List mode</source>
+ <translation>Tryb wykŏzu</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Kwota</translation>
+ </message>
+ <message>
+ <source>Received with label</source>
+ <translation>Ôdebrane z etyketōm</translation>
+ </message>
+ <message>
+ <source>Received with address</source>
+ <translation>Ôdebrane z adresōm</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Datōm</translation>
+ </message>
+ <message>
+ <source>Confirmations</source>
+ <translation>Przituplowania</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Przituplowany</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Kopiyruj adresã</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopiyruj etyketã</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopiyruj kwotã</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Kopiyruj ID transakcyje</translation>
+ </message>
+ <message>
+ <source>Lock unspent</source>
+ <translation>Zaszperuj niywydane</translation>
+ </message>
+ <message>
+ <source>Unlock unspent</source>
+ <translation>Ôdszperuj niywydane</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Kopiyruj wielość</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Kopiyruj ôpłŏckã</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Kopiyruj wielość po ôpłŏcce</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Kopiyruj wielość bajtōw</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Kopiyruj sztaub</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Kopiyruj wydŏwkã</translation>
+ </message>
+ <message>
+ <source>(%1 locked)</source>
+ <translation>(%1 zaszperowane)</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>ja</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>niy</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
+ <translation>Ta etyketa stŏwŏ sie czyrwōnŏ jeźli keryś z ôdbiyrŏczy dostŏwŏ kwotã myńszõ aniżeli terŏźny prōg sztaubu.</translation>
+ </message>
+ <message>
+ <source>Can vary +/- %1 satoshi(s) per input.</source>
+ <translation>Chwiyrŏ sie +/- %1 satoshi na wchōd.</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(chyba etykety)</translation>
+ </message>
+ <message>
+ <source>change from %1 (%2)</source>
+ <translation>wydŏwka z %1 (%2)</translation>
+ </message>
+ <message>
+ <source>(change)</source>
+ <translation>(wydŏwka)</translation>
+ </message>
+</context>
+<context>
+ <name>EditAddressDialog</name>
+ <message>
+ <source>Edit Address</source>
+ <translation>Edytuj adresã</translation>
+ </message>
+ <message>
+ <source>&amp;Label</source>
+ <translation>&amp;Etyketa</translation>
+ </message>
+ <message>
+ <source>The label associated with this address list entry</source>
+ <translation>Etyketa ôbwiōnzanŏ z tym wpisym na wykŏzie adres</translation>
+ </message>
+ <message>
+ <source>The address associated with this address list entry. This can only be modified for sending addresses.</source>
+ <translation>Ta adresa je ôbwiōnzanŏ z wpisym na wykŏzie adres. Może być zmodyfikowany jyno dlŏ adres posyłajōncych.</translation>
+ </message>
+ <message>
+ <source>&amp;Address</source>
+ <translation>&amp;Adresa</translation>
+ </message>
+ <message>
+ <source>New sending address</source>
+ <translation>Nowŏ adresa posyłaniŏ</translation>
+ </message>
+ <message>
+ <source>Edit receiving address</source>
+ <translation>Edytuj adresã ôdbiōru</translation>
+ </message>
+ <message>
+ <source>Edit sending address</source>
+ <translation>Edytuj adresã posyłaniŏ</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is not a valid Bitcoin address.</source>
+ <translation>Wkludzōnŏ adresa "%1" niyma nŏleżnōm adresōm Bitcoin.</translation>
+ </message>
+ <message>
+ <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source>
+ <translation>Adresa "%1" już je za adresã ôdbiorczõ z etyketōm "%2" i bez to niy idzie jeji przidać za adresã nadŏwcy.</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book with label "%2".</source>
+ <translation>Wkludzōnŏ adresa "%1" już je w ksiōnżce adres z ôpisym "%2".</translation>
+ </message>
+ <message>
+ <source>Could not unlock wallet.</source>
+ <translation>Niy idzie było ôdszperować portmanyja.</translation>
+ </message>
+ <message>
+ <source>New key generation failed.</source>
+ <translation>Gynerowanie nowego klucza niy podarziło sie.</translation>
+ </message>
+</context>
+<context>
+ <name>FreespaceChecker</name>
+ <message>
+ <source>A new data directory will be created.</source>
+ <translation>Bydzie zrychtowany nowy folder danych.</translation>
+ </message>
+ <message>
+ <source>name</source>
+ <translation>miano</translation>
+ </message>
+ <message>
+ <source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
+ <translation>Katalog już je. Przidej %1 jeźli mŏsz zastrojynie zrychtować tukej nowy katalog.</translation>
+ </message>
+ <message>
+ <source>Cannot create data directory here.</source>
+ <translation>Niy idzie było tukej zrychtować folderu datōw.</translation>
+ </message>
+</context>
+<context>
+ <name>HelpMessageDialog</name>
+ <message>
+ <source>version</source>
+ <translation>wersyjŏ</translation>
+ </message>
+ <message>
+ <source>(%1-bit)</source>
+ <translation>(%1-bit)</translation>
+ </message>
+ <message>
+ <source>About %1</source>
+ <translation>Ô %1</translation>
+ </message>
+ <message>
+ <source>Command-line options</source>
+ <translation>Ôpcyje piski kōmynd</translation>
+ </message>
+</context>
+<context>
+ <name>Intro</name>
+ <message>
+ <source>Welcome</source>
+ <translation>Witej</translation>
+ </message>
+ <message>
+ <source>Welcome to %1.</source>
+ <translation>Witej w %1.</translation>
+ </message>
+ <message>
+ <source>As this is the first time the program is launched, you can choose where %1 will store its data.</source>
+ <translation>Pōniywŏż je to piyrsze sztartniyńcie programu, możesz ôbrać kaj %1 bydzie spamiyntować swoje daty.</translation>
+ </message>
+ <message>
+ <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
+ <translation>Kej naciśniesz OK, %1 zacznie pobiyrać i przetwŏrzać cołkõ %4 keta blokōw (%2GB) przi zaczynaniu ôd piyrszych transakcyji w %3 kej %4 ôstoł sztartniynty.</translation>
+ </message>
+ <message>
+ <source>This initial synchronisation is very demanding, and may expose hardware problems with your computer that had previously gone unnoticed. Each time you run %1, it will continue downloading where it left off.</source>
+ <translation>Wstympnŏ synchrōnizacyjŏ je barzo wymŏgajōncŏ i może wyzdradzić wczaśnij niyzaôbserwowane niyprzileżytości sprzyntowe. Za kożdym sztartniyńciym %1 pobiyranie bydzie kōntynuowane ôd placu w kerym ôstało zastawiōne.</translation>
+ </message>
+ <message>
+ <source>If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</source>
+ <translation>Jeźli ôbrołś ôpcyjõ ukrōcyniŏ spamiyntowaniŏ kety blokōw (przicinanie) daty historyczne cołki czas bydōm musiały być pobrane i przetworzōne, jednak po tym ôstanõ wychrōniōne coby ôgraniczyć użycie dysku.</translation>
+ </message>
+ <message>
+ <source>Use the default data directory</source>
+ <translation>Użyj wychodnego folderu datōw</translation>
+ </message>
+ <message>
+ <source>Use a custom data directory:</source>
+ <translation>Użyj ôbranego folderu datōw</translation>
+ </message>
+ <message>
+ <source>Bitcoin</source>
+ <translation>Bitcoin</translation>
+ </message>
+ <message>
+ <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
+ <translation>Co nojmynij %1 GB datōw ôstanie spamiyntane w tym katalogu, daty te bydōm z czasym corŏz srogsze.</translation>
+ </message>
+ <message>
+ <source>Approximately %1 GB of data will be stored in this directory.</source>
+ <translation>Kole %1 GB datōw ôstanie spamiyntane w tym katalogu.</translation>
+ </message>
+ <message>
+ <source>%1 will download and store a copy of the Bitcoin block chain.</source>
+ <translation>%1 sebiere i spamiyntŏ kopijõ kety blokōw Bitcoin.</translation>
+ </message>
+ <message>
+ <source>The wallet will also be stored in this directory.</source>
+ <translation>Portmanyj tyż ôstanie spamiyntany w tym katalogu.</translation>
+ </message>
+ <message>
+ <source>Error: Specified data directory "%1" cannot be created.</source>
+ <translation>Feler: podany folder datōw "%1" niy mōg ôstać zrychtowany.</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Feler</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n GB of free space available</source>
+ <translation><numerusform>%n GB swobodnego placu dostympne</numerusform><numerusform>%n GB swobodnego placu dostympne</numerusform><numerusform>%n GB swobodnego placu dostympne</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation><numerusform>(z %n GB przidajnego)</numerusform><numerusform>(z %n GB przidajnych)</numerusform><numerusform>(z %n GB przidajnych)</numerusform></translation>
+ </message>
+</context>
+<context>
+ <name>ModalOverlay</name>
+ <message>
+ <source>Form</source>
+ <translation>Formular</translation>
+ </message>
+ <message>
+ <source>Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source>
+ <translation>Świyże transakcyje mogōm niy być jeszcze widzialne, a tedyć saldo portmanyja może być niynŏleżne. Te detale bydōm nŏleżne, kej portmanyj zakōńczy synchrōnizacyjõ z necym bitcoin, zgodnie z miyniōnym ôpisym.</translation>
+ </message>
+ <message>
+ <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source>
+ <translation>Prōba wydaniŏ bitcoinōw kere niy sōm jeszcze wyświytlōne za transakcyjŏ ôstanie ôdciepniyntŏ bez nec.</translation>
+ </message>
+ <message>
+ <source>Number of blocks left</source>
+ <translation>Ôstało blokōw</translation>
+ </message>
+ <message>
+ <source>Unknown...</source>
+ <translation>Niyznōme...</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Czŏs ôstatnigo bloku</translation>
+ </message>
+ <message>
+ <source>Progress</source>
+ <translation>Postymp</translation>
+ </message>
+ <message>
+ <source>Progress increase per hour</source>
+ <translation>Przirost postympu na godzinã</translation>
+ </message>
+ <message>
+ <source>calculating...</source>
+ <translation>ôbliczanie...</translation>
+ </message>
+ <message>
+ <source>Estimated time left until synced</source>
+ <translation>Przewidowany czŏs abszlusu synchrōnizacyje</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Skryj</translation>
+ </message>
+ <message>
+ <source>Unknown. Syncing Headers (%1)...</source>
+ <translation>Niyznōme. Synchrōnizowanie nŏgōwkōw (%1)...</translation>
+ </message>
+</context>
+<context>
+ <name>OpenURIDialog</name>
+ <message>
+ <source>Open URI</source>
+ <translation>Ôdewrzij URI</translation>
+ </message>
+ <message>
+ <source>Open payment request from URI or file</source>
+ <translation>Ôdewrzij żōndanie płatu z URI abo zbioru</translation>
+ </message>
+ <message>
+ <source>URI:</source>
+ <translation>URI:</translation>
+ </message>
+ <message>
+ <source>Select payment request file</source>
+ <translation>Ôtwōrz żōndanie płatu ze zbioru</translation>
+ </message>
+ <message>
+ <source>Select payment request file to open</source>
+ <translation>Ôbier zbiōr żōndaniŏ płatu do ôdewrzyniŏ</translation>
+ </message>
+</context>
+<context>
+ <name>OptionsDialog</name>
+ <message>
+ <source>Options</source>
+ <translation>Ôpcyje</translation>
+ </message>
+ <message>
+ <source>&amp;Main</source>
+ <translation>&amp;Bazowe</translation>
+ </message>
+ <message>
+ <source>Automatically start %1 after logging in to the system.</source>
+ <translation>Autōmatycznie sztartnij %1 po wlogowaniu do systymu.</translation>
+ </message>
+ <message>
+ <source>&amp;Start %1 on system login</source>
+ <translation>&amp;Sztartuj %1 w czasie logowaniŏ do systymu</translation>
+ </message>
+ <message>
+ <source>Size of &amp;database cache</source>
+ <translation>Srogość bufōra bazy datōw</translation>
+ </message>
+ <message>
+ <source>MB</source>
+ <translation>MB</translation>
+ </message>
+ <message>
+ <source>Number of script &amp;verification threads</source>
+ <translation>Wielość wōntkōw &amp;weryfikacyje skryptu</translation>
+ </message>
+ <message>
+ <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
+ <translation>Adresa IP proxy (bp. IPv4: 127.0.0.1 / IPv6: ::1)</translation>
+ </message>
+ <message>
+ <source>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source>
+ <translation>Minimalizuje zamiast zakōńczyć fungowanie aplikacyje przi zawiyraniu ôkna. Kej ta ôpcyjŏ je zapuszczonŏ, aplikacyjŏ zakōńczy fungowanie po ôbraniu Zawrzij w myni.</translation>
+ </message>
+ <message>
+ <source>Active command-line options that override above options:</source>
+ <translation>Aktywne ôpcyje piski kōmynd, kere nadpisujōm powyższe ôpcyje:</translation>
+ </message>
+ <message>
+ <source>Open the %1 configuration file from the working directory.</source>
+ <translation>Ôdewrzij %1 zbiōr kōnfiguracyje z czynnego katalogu.</translation>
+ </message>
+ <message>
+ <source>Open Configuration File</source>
+ <translation>Ôdewrzij zbiōr kōnfiguracyje</translation>
+ </message>
+ <message>
+ <source>Reset all client options to default.</source>
+ <translation>Prziwrōć wszyjske wychodne ustawiyniŏ klijynta.</translation>
+ </message>
+ <message>
+ <source>&amp;Reset Options</source>
+ <translation>&amp;Resetuj Ôpcyje</translation>
+ </message>
+ <message>
+ <source>&amp;Network</source>
+ <translation>&amp;Nec</translation>
+ </message>
+ <message>
+ <source>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</source>
+ <translation>Zastawiŏ niykere moderne funkcyje, ale wszyjske bloki durch bydōm w połni wybadowane. Cŏfniyńcie tego nasztalowaniŏ fołdruje pōnownego sebraniŏ cołkij kety blokōw. Istne spotrzebowanie dysku może być cosikej wyższe.</translation>
+ </message>
+ <message>
+ <source>Prune &amp;block storage to</source>
+ <translation>Przitnij skłŏd &amp;blokōw do</translation>
+ </message>
+ <message>
+ <source>GB</source>
+ <translation>GB</translation>
+ </message>
+ <message>
+ <source>Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation>Cŏfniyńcie tego ustawiyniŏ wymŏgŏ pōnownego sebraniŏ cołkij kety blokōw.</translation>
+ </message>
+ <message>
+ <source>(0 = auto, &lt;0 = leave that many cores free)</source>
+ <translation>(0 = autōmatycznie, &lt;0 = ôstŏw tela swobodnych drzyni)</translation>
+ </message>
+ <message>
+ <source>W&amp;allet</source>
+ <translation>Portm&amp;anyj</translation>
+ </message>
+ <message>
+ <source>Expert</source>
+ <translation>Ekspert</translation>
+ </message>
+ <message>
+ <source>Enable coin &amp;control features</source>
+ <translation>Zapuść funkcyje kōntroli mōnet</translation>
+ </message>
+ <message>
+ <source>If you disable the spending of unconfirmed change, the change from a transaction cannot be used until that transaction has at least one confirmation. This also affects how your balance is computed.</source>
+ <translation>Jeźli zastawisz możebność wydaniŏ niyprzituplikowanyj wydanej wydŏwki, wydŏwka z transakcyje niy bydzie mogła ôstać użytŏ, podwiela ta transakcyjŏ niy bydzie miała nojmynij jednego przituplowaniŏ. To tyż mŏ wpływ na porachowanie Twojigo salda.</translation>
+ </message>
+ <message>
+ <source>&amp;Spend unconfirmed change</source>
+ <translation>&amp;Wydej niyprzituplowanõ wydŏwkã</translation>
+ </message>
+ <message>
+ <source>Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</source>
+ <translation>Autōmatycznie ôdewrzij port klijynta Bitcoin na routerze. Ta ôpcyjŏ funguje ino jeźli twōj router podpiyrŏ UPnP i je ôno zapuszczone.</translation>
+ </message>
+ <message>
+ <source>Map port using &amp;UPnP</source>
+ <translation>Mapuj port przi używaniu &amp;UPnP</translation>
+ </message>
+ <message>
+ <source>Accept connections from outside.</source>
+ <translation>Akceptuj skuplowania ôd zewnōntrz.</translation>
+ </message>
+ <message>
+ <source>Allow incomin&amp;g connections</source>
+ <translation>Zwōl na skuplowania przichodzōnce</translation>
+ </message>
+ <message>
+ <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source>
+ <translation>Skupluj sie z necym Bitcoin bez SOCKS5 proxy.</translation>
+ </message>
+ <message>
+ <source>&amp;Connect through SOCKS5 proxy (default proxy):</source>
+ <translation>&amp;Skupluj bez proxy SOCKS5 (wychodne proxy):</translation>
+ </message>
+ <message>
+ <source>Proxy &amp;IP:</source>
+ <translation>Proxy &amp;IP:</translation>
+ </message>
+ <message>
+ <source>&amp;Port:</source>
+ <translation>&amp;Port:</translation>
+ </message>
+ <message>
+ <source>Port of the proxy (e.g. 9050)</source>
+ <translation>Port ôd proxy (bp. 9050)</translation>
+ </message>
+ <message>
+ <source>IPv4</source>
+ <translation>IPv4</translation>
+ </message>
+ <message>
+ <source>IPv6</source>
+ <translation>IPv6</translation>
+ </message>
+ <message>
+ <source>Tor</source>
+ <translation>Tor</translation>
+ </message>
+ <message>
+ <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source>
+ <translation>Skupluj sie z necym Bitcoin ze pōmocōm ôsobnego proxy SOCKS5 dlŏ necu TOR</translation>
+ </message>
+ <message>
+ <source>&amp;Window</source>
+ <translation>Ô&amp;kno</translation>
+ </message>
+ <message>
+ <source>User Interface &amp;language:</source>
+ <translation>Gŏdka &amp;używŏcza:</translation>
+ </message>
+ <message>
+ <source>The user interface language can be set here. This setting will take effect after restarting %1.</source>
+ <translation>Idzie sam nasztalować gŏdka interfejsu używŏcza. Nasztalowanie prziniesie skutki po resztarcie %1.</translation>
+ </message>
+ <message>
+ <source>&amp;OK</source>
+ <translation>&amp;OK</translation>
+ </message>
+ <message>
+ <source>&amp;Cancel</source>
+ <translation>&amp;Pociep</translation>
+ </message>
+ <message>
+ <source>default</source>
+ <translation>wychodny</translation>
+ </message>
+ <message>
+ <source>none</source>
+ <translation>żŏdyn</translation>
+ </message>
+ <message>
+ <source>Configuration options</source>
+ <translation>Ôpcyje kōnfiguracyje</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Feler</translation>
+ </message>
+ </context>
+<context>
+ <name>OverviewPage</name>
+ <message>
+ <source>Form</source>
+ <translation>Formular</translation>
+ </message>
+ <message>
+ <source>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</source>
+ <translation>Wyświytlanŏ informacyjŏ może być niyterŏźnŏ. Twōj portmanyj synchrōnizuje sie autōmatycznie z necym bitcoin zarŏz po tym, jak zrychtowane je skuplowanie, ale proces tyn niy ôstoł jeszcze skōńczōny.</translation>
+ </message>
+ <message>
+ <source>Available:</source>
+ <translation>Dostympne:</translation>
+ </message>
+ <message>
+ <source>Pending:</source>
+ <translation>Czekajōnce:</translation>
+ </message>
+ <message>
+ <source>Balances</source>
+ <translation>Salda</translation>
+ </message>
+ <message>
+ <source>Total:</source>
+ <translation>Cuzamyn:</translation>
+ </message>
+ <message>
+ <source>Your current total balance</source>
+ <translation>Twoje terŏźne saldo</translation>
+ </message>
+ </context>
+<context>
+ <name>PaymentServer</name>
+ <message>
+ <source>URI handling</source>
+ <translation>Bedynōng URI</translation>
+ </message>
+ <message>
+ <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source>
+ <translation>'bitcoin://' to niyma nŏleżne URI. Użyj 'bitcoin:'.</translation>
+ </message>
+ <message>
+ <source>Payment request network doesn't match client network.</source>
+ <translation>Nec żōndaniŏ płatu niy ôdpadŏ necu klijynta.</translation>
+ </message>
+ <message>
+ <source>Unverified payment requests to custom payment scripts are unsupported.</source>
+ <translation>Niyzweryfikowane żōndaniŏ płatu do włŏsnych skryptōw płatu sōm niypodpiyrane.</translation>
+ </message>
+ <message>
+ <source>Network request error</source>
+ <translation>Feler żōndaniŏ necu</translation>
+ </message>
+ <message>
+ <source>Payment acknowledged</source>
+ <translation>Płat przituplowany</translation>
+ </message>
+</context>
+<context>
+ <name>PeerTableModel</name>
+ <message>
+ <source>User Agent</source>
+ <translation>Agynt Używŏcza</translation>
+ </message>
+ <message>
+ <source>Ping</source>
+ <translation>Ping</translation>
+ </message>
+ <message>
+ <source>Received</source>
+ <translation>Ôdebrane</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>Amount</source>
+ <translation>Kwota</translation>
+ </message>
+ <message>
+ <source>Enter a Bitcoin address (e.g. %1)</source>
+ <translation>Wkludź adresã Bitcoin (bp. %1)</translation>
+ </message>
+ <message>
+ <source>%1 d</source>
+ <translation>%1 d</translation>
+ </message>
+ <message>
+ <source>%1 h</source>
+ <translation>%1 h</translation>
+ </message>
+ <message>
+ <source>%1 m</source>
+ <translation>%1 m</translation>
+ </message>
+ <message>
+ <source>%1 s</source>
+ <translation>%1 s</translation>
+ </message>
+ <message>
+ <source>N/A</source>
+ <translation>N/A</translation>
+ </message>
+ <message>
+ <source>%1 ms</source>
+ <translation>%1 ms</translation>
+ </message>
+ <message>
+ <source>%1 B</source>
+ <translation>%1 B</translation>
+ </message>
+ <message>
+ <source>%1 KB</source>
+ <translation>%1 KB</translation>
+ </message>
+ <message>
+ <source>%1 MB</source>
+ <translation>%1 MB</translation>
+ </message>
+ <message>
+ <source>%1 GB</source>
+ <translation>%1 GB</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>niyznōme</translation>
+ </message>
+</context>
+<context>
+ <name>QObject::QObject</name>
+ <message>
+ <source>Error: %1</source>
+ <translation>Feler: %1</translation>
+ </message>
+</context>
+<context>
+ <name>QRImageWidget</name>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;Spamiyntej Ôbrŏzek</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>&amp;Kopiyruj Ôbrŏzek</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Spamiyntej kod QR</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>Ôbrŏzek PNG (*.png)</translation>
+ </message>
+</context>
+<context>
+ <name>RPCConsole</name>
+ <message>
+ <source>N/A</source>
+ <translation>N/A</translation>
+ </message>
+ <message>
+ <source>Client version</source>
+ <translation>Wersyjŏ klijynta</translation>
+ </message>
+ <message>
+ <source>Debug window</source>
+ <translation>Ôkno debugowaniŏ</translation>
+ </message>
+ <message>
+ <source>Using BerkeleyDB version</source>
+ <translation>Używanie wersyje BerkeleyDB</translation>
+ </message>
+ <message>
+ <source>Datadir</source>
+ <translation>Katalog datōw</translation>
+ </message>
+ <message>
+ <source>Startup time</source>
+ <translation>Czŏs sztartniyńciŏ</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>Nec</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>Miano</translation>
+ </message>
+ <message>
+ <source>Number of connections</source>
+ <translation>Wielość skuplowań</translation>
+ </message>
+ <message>
+ <source>Block chain</source>
+ <translation>Keta blokōw</translation>
+ </message>
+ <message>
+ <source>Current number of blocks</source>
+ <translation>Terŏźniŏ wielość blokōw</translation>
+ </message>
+ <message>
+ <source>Current number of transactions</source>
+ <translation>Terŏźniŏ wielość transakcyji</translation>
+ </message>
+ <message>
+ <source>Wallet: </source>
+ <translation>Portmanyj: </translation>
+ </message>
+ <message>
+ <source>Received</source>
+ <translation>Ôdebrane</translation>
+ </message>
+ <message>
+ <source>Direction</source>
+ <translation>Richtōng</translation>
+ </message>
+ <message>
+ <source>Version</source>
+ <translation>Wersyjŏ</translation>
+ </message>
+ <message>
+ <source>User Agent</source>
+ <translation>Agynt Używŏcza</translation>
+ </message>
+ <message>
+ <source>Services</source>
+ <translation>Usugi</translation>
+ </message>
+ <message>
+ <source>Connection Time</source>
+ <translation>Czŏs Skuplowaniŏ</translation>
+ </message>
+ <message>
+ <source>Last block time</source>
+ <translation>Czas ôstatnigo bloku</translation>
+ </message>
+ <message>
+ <source>&amp;Open</source>
+ <translation>Ô&amp;dewrzij</translation>
+ </message>
+ <message>
+ <source>&amp;Network Traffic</source>
+ <translation>&amp;Ruch necowy</translation>
+ </message>
+ <message>
+ <source>In:</source>
+ <translation>Wchōd:</translation>
+ </message>
+ <message>
+ <source>Out:</source>
+ <translation>Wychōd:</translation>
+ </message>
+ <message>
+ <source>1 &amp;day</source>
+ <translation>1 &amp;dziyń</translation>
+ </message>
+ <message>
+ <source>&amp;Disconnect</source>
+ <translation>Ô&amp;dkupluj</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation>wychodny portmanyj</translation>
+ </message>
+ <message>
+ <source>Welcome to the %1 RPC console.</source>
+ <translation>Witej w %1 kōnsoli RPC.</translation>
+ </message>
+ <message>
+ <source>WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.</source>
+ <translation>POZŌR: Machlyrze namŏwiajōm do wpisowaniŏ tukej roztōmajtych nakŏzań coby porwać portmanyj. Niy używej tyj kōnsole bez połnego zrozumiyniŏ wpisowanych nakŏzań.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled</source>
+ <translation>Aktywność necowŏ zastawiōnŏ</translation>
+ </message>
+ <message>
+ <source>never</source>
+ <translation>nikej</translation>
+ </message>
+ <message>
+ <source>Inbound</source>
+ <translation>Wchodowy</translation>
+ </message>
+ <message>
+ <source>Outbound</source>
+ <translation>Wychodowy</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ja</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Niy</translation>
+ </message>
+ </context>
+<context>
+ <name>ReceiveCoinsDialog</name>
+ <message>
+ <source>&amp;Label:</source>
+ <translation>&amp;Etyketa:</translation>
+ </message>
+ <message>
+ <source>An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Bitcoin network.</source>
+ <translation>Ôpcyjōnalnŏ wiadōmość do prziwstōniŏ do żōndaniŏ płatu, kerŏ bydzie wyświytlanŏ, kej żōndanie ôstanie ôdewrzōne. Napōmniynie: wiadōmość ta niy ôstanie wysłanŏ z płatym w nec Bitcoin.</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Wypucuj</translation>
+ </message>
+ <message>
+ <source>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</source>
+ <translation>Natywne adresy segwit (aka Bech32 abo BIP-173) zmyńszajōm niyskorzij twoje ôpłŏcki za transakcyje i dadzōm lepsze zabezpieczynie przed chybami, ale stare portmanyje jejich niy podpiyrajōm. Jeźli ôdznaczōne, zrychtowanŏ ôstanie adresa kōmpatybilnŏ ze starszymi portmanyjami.</translation>
+ </message>
+ <message>
+ <source>Show</source>
+ <translation>Pokŏż</translation>
+ </message>
+ <message>
+ <source>Remove</source>
+ <translation>Wychrōń</translation>
+ </message>
+ <message>
+ <source>Copy URI</source>
+ <translation>Kopiyruj URI</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopiyruj etyketã</translation>
+ </message>
+ <message>
+ <source>Copy message</source>
+ <translation>Kopiyruj wiadōmość</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopiyruj kwotã</translation>
+ </message>
+</context>
+<context>
+ <name>ReceiveRequestDialog</name>
+ <message>
+ <source>QR Code</source>
+ <translation>Kod QR</translation>
+ </message>
+ <message>
+ <source>Copy &amp;URI</source>
+ <translation>Kopiyruj &amp;URI</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Address</source>
+ <translation>Kopiyruj &amp;Adresã</translation>
+ </message>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;Spamiyntej Ôbrozek</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>Informacyje ô płacie</translation>
+ </message>
+ <message>
+ <source>URI</source>
+ <translation>URI</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adresa</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Kwota</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etyketa</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Wiadōmość</translation>
+ </message>
+ <message>
+ <source>Wallet</source>
+ <translation>Portmanyj</translation>
+ </message>
+ </context>
+<context>
+ <name>RecentRequestsTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Datōm</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etyketa</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Wiadōmość</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(chyba etykety)</translation>
+ </message>
+ </context>
+<context>
+ <name>SendCoinsDialog</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>Poślij mōnety</translation>
+ </message>
+ <message>
+ <source>Quantity:</source>
+ <translation>Wielość:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation>Bajtōw:</translation>
+ </message>
+ <message>
+ <source>Amount:</source>
+ <translation>Kwota:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation>Ôpłŏcka:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation>Po ôpłŏcce:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation>Wydŏwka:</translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Ôbier...</translation>
+ </message>
+ <message>
+ <source>Warning: Fee estimation is currently not possible.</source>
+ <translation>Pozōr: Ôszacowanie ôpłŏcki za transakcyje je aktualnie niymożebne.</translation>
+ </message>
+ <message>
+ <source>per kilobyte</source>
+ <translation>na kilobajt</translation>
+ </message>
+ <message>
+ <source>Hide</source>
+ <translation>Skryj</translation>
+ </message>
+ <message>
+ <source>Recommended:</source>
+ <translation>Doradzane:</translation>
+ </message>
+ <message>
+ <source>Custom:</source>
+ <translation>Włŏsne:</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation>Sztaub:</translation>
+ </message>
+ <message>
+ <source>Balance:</source>
+ <translation>Saldo:</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Kopiyruj wielość</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopiyruj kwotã</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Kopiyruj ôpłŏckã</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Kopiyruj wielość po ôpłŏcce</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Kopiyruj wielość bajtōw</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Kopiyruj sztaub</translation>
+ </message>
+ <message>
+ <source>Copy change</source>
+ <translation>Kopiyruj wydŏwkã</translation>
+ </message>
+ <message>
+ <source>%1 (%2 blocks)</source>
+ <translation>%1 (%2 blokōw)</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>abo</translation>
+ </message>
+ <message>
+ <source>Transaction creation failed!</source>
+ <translation>Utworzynie transakcyje niy podarziło sie!</translation>
+ </message>
+ <message>
+ <source>Warning: Invalid Bitcoin address</source>
+ <translation>Pozōr: niynŏleżnŏ adresa Bitcoin</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown change address</source>
+ <translation>Pozōr: Niyznōmŏ adresa wydŏwki</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(chyba etykety)</translation>
+ </message>
+</context>
+<context>
+ <name>SendCoinsEntry</name>
+ <message>
+ <source>&amp;Label:</source>
+ <translation>&amp;Etyketa:</translation>
+ </message>
+ <message>
+ <source>This is a normal payment.</source>
+ <translation>To je normalny płat.</translation>
+ </message>
+ <message>
+ <source>Alt+A</source>
+ <translation>Alt+A</translation>
+ </message>
+ <message>
+ <source>Alt+P</source>
+ <translation>Alt+P</translation>
+ </message>
+ <message>
+ <source>Use available balance</source>
+ <translation>Użyj dostympnego salda</translation>
+ </message>
+ <message>
+ <source>Message:</source>
+ <translation>Wiadōmość:</translation>
+ </message>
+ <message>
+ <source>A message that was attached to the bitcoin: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Bitcoin network.</source>
+ <translation>Wiadōmość, kerŏ ôstała prziwstōnŏ do URI bitcoin:, kerŏ bydzie przechowowanŏ z transakcyjōm w cylach informacyjnych. Napōmniynie: Ta wiadōmość niy bydzie rozszyrzowanŏ w necu Bitcoin.</translation>
+ </message>
+ </context>
+<context>
+ <name>SendConfirmationDialog</name>
+ <message>
+ <source>Yes</source>
+ <translation>Ja</translation>
+ </message>
+</context>
+<context>
+ <name>ShutdownWindow</name>
+ </context>
+<context>
+ <name>SignVerifyMessageDialog</name>
+ <message>
+ <source>Signatures - Sign / Verify a Message</source>
+ <translation>Szkryfki - Podpisz / Zweryfikuj Wiadōmość</translation>
+ </message>
+ <message>
+ <source>&amp;Sign Message</source>
+ <translation>&amp;Szkryftnij Wiadōmość</translation>
+ </message>
+ <message>
+ <source>Alt+A</source>
+ <translation>Alt+A</translation>
+ </message>
+ <message>
+ <source>Alt+P</source>
+ <translation>Alt+P</translation>
+ </message>
+ <message>
+ <source>Sign &amp;Message</source>
+ <translation>Szkryftnij &amp;Wiadōmość</translation>
+ </message>
+ <message>
+ <source>&amp;Verify Message</source>
+ <translation>&amp;Weryfikuj Wiadōmość</translation>
+ </message>
+ <message>
+ <source>Message signing failed.</source>
+ <translation>Szkryftniyńcie wiadōmości niy podarziło sie.</translation>
+ </message>
+ <message>
+ <source>Message signed.</source>
+ <translation>Wiadōmość szkryftniyntŏ.</translation>
+ </message>
+ <message>
+ <source>Message verification failed.</source>
+ <translation>Weryfikacyjŏ wiadōmości niy podarziła sie.</translation>
+ </message>
+ </context>
+<context>
+ <name>SplashScreen</name>
+ <message>
+ <source>[testnet]</source>
+ <translation>[testnet]</translation>
+ </message>
+</context>
+<context>
+ <name>TrafficGraphWidget</name>
+ <message>
+ <source>KB/s</source>
+ <translation>KB/s</translation>
+ </message>
+</context>
+<context>
+ <name>TransactionDesc</name>
+ <message>
+ <source>Status</source>
+ <translation>Sztatus</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Datōm</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation>Źrōdło</translation>
+ </message>
+ <message>
+ <source>From</source>
+ <translation>Z</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>niyznōme</translation>
+ </message>
+ <message>
+ <source>To</source>
+ <translation>Do</translation>
+ </message>
+ <message>
+ <source>label</source>
+ <translation>etyketa</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Wiadōmość</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation>Kōmyntŏrz</translation>
+ </message>
+ <message>
+ <source>Transaction</source>
+ <translation>Transakcyjŏ</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Kwota</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionDescDialog</name>
+ </context>
+<context>
+ <name>TransactionTableModel</name>
+ <message>
+ <source>Date</source>
+ <translation>Datōm</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Zorta</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etyketa</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Ôdebrane z</translation>
+ </message>
+ <message>
+ <source>Received from</source>
+ <translation>Ôdebrane ôd</translation>
+ </message>
+ <message>
+ <source>Payment to yourself</source>
+ <translation>Płat do siebie</translation>
+ </message>
+ <message>
+ <source>(no label)</source>
+ <translation>(chyba etykety)</translation>
+ </message>
+ </context>
+<context>
+ <name>TransactionView</name>
+ <message>
+ <source>All</source>
+ <translation>Wszyjske</translation>
+ </message>
+ <message>
+ <source>Today</source>
+ <translation>Dzisiej</translation>
+ </message>
+ <message>
+ <source>Received with</source>
+ <translation>Ôdebrane z</translation>
+ </message>
+ <message>
+ <source>Other</source>
+ <translation>Inksze</translation>
+ </message>
+ <message>
+ <source>Enter address, transaction id, or label to search</source>
+ <translation>Wkludź adresa, idyntyfikatōr transakcyje abo etyketã coby wyszukać</translation>
+ </message>
+ <message>
+ <source>Copy address</source>
+ <translation>Kopiyruj adresã</translation>
+ </message>
+ <message>
+ <source>Copy label</source>
+ <translation>Kopiyruj etyketã</translation>
+ </message>
+ <message>
+ <source>Copy amount</source>
+ <translation>Kopiyruj kwotã</translation>
+ </message>
+ <message>
+ <source>Copy transaction ID</source>
+ <translation>Kopiyruj ID transakcyje</translation>
+ </message>
+ <message>
+ <source>Edit label</source>
+ <translation>Edytuj etyketa</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>Zbiōr *.CSV (dane rozdzielane kōmami)</translation>
+ </message>
+ <message>
+ <source>Confirmed</source>
+ <translation>Przituplowany</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>Datōm</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>Zorta</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>Etyketa</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>Adresa</translation>
+ </message>
+ <message>
+ <source>ID</source>
+ <translation>ID</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>Eksportowanie niy podarziło sie</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>do</translation>
+ </message>
+</context>
+<context>
+ <name>UnitDisplayStatusBarControl</name>
+ </context>
+<context>
+ <name>WalletFrame</name>
+ </context>
+<context>
+ <name>WalletModel</name>
+ <message>
+ <source>Send Coins</source>
+ <translation>Poślij mōnety</translation>
+ </message>
+ <message>
+ <source>New fee:</source>
+ <translation>Nowŏ ôpłŏcka:</translation>
+ </message>
+ </context>
+<context>
+ <name>WalletView</name>
+ <message>
+ <source>Export the data in the current tab to a file</source>
+ <translation>Eksportuj dane z aktywnyj szkarty do zbioru</translation>
+ </message>
+ <message>
+ <source>Backup Failed</source>
+ <translation>Backup niy podarził sie</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Pociep</translation>
+ </message>
+</context>
+<context>
+ <name>bitcoin-core</name>
+ <message>
+ <source>Bitcoin Core</source>
+ <translation>Bitcoin Core</translation>
+ </message>
+ <message>
+ <source>The %s developers</source>
+ <translation>Twōrcy %s</translation>
+ </message>
+ <message>
+ <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source>
+ <translation>Pozōr: Nec niy wydŏwŏ sie w połni zgodliwy! Niykerzi grubiŏrze wydajōm sie doświadczać niyprzileżytości.</translation>
+ </message>
+ <message>
+ <source>Copyright (C) %i-%i</source>
+ <translation>Copyright (C) %i-%i</translation>
+ </message>
+ <message>
+ <source>Error loading %s</source>
+ <translation>Feler wgrŏwaniŏ %s</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Private keys can only be disabled during creation</source>
+ <translation>Feler wgrŏwaniŏ %s: Klucze prywatne mogōm być zastawiōne ino w czasie tworzyniŏ</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet corrupted</source>
+ <translation>Feler wgrŏwaniŏ %s: Portmanyj poprzniōny</translation>
+ </message>
+ <message>
+ <source>Error loading %s: Wallet requires newer version of %s</source>
+ <translation>Feler wgrŏwaniŏ %s: Portmanyj wymŏgŏ nowszyj wersyje %s</translation>
+ </message>
+ <message>
+ <source>Error loading block database</source>
+ <translation>Feler wgrŏwaniŏ bazy blokōw</translation>
+ </message>
+ <message>
+ <source>Error: Disk space is low!</source>
+ <translation>Feler: Za mało wolnego placu na dysku!</translation>
+ </message>
+ <message>
+ <source>Loading P2P addresses...</source>
+ <translation>Wgrŏwanie adres P2P...</translation>
+ </message>
+ <message>
+ <source>Loading banlist...</source>
+ <translation>Wgrŏwanie wykŏzu zaszperowanych...</translation>
+ </message>
+ <message>
+ <source>Unsupported argument -benchmark ignored, use -debug=bench.</source>
+ <translation>Niypodpiyrany argumynt -benchmark zignorowany, użyj -debug=bench.</translation>
+ </message>
+ <message>
+ <source>Unsupported argument -debugnet ignored, use -debug=net.</source>
+ <translation>Niypodpiyrany argumynt -debugnet zignorowany, użyj -debug=net.</translation>
+ </message>
+ <message>
+ <source>Unsupported argument -tor found, use -onion.</source>
+ <translation>Znŏdniynto było niypodpiyrany argumynt -tor, użyj -onion.</translation>
+ </message>
+ <message>
+ <source>Unsupported logging category %s=%s.</source>
+ <translation>Niypodpiyranŏ kategoryjŏ registrowaniŏ %s=%s.</translation>
+ </message>
+ <message>
+ <source>Verifying blocks...</source>
+ <translation>Weryfikacyjŏ blokōw...</translation>
+ </message>
+ <message>
+ <source>Error loading %s: You can't disable HD on an already existing HD wallet</source>
+ <translation>Feler w czasie wgrŏwaniŏ %s: Niy idzie zastawić HD w już bydōncym portmanyju HD</translation>
+ </message>
+ <message>
+ <source>Information</source>
+ <translation>Informacyjŏ</translation>
+ </message>
+ <message>
+ <source>Signing transaction failed</source>
+ <translation>Szkryftniyńcie transakcyji niy podarziło sie</translation>
+ </message>
+ <message>
+ <source>This is experimental software.</source>
+ <translation>To je eksperymyntalny softwer.</translation>
+ </message>
+ <message>
+ <source>Transaction too large</source>
+ <translation>Transakcyjŏ za srogŏ</translation>
+ </message>
+ <message>
+ <source>Verifying wallet(s)...</source>
+ <translation>Weryfikacyjŏ portmanyja(ōw)...</translation>
+ </message>
+ <message>
+ <source>Warning</source>
+ <translation>Pozōr</translation>
+ </message>
+ <message>
+ <source>Warning: unknown new rules activated (versionbit %i)</source>
+ <translation>Pozōr: aktywowano było niyznōme nowe prawidła (versionbit %i)</translation>
+ </message>
+ <message>
+ <source>Error loading %s: You can't enable HD on an already existing non-HD wallet</source>
+ <translation>Feler w czasie wgrŏwaniŏ %s: Niy idzie zapuścić HD w już bydōncym portmanyju niy-HD</translation>
+ </message>
+ <message>
+ <source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source>
+ <translation>Imyntnŏ dugość kety wersyje (%i) przekrŏczŏ maksymalnõ dopuszczalnõ dugość (%i). Zmyńsz wielość abo miara parametra uacomment.</translation>
+ </message>
+ <message>
+ <source>Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.</source>
+ <translation>Znŏdniynto było niypodpiyrany argumynt -socks. Ôbiyranie wersyje SOCKS je już niymożebne, podpiyrane sōm ino proxy SOCKS5.</translation>
+ </message>
+ <message>
+ <source>Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.</source>
+ <translation>Niypodpiyrany argumynt -whitelistalwaysrelay zignorowany, użyj -whitelistrelay i/abo -whitelistforcerelay.</translation>
+ </message>
+ <message>
+ <source>Warning: Unknown block versions being mined! It's possible unknown rules are in effect</source>
+ <translation>Pozōr: wydobywane sōm niyznōme wersyje blokōw! Możliwe, iże ôbowiōnzujōm niyznōme prawidła.</translation>
+ </message>
+ <message>
+ <source>Warning: Wallet file corrupt, data salvaged! Original %s saved as %s in %s; if your balance or transactions are incorrect you should restore from a backup.</source>
+ <translation>Pozōr: Ôdtworzōno było dane z poprzniōnego zbioru portmanyja! Ôryginalny %s ôstoł zapisany za %s w %s; jeźli twoje saldo abo transakcyje sōm niynŏleżne winiyn żeś prziwrōcić kopijõ ibrycznõ.</translation>
+ </message>
+ <message>
+ <source>Error loading wallet %s. Duplicate -wallet filename specified.</source>
+ <translation>Feler w czasie wgrŏwaniŏ portmanyja %s. Podanŏ tuplowane miano zbioru w -wallet.</translation>
+ </message>
+ <message>
+ <source>Starting network threads...</source>
+ <translation>Sztartowanie wōntkōw necowych...</translation>
+ </message>
+ <message>
+ <source>Unknown network specified in -onlynet: '%s'</source>
+ <translation>Niyznōmy nec ôkryślōny w -onlynet: '%s'</translation>
+ </message>
+ <message>
+ <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source>
+ <translation>Pozōr: Wykryto było klucze prywatne w portmanyju {%s} kery mŏ zastawiōne klucze prywatne</translation>
+ </message>
+ <message>
+ <source>Loading block index...</source>
+ <translation>Wgrŏwanie indeksu blokōw...</translation>
+ </message>
+ <message>
+ <source>Loading wallet...</source>
+ <translation>Wgrŏwanie portmanyja...</translation>
+ </message>
+ <message>
+ <source>Rescanning...</source>
+ <translation>Pōnowne skanowanie</translation>
+ </message>
+ <message>
+ <source>Done loading</source>
+ <translation>Wgrŏwanie zakōńczōne</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Feler</translation>
+ </message>
+</context>
+</TS> \ No newline at end of file
diff --git a/src/qt/locale/bitcoin_tr.ts b/src/qt/locale/bitcoin_tr.ts
index b092ee060e..db30aa04c2 100644
--- a/src/qt/locale/bitcoin_tr.ts
+++ b/src/qt/locale/bitcoin_tr.ts
@@ -326,6 +326,14 @@
<translation>&amp;URI Aç...</translation>
</message>
<message>
+ <source>Wallet:</source>
+ <translation>Cüzdan:</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation>varsayılan cüzdan</translation>
+ </message>
+ <message>
<source>Click to disable network activity.</source>
<translation>Ağ etkinliğini devre dışı bırakmak için tıklayın.</translation>
</message>
@@ -346,6 +354,10 @@
<translation>Diskteki bloklar yeniden indeksleniyor...</translation>
</message>
<message>
+ <source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
+ <translation>Tünelleme &lt;b&gt;etkin&lt;/b&gt;: %1</translation>
+ </message>
+ <message>
<source>Send coins to a Bitcoin address</source>
<translation>Bir bitcoin adresine bitcoin gönder</translation>
</message>
@@ -514,6 +526,12 @@
</translation>
</message>
<message>
+ <source>Wallet: %1
+</source>
+ <translation>Cüzdan: %1
+</translation>
+ </message>
+ <message>
<source>Type: %1
</source>
<translation>Tür: %1
@@ -750,6 +768,10 @@
<translation>Girilen "%1" adresi geçerli bir Bitcoin adresi değildir.</translation>
</message>
<message>
+ <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source>
+ <translation>Adres "%1" adres "%2" etiketiyle alım adresiniz olarak mevcut ve bu sebepten gönderen adres olarak eklenemiyor.</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation>Cüzdan kilidi açılamadı.</translation>
</message>
@@ -1479,6 +1501,10 @@
<translation>Hata: Belirtilen "%1" veri klasörü yoktur.</translation>
</message>
<message>
+ <source>Error: Cannot parse configuration file: %1.</source>
+ <translation>Hata: %1 yapılandırma dosyası ayrıştırılamadı. </translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation>Hata: %1</translation>
</message>
@@ -1569,6 +1595,14 @@
<translation>Bellek kullanımı</translation>
</message>
<message>
+ <source>Wallet: </source>
+ <translation>Cüzdan:</translation>
+ </message>
+ <message>
+ <source>(none)</source>
+ <translation>(boş)</translation>
+ </message>
+ <message>
<source>&amp;Reset</source>
<translation>&amp;Sıfırla</translation>
</message>
@@ -1737,6 +1771,10 @@
<translation>&amp;Yasaklamayı Kaldır</translation>
</message>
<message>
+ <source>default wallet</source>
+ <translation>varsayılan cüzdan</translation>
+ </message>
+ <message>
<source>Welcome to the %1 RPC console.</source>
<translation>%1 RPC konsoluna hoş geldiniz.</translation>
</message>
@@ -1761,6 +1799,14 @@
<translation>Ağ etkinliği devre dışı bırakıldı</translation>
</message>
<message>
+ <source>Executing command without any wallet</source>
+ <translation>Komut bir cüzdan olmadan çalıştırılıyor</translation>
+ </message>
+ <message>
+ <source>Executing command using "%1" wallet</source>
+ <translation>Komut "%1" cüzdanı kullanılarak çalıştırılıyor</translation>
+ </message>
+ <message>
<source>(node id: %1)</source>
<translation>(düğüm kimliği: %1)</translation>
</message>
@@ -1832,6 +1878,10 @@
<translation>Temizle</translation>
</message>
<message>
+ <source>Generate native segwit (Bech32) address</source>
+ <translation>Yerli segwit (Bech32) adresi oluştur</translation>
+ </message>
+ <message>
<source>Requested payments history</source>
<translation>Talep edilen ödemelerin tarihçesi</translation>
</message>
@@ -2141,10 +2191,22 @@
<translation>veya</translation>
</message>
<message>
+ <source>from wallet %1</source>
+ <translation>cüzdan %1'den</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction.</source>
+ <translation>Lütfen, işleminizi gözden geçirin.</translation>
+ </message>
+ <message>
<source>Transaction fee</source>
<translation>İşlem ücreti</translation>
</message>
<message>
+ <source>Total Amount</source>
+ <translation>Toplam Tutar</translation>
+ </message>
+ <message>
<source>Confirm send coins</source>
<translation>Bitcoin gönderimini onaylayın</translation>
</message>
@@ -2990,7 +3052,11 @@
<source>The wallet data was successfully saved to %1.</source>
<translation>Cüzdan verileri %1 konumuna başarıyla kaydedildi.</translation>
</message>
- </context>
+ <message>
+ <source>Cancel</source>
+ <translation>İptal</translation>
+ </message>
+</context>
<context>
<name>bitcoin-core</name>
<message>
@@ -3162,6 +3228,10 @@
<translation> -fallbackfee=&lt;tutar&gt; için geçersiz tutar: '%s'</translation>
</message>
<message>
+ <source>Upgrading txindex database</source>
+ <translation>txindex veritabanı yükseltiliyor</translation>
+ </message>
+ <message>
<source>Loading P2P addresses...</source>
<translation>P2P adresleri yükleniyor...</translation>
</message>
@@ -3202,6 +3272,10 @@
<translation>Bu bilgisayarda %s unsuruna bağlanılamadı. %s muhtemelen hâlihazırda çalışmaktadır.</translation>
</message>
<message>
+ <source>Unable to generate keys</source>
+ <translation>Anahtar üretilemiyor</translation>
+ </message>
+ <message>
<source>Unsupported argument -benchmark ignored, use -debug=bench.</source>
<translation>Desteklenmeyen -benchmark argümanı görmezden gelindi, -debug=bench kullanınız.</translation>
</message>
@@ -3338,6 +3412,10 @@
<translation>Cüzdan(lar) kontrol ediliyor...</translation>
</message>
<message>
+ <source>Wallet %s resides outside wallet directory %s</source>
+ <translation>Cüzdan %s, %s cüzdan klasörünün dışında bulunuyor</translation>
+ </message>
+ <message>
<source>Warning</source>
<translation>Uyarı</translation>
</message>
@@ -3434,6 +3512,14 @@
<translation>Yetersiz bakiye</translation>
</message>
<message>
+ <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
+ <translation>İşlem ücreti hesaplama başarısız. Fallbackfee özelliği devre dışı. Lütfen bir kaç blok için bekleyiniz yada -fallbackfee özelliğini aktif ediniz.</translation>
+ </message>
+ <message>
+ <source>Cannot write to data directory '%s'; check permissions.</source>
+ <translation>Veriler klasöre yazılamıyor '%s'; yetkilendirmeyi kontrol edin.</translation>
+ </message>
+ <message>
<source>Loading block index...</source>
<translation>Blok indeksi yükleniyor...</translation>
</message>
diff --git a/src/qt/locale/bitcoin_tr_TR.ts b/src/qt/locale/bitcoin_tr_TR.ts
index cf119c65c2..bf2dae99dc 100644
--- a/src/qt/locale/bitcoin_tr_TR.ts
+++ b/src/qt/locale/bitcoin_tr_TR.ts
@@ -30,6 +30,10 @@
<translation>Seçili adresi listeden sil</translation>
</message>
<message>
+ <source>Enter address or label to search</source>
+ <translation>Aramak için adres veya etiket girin</translation>
+ </message>
+ <message>
<source>Export the data in the current tab to a file</source>
<translation>Seçili sekmedeki veriyi dosya olarak dışa aktar</translation>
</message>
@@ -132,6 +136,10 @@
<translation>Yeni parolayı tekrarla</translation>
</message>
<message>
+ <source>Show password</source>
+ <translation>Şifreyi göster</translation>
+ </message>
+ <message>
<source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;ten or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
<translation>Yeni parolayı cüzdana girin.&lt;br/&gt;Lütfen &lt;b&gt;on yada daha fazla karakter&lt;/b&gt; veya &lt;b&gt;sekiz yada daha fazla kelime&lt;/b&gt;içeren bir parola kullanın. </translation>
</message>
@@ -192,6 +200,10 @@
<translation>Cüzdan şifreleme başarısız oldu</translation>
</message>
<message>
+ <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source>
+ <translation>Cüzdan şifreleme dahili bir hata nedeniyle başarısız oldu. Cüzdanınız şifrelenemedi.</translation>
+ </message>
+ <message>
<source>The supplied passphrases do not match.</source>
<translation>Girilen parolalar eşleşmiyor.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_uk.ts b/src/qt/locale/bitcoin_uk.ts
index 6698aa4235..1865a84834 100644
--- a/src/qt/locale/bitcoin_uk.ts
+++ b/src/qt/locale/bitcoin_uk.ts
@@ -3478,12 +3478,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p
<translation>Вказаний шлях -walletdir "%s" не є каталогом</translation>
</message>
<message>
- <source>Specified blocks directory "%s" does not exist.
-</source>
- <translation>Вказаний шлях до блоків "%s" не існує
-</translation>
- </message>
- <message>
<source>The transaction amount is too small to pay the fee</source>
<translation>Неможливо сплатити комісію із-за малої суми транзакції</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ur_PK.ts b/src/qt/locale/bitcoin_ur_PK.ts
index eadd059f7d..03502be8a8 100644
--- a/src/qt/locale/bitcoin_ur_PK.ts
+++ b/src/qt/locale/bitcoin_ur_PK.ts
@@ -53,10 +53,46 @@
<source>C&amp;hoose</source>
<translation>چننا</translation>
</message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>پتے ارسال کیے جارہے ہیں</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>پتے موصول ہورہے ہیں</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Address</source>
+ <translation>&amp;پتا نقل کریں</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>&amp;لیبل نقل کریں</translation>
+ </message>
+ <message>
+ <source>&amp;Edit</source>
+ <translation>&amp;تدوین</translation>
+ </message>
+ <message>
+ <source>Export Address List</source>
+ <translation>پتا فہرست ایکسپورٹ کریں</translation>
+ </message>
+ <message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>کاما سے جدا فائلیں (*.csv)</translation>
+ </message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>ایکسپورٹ ناکام ہوا</translation>
+ </message>
</context>
<context>
<name>AddressTableModel</name>
<message>
+ <source>Label</source>
+ <translation>لیبل</translation>
+ </message>
+ <message>
<source>Address</source>
<translation> پتہ</translation>
</message>
@@ -176,9 +212,17 @@
<source>Address</source>
<translation> پتہ</translation>
</message>
+ <message>
+ <source>Label</source>
+ <translation>لیبل</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>لیبل</translation>
+ </message>
</context>
<context>
<name>SendCoinsDialog</name>
@@ -221,13 +265,29 @@
</context>
<context>
<name>TransactionTableModel</name>
+ <message>
+ <source>Label</source>
+ <translation>لیبل</translation>
+ </message>
</context>
<context>
<name>TransactionView</name>
<message>
+ <source>Comma separated file (*.csv)</source>
+ <translation>کاما سے جدا فائلیں (*.csv)</translation>
+ </message>
+ <message>
+ <source>Label</source>
+ <translation>لیبل</translation>
+ </message>
+ <message>
<source>Address</source>
<translation> پتہ</translation>
</message>
+ <message>
+ <source>Exporting Failed</source>
+ <translation>ایکسپورٹ ناکام ہوا</translation>
+ </message>
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
diff --git a/src/qt/locale/bitcoin_vi.ts b/src/qt/locale/bitcoin_vi.ts
index 563d047ff7..768ad38912 100644
--- a/src/qt/locale/bitcoin_vi.ts
+++ b/src/qt/locale/bitcoin_vi.ts
@@ -3,15 +3,15 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation>Phải chuột để edit address hoặc label</translation>
+ <translation>Phải chuột để sửa địa chỉ hoặc nhãn</translation>
</message>
<message>
<source>Create a new address</source>
- <translation>Create một address mới</translation>
+ <translation>Tạo một địa chỉ mới</translation>
</message>
<message>
<source>&amp;New</source>
- <translation>&amp;Tạo mới</translation>
+ <translation>&amp;Mới</translation>
</message>
<message>
<source>Copy the currently selected address to the system clipboard</source>
@@ -318,6 +318,10 @@
<translation>Mở &amp;URI...</translation>
</message>
<message>
+ <source>Wallet:</source>
+ <translation>Ví tiền</translation>
+ </message>
+ <message>
<source>Click to disable network activity.</source>
<translation>Click để vô hiệu hoạt động mạng.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_zh_CN.ts b/src/qt/locale/bitcoin_zh_CN.ts
index 6678641ad3..ed9f6c2d7d 100644
--- a/src/qt/locale/bitcoin_zh_CN.ts
+++ b/src/qt/locale/bitcoin_zh_CN.ts
@@ -47,15 +47,15 @@
</message>
<message>
<source>Choose the address to send coins to</source>
- <translation>选择要付钱过去的地址</translation>
+ <translation>选择要发币给哪些地址</translation>
</message>
<message>
<source>Choose the address to receive coins with</source>
- <translation>选择要收钱进来的地址</translation>
+ <translation>选择要用哪些地址收币</translation>
</message>
<message>
<source>C&amp;hoose</source>
- <translation>选择</translation>
+ <translation>选择(&amp;C)</translation>
</message>
<message>
<source>Sending addresses</source>
@@ -67,23 +67,23 @@
</message>
<message>
<source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
- <translation>这些是你要付款过去的比特币地址。在付钱之前,务必要检查金额和收款地址是否正确。</translation>
+ <translation>您可以给这些比特币地址付款。在付款之前,务必要检查金额和收款地址是否正确。</translation>
</message>
<message>
<source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source>
- <translation>这些是你用来收款的比特币地址。建议在每次交易时,都使用一个新的收款地址。</translation>
+ <translation>您可以用这些比特币地址收款。建议在每次交易时,都使用一个新的收款地址。</translation>
</message>
<message>
<source>&amp;Copy Address</source>
- <translation>复制地址</translation>
+ <translation>复制地址(&amp;C)</translation>
</message>
<message>
<source>Copy &amp;Label</source>
- <translation>复制标签</translation>
+ <translation>复制标签(&amp;L)</translation>
</message>
<message>
<source>&amp;Edit</source>
- <translation>编辑</translation>
+ <translation>编辑(&amp;E)</translation>
</message>
<message>
<source>Export Address List</source>
@@ -189,7 +189,7 @@
</message>
<message>
<source>%1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
- <translation>%1 现在要关闭,以完成加密过程。请注意,加密钱包不能完全防止入侵你的电脑的恶意程序偷取钱币。</translation>
+ <translation>%1 现在要关闭,以完成加密过程。请注意,加密钱包不能完全防止入侵您电脑的恶意程序偷取您的比特币。</translation>
</message>
<message>
<source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
@@ -315,17 +315,25 @@
</message>
<message>
<source>&amp;Sending addresses...</source>
- <translation>正在发送地址(&amp;S)...</translation>
+ <translation>付款地址(&amp;S)...</translation>
</message>
<message>
<source>&amp;Receiving addresses...</source>
- <translation>正在接收地址(&amp;R)...</translation>
+ <translation>收款地址(&amp;R)...</translation>
</message>
<message>
<source>Open &amp;URI...</source>
<translation>打开 &amp;URI...</translation>
</message>
<message>
+ <source>Wallet:</source>
+ <translation>钱包:</translation>
+ </message>
+ <message>
+ <source>default wallet</source>
+ <translation>默认钱包</translation>
+ </message>
+ <message>
<source>Click to disable network activity.</source>
<translation>点击禁用网络活动。</translation>
</message>
@@ -343,7 +351,11 @@
</message>
<message>
<source>Reindexing blocks on disk...</source>
- <translation>正在为数据块重建索引...</translation>
+ <translation>正在为区块数据重建索引...</translation>
+ </message>
+ <message>
+ <source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
+ <translation>代理已被&lt;b&gt;启用&lt;/b&gt;:%1</translation>
</message>
<message>
<source>Send coins to a Bitcoin address</source>
@@ -441,13 +453,21 @@
<source>&amp;Command-line options</source>
<translation>命令行选项(&amp;C)</translation>
</message>
+ <message numerus="yes">
+ <source>%n active connection(s) to Bitcoin network</source>
+ <translation><numerusform>%n 个有效连接至比特币网络</numerusform></translation>
+ </message>
<message>
<source>Indexing blocks on disk...</source>
- <translation>正在为数据块建立索引...</translation>
+ <translation>正在为区块数据建立索引...</translation>
</message>
<message>
<source>Processing blocks on disk...</source>
- <translation>正在处理数据块...</translation>
+ <translation>正在处理区块数据...</translation>
+ </message>
+ <message numerus="yes">
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation><numerusform>已处理 %n 个区块的交易历史</numerusform></translation>
</message>
<message>
<source>%1 behind</source>
@@ -506,6 +526,11 @@
</translation>
</message>
<message>
+ <source>Wallet: %1
+</source>
+ <translation>钱包:%1</translation>
+ </message>
+ <message>
<source>Type: %1
</source>
<translation>类型: %1
@@ -556,7 +581,7 @@
<name>CoinControlDialog</name>
<message>
<source>Coin Selection</source>
- <translation>选择钱币</translation>
+ <translation>币源选择(Coin Selection)</translation>
</message>
<message>
<source>Quantity:</source>
@@ -576,7 +601,7 @@
</message>
<message>
<source>Dust:</source>
- <translation>小额:</translation>
+ <translation>粉尘:</translation>
</message>
<message>
<source>After Fee:</source>
@@ -584,11 +609,11 @@
</message>
<message>
<source>Change:</source>
- <translation>变更 : </translation>
+ <translation>找零 : </translation>
</message>
<message>
<source>(un)select all</source>
- <translation>(不)全选</translation>
+ <translation>全(不)选</translation>
</message>
<message>
<source>Tree mode</source>
@@ -664,7 +689,7 @@
</message>
<message>
<source>Copy dust</source>
- <translation>复制零散金额</translation>
+ <translation>复制粉尘金额</translation>
</message>
<message>
<source>Copy change</source>
@@ -684,7 +709,7 @@
</message>
<message>
<source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
- <translation>当任何一个收款金额小于目前的零散金额上限时,文字会变红色。</translation>
+ <translation>当任何一个收款金额小于目前的粉尘金额上限时,文字会变红色。</translation>
</message>
<message>
<source>Can vary +/- %1 satoshi(s) per input.</source>
@@ -742,12 +767,20 @@
<translation>输入的地址 %1 并不是有效的比特币地址。</translation>
</message>
<message>
+ <source>Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source>
+ <translation>地址“%1”已经存在,它是一个接受地址,标签为“%2”,所以它不能被添加为一个发送地址。</translation>
+ </message>
+ <message>
+ <source>The entered address "%1" is already in the address book with label "%2".</source>
+ <translation>输入地址“%1”已经存在于地址簿中,标签为“%2”。</translation>
+ </message>
+ <message>
<source>Could not unlock wallet.</source>
<translation>无法将钱包解锁。</translation>
</message>
<message>
<source>New key generation failed.</source>
- <translation>产生新的密钥失败了。</translation>
+ <translation>生成新密钥失败。</translation>
</message>
</context>
<context>
@@ -785,7 +818,7 @@
</message>
<message>
<source>About %1</source>
- <translation>關於 %1</translation>
+ <translation>关于 %1</translation>
</message>
<message>
<source>Command-line options</source>
@@ -850,7 +883,15 @@
<source>Error</source>
<translation>错误</translation>
</message>
- </context>
+ <message numerus="yes">
+ <source>%n GB of free space available</source>
+ <translation><numerusform>%n GB 可用空闲空间</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation><numerusform>(%n GB 需要)</numerusform></translation>
+ </message>
+</context>
<context>
<name>ModalOverlay</name>
<message>
@@ -875,7 +916,7 @@
</message>
<message>
<source>Last block time</source>
- <translation>上一数据块时间</translation>
+ <translation>上一区块时间</translation>
</message>
<message>
<source>Progress</source>
@@ -977,11 +1018,11 @@
</message>
<message>
<source>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source>
- <translation>窗口被关闭时最小化而不是退出应用程序。当此选项启用时,应用程序只会在菜单中选择退出时退出。</translation>
+ <translation>窗口被关闭时最小化而不是退出应用程序。当此选项启用时,应用程序只会在菜单中选择“退出”时退出。</translation>
</message>
<message>
<source>Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source>
- <translation>出现在交易的选项卡的上下文菜单项的第三方网址 (例如:区块链接查询) 。 %s的URL被替换为交易哈希。多个的URL需要竖线 | 分隔。</translation>
+ <translation>出现在交易的选项卡的上下文菜单项的第三方网址 (例如:区块浏览器) 。 %s的URL被替换为交易哈希。多个的URL需要竖线 | 分隔。</translation>
</message>
<message>
<source>Active command-line options that override above options:</source>
@@ -1008,6 +1049,22 @@
<translation>网络(&amp;N)</translation>
</message>
<message>
+ <source>Disables some advanced features but all blocks will still be fully validated. Reverting this setting requires re-downloading the entire blockchain. Actual disk usage may be somewhat higher.</source>
+ <translation>禁用一些高级特性,但是仍然会对所有区块数据进行完整验证。必须重新下载整个区块链数据才能撤销此设置。实际的磁盘空间占用可能会略高。</translation>
+ </message>
+ <message>
+ <source>Prune &amp;block storage to</source>
+ <translation>将区块存储修剪至(&amp;B)</translation>
+ </message>
+ <message>
+ <source>GB</source>
+ <translation>GB</translation>
+ </message>
+ <message>
+ <source>Reverting this setting requires re-downloading the entire blockchain.</source>
+ <translation>警告:还原此设置需要重新下载整个区块链。</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation>(0 = 自动, &lt;0 = 保持指定数量的CPU核心空闲)</translation>
</message>
@@ -1025,11 +1082,11 @@
</message>
<message>
<source>If you disable the spending of unconfirmed change, the change from a transaction cannot be used until that transaction has at least one confirmation. This also affects how your balance is computed.</source>
- <translation>如果禁用未确认的零钱,则零钱至少需要1个确认才能使用。同时账户余额计算会受到影响。</translation>
+ <translation>如果您禁止动用尚未确认的找零资金,则一笔交易的找零资金至少需要有1个确认后才能动用。这同时也会影响账户余额的计算。</translation>
</message>
<message>
<source>&amp;Spend unconfirmed change</source>
- <translation>使用未经确认的零钱(&amp;S)</translation>
+ <translation>动用尚未确认的找零资金(&amp;S)</translation>
</message>
<message>
<source>Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</source>
@@ -1101,7 +1158,7 @@
</message>
<message>
<source>M&amp;inimize on close</source>
- <translation>单击关闭按钮最小化(&amp;I)</translation>
+ <translation>单击关闭按钮时最小化(&amp;I)</translation>
</message>
<message>
<source>&amp;Display</source>
@@ -1275,6 +1332,10 @@
<translation>URI 处理</translation>
</message>
<message>
+ <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source>
+ <translation>‘bitcoin://’不是合法的URI。请使用'bitcoin:'作为替代。</translation>
+ </message>
+ <message>
<source>Payment request fetch URL is invalid: %1</source>
<translation>取得付款请求的 URL 无效: %1</translation>
</message>
@@ -1412,10 +1473,34 @@
<source>%1 ms</source>
<translation>%1 毫秒</translation>
</message>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation><numerusform>%n 秒</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation><numerusform>%n 分</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation><numerusform>%n 时</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation><numerusform>%n 天</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation><numerusform>%n 周</numerusform></translation>
+ </message>
<message>
<source>%1 and %2</source>
<translation>%1 和 %2</translation>
</message>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation><numerusform>%n 年</numerusform></translation>
+ </message>
<message>
<source>%1 B</source>
<translation>%1 字节</translation>
@@ -1444,10 +1529,18 @@
<context>
<name>QObject::QObject</name>
<message>
+ <source>Error parsing command line arguments: %1.</source>
+ <translation>解析命令行参数错误:%1</translation>
+ </message>
+ <message>
<source>Error: Specified data directory "%1" does not exist.</source>
<translation>错误:指定的数据目录“%1”不存在。</translation>
</message>
<message>
+ <source>Error: Cannot parse configuration file: %1.</source>
+ <translation>错误:无法解析配置文件:%1</translation>
+ </message>
+ <message>
<source>Error: %1</source>
<translation>错误:%1</translation>
</message>
@@ -1519,15 +1612,15 @@
</message>
<message>
<source>Block chain</source>
- <translation>数据链</translation>
+ <translation>区块链</translation>
</message>
<message>
<source>Current number of blocks</source>
- <translation>当前数据块数量</translation>
+ <translation>当前区块数量</translation>
</message>
<message>
<source>Memory Pool</source>
- <translation>资金池</translation>
+ <translation>内存池</translation>
</message>
<message>
<source>Current number of transactions</source>
@@ -1538,6 +1631,14 @@
<translation>内存使用</translation>
</message>
<message>
+ <source>Wallet: </source>
+ <translation>钱包:</translation>
+ </message>
+ <message>
+ <source>(none)</source>
+ <translation>(无)</translation>
+ </message>
+ <message>
<source>&amp;Reset</source>
<translation>&amp;重启</translation>
</message>
@@ -1575,7 +1676,7 @@
</message>
<message>
<source>Starting Block</source>
- <translation>正在启动数据块</translation>
+ <translation>起步区块</translation>
</message>
<message>
<source>Synced Headers</source>
@@ -1583,7 +1684,7 @@
</message>
<message>
<source>Synced Blocks</source>
- <translation>同步区块链</translation>
+ <translation>已同步区块</translation>
</message>
<message>
<source>User Agent</source>
@@ -1639,7 +1740,7 @@
</message>
<message>
<source>Last block time</source>
- <translation>上一数据块时间</translation>
+ <translation>上一区块时间</translation>
</message>
<message>
<source>&amp;Open</source>
@@ -1702,6 +1803,10 @@
<translation>重新允许</translation>
</message>
<message>
+ <source>default wallet</source>
+ <translation>默认钱包</translation>
+ </message>
+ <message>
<source>Welcome to the %1 RPC console.</source>
<translation>欢迎使用 %1 的 RPC 控制台。</translation>
</message>
@@ -1726,6 +1831,14 @@
<translation>网络活动已禁用</translation>
</message>
<message>
+ <source>Executing command without any wallet</source>
+ <translation>不使用任何钱包执行命令</translation>
+ </message>
+ <message>
+ <source>Executing command using "%1" wallet</source>
+ <translation>使用“%1”钱包执行命令</translation>
+ </message>
+ <message>
<source>(node id: %1)</source>
<translation>(节点ID: %1)</translation>
</message>
@@ -1797,8 +1910,12 @@
<translation>清除</translation>
</message>
<message>
+ <source>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</source>
+ <translation>原生隔离见证地址(又称为Bech32或者BIP-173)可减少您日后的交易费用,并且可以更好的防范打字错误,但旧版本的钱包不能识别这种地址。如果取消勾选,则会生成一个与旧版本钱包兼容的地址。</translation>
+ </message>
+ <message>
<source>Generate native segwit (Bech32) address</source>
- <translation>生成本地分离见证 (Bech32)地址</translation>
+ <translation>生成原生隔离见证 (Bech32)地址</translation>
</message>
<message>
<source>Requested payments history</source>
@@ -1975,15 +2092,15 @@
</message>
<message>
<source>Change:</source>
- <translation>变更 : </translation>
+ <translation>找零 : </translation>
</message>
<message>
<source>If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</source>
- <translation>如果激活该选项,但是零钱地址用光或者非法,将会新生成零钱地址,转入零钱。</translation>
+ <translation>如果该选项已被激活,但是找零地址却被用光了,或者是非法的,找零资金将会被转入新生成的地址。</translation>
</message>
<message>
<source>Custom change address</source>
- <translation>自定义零钱地址</translation>
+ <translation>自定义找零地址</translation>
</message>
<message>
<source>Transaction Fee:</source>
@@ -2006,6 +2123,14 @@
<translation>收起 费用设置 </translation>
</message>
<message>
+ <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size.
+
+Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis per kB" for a transaction size of 500 bytes (half of 1 kB) would ultimately yield a fee of only 50 satoshis.</source>
+ <translation>按照交易的虚拟大小自定义每kB ( 1,000 字节 )要交多少手续费。
+
+注意:手续费是按照字节数计算的,对于一笔大小为500字节(1kB的一半)的交易来说,"每kB付100聪手续费"就意味着手续费一共只付了50聪。</translation>
+ </message>
+ <message>
<source>per kilobyte</source>
<translation>每kb</translation>
</message>
@@ -2031,7 +2156,7 @@
</message>
<message>
<source>(Smart fee not initialized yet. This usually takes a few blocks...)</source>
- <translation>(智能交易费用 尚未初始化。 需要再下载一些数据块...)</translation>
+ <translation>(智能交易费用 尚未初始化。 需要再下载一些区块数据...)</translation>
</message>
<message>
<source>Send to multiple recipients at once</source>
@@ -2126,6 +2251,14 @@
<translation>你可以之后再提高手续费(有BIP-125手续费追加的标记)</translation>
</message>
<message>
+ <source>from wallet %1</source>
+ <translation>从钱包%1</translation>
+ </message>
+ <message>
+ <source>Please, review your transaction.</source>
+ <translation>请检查您的交易。</translation>
+ </message>
+ <message>
<source>Transaction fee</source>
<translation>交易费用</translation>
</message>
@@ -2134,6 +2267,10 @@
<translation>没有BIP-125手续费追加的标记。</translation>
</message>
<message>
+ <source>Total Amount</source>
+ <translation>总额</translation>
+ </message>
+ <message>
<source>Confirm send coins</source>
<translation>确认发送</translation>
</message>
@@ -2177,13 +2314,17 @@
<source>Pay only the required fee of %1</source>
<translation>只支付必要费用 %1</translation>
</message>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation><numerusform>预计 %n 个区块后开始被确认。</numerusform></translation>
+ </message>
<message>
<source>Warning: Invalid Bitcoin address</source>
<translation>警告: 比特币地址无效</translation>
</message>
<message>
<source>Warning: Unknown change address</source>
- <translation>警告:未知的更改地址</translation>
+ <translation>警告:未知的找零地址</translation>
</message>
<message>
<source>Confirm custom change address</source>
@@ -2458,6 +2599,10 @@
</context>
<context>
<name>TransactionDesc</name>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>在进一步同步完%n个区块前状态待定</numerusform></translation>
+ </message>
<message>
<source>Open until %1</source>
<translation>至 %1 个数据块时开启</translation>
@@ -2534,6 +2679,10 @@
<source>Credit</source>
<translation>收入</translation>
</message>
+ <message numerus="yes">
+ <source>matures in %n more block(s)</source>
+ <translation><numerusform>还差 %n 个区块成熟</numerusform></translation>
+ </message>
<message>
<source>not accepted</source>
<translation>未被接受</translation>
@@ -2575,6 +2724,10 @@
<translation>交易总大小</translation>
</message>
<message>
+ <source>Transaction virtual size</source>
+ <translation>交易虚拟大小</translation>
+ </message>
+ <message>
<source>Output index</source>
<translation>输出索引</translation>
</message>
@@ -2584,7 +2737,7 @@
</message>
<message>
<source>Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source>
- <translation>生成的比特币在可以使用前必须有 %1 个成熟的区块。当您生成了此区块后,它将被广播到网络中以加入区块链。如果它未成功进入区块链,其状态将变更为“不接受”并且不可使用。这可能偶尔会发生,如果另一个节点比你早几秒钟成功生成一个区块。</translation>
+ <translation>新挖出的比特币在可以使用前必须经过 %1 个区块确认的成熟过程。当您挖出此区块后,它将被广播到网络中以加入区块链。如果它未成功进入区块链,其状态将变更为“不接受”并且不可使用。这可能偶尔会发生,在另一个节点比你早几秒钟成功挖出一个区块时就会这样。</translation>
</message>
<message>
<source>Debug information</source>
@@ -2636,6 +2789,10 @@
<source>Label</source>
<translation>标签</translation>
</message>
+ <message numerus="yes">
+ <source>Open for %n more block(s)</source>
+ <translation><numerusform>在进一步同步完%n个区块前状态待定</numerusform></translation>
+ </message>
<message>
<source>Open until %1</source>
<translation>至 %1 个数据块时开启</translation>
@@ -2975,7 +3132,11 @@
<source>The wallet data was successfully saved to %1.</source>
<translation>钱包数据成功保存至 %1。</translation>
</message>
- </context>
+ <message>
+ <source>Cancel</source>
+ <translation>取消</translation>
+ </message>
+</context>
<context>
<name>bitcoin-core</name>
<message>
@@ -2992,7 +3153,7 @@
</message>
<message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
- <translation>无法在开启修剪的状态下重扫描,请使用 -reindex重新下载完整的区块链。</translation>
+ <translation>无法在开启修剪的状态下进行重扫描,请使用 -reindex重新下载完整的区块链。</translation>
</message>
<message>
<source>Error: A fatal internal error occurred, see debug.log for details</source>
@@ -3044,7 +3205,7 @@
</message>
<message>
<source>This is the transaction fee you may discard if change is smaller than dust at this level</source>
- <translation>如果对你的交易量来说,消耗的手续费微乎其微,那么这笔手续费你或许可以忽略它。</translation>
+ <translation>如果找零金额低于粉尘水平,你或许可以忽略这笔手续费。</translation>
</message>
<message>
<source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source>
@@ -3080,7 +3241,7 @@
</message>
<message>
<source>Change index out of range</source>
- <translation>修改索引超过范围</translation>
+ <translation>找零超过索引范围</translation>
</message>
<message>
<source>Copyright (C) %i-%i</source>
@@ -3088,11 +3249,11 @@
</message>
<message>
<source>Corrupted block database detected</source>
- <translation>检测发现数据块数据库损坏。请使用 -reindex参数重启客户端。</translation>
+ <translation>检测到区块数据库损坏</translation>
</message>
<message>
<source>Do you want to rebuild the block database now?</source>
- <translation>你想现在就重建块数据库吗?</translation>
+ <translation>你想现在就重建区块数据库吗?</translation>
</message>
<message>
<source>Error creating %s: You can't create non-HD wallets with this version.</source>
@@ -3100,7 +3261,7 @@
</message>
<message>
<source>Error initializing block database</source>
- <translation>初始化数据块数据库出错</translation>
+ <translation>初始化区块数据库出错</translation>
</message>
<message>
<source>Error initializing wallet database environment %s!</source>
@@ -3120,11 +3281,11 @@
</message>
<message>
<source>Error loading block database</source>
- <translation>导入数据块数据库出错</translation>
+ <translation>导入区块数据库出错</translation>
</message>
<message>
<source>Error opening block database</source>
- <translation>导入数据块数据库出错</translation>
+ <translation>导入区块数据库出错</translation>
</message>
<message>
<source>Error: Disk space is low!</source>
@@ -3159,6 +3320,14 @@
<translation>-fallbackfee 的无效数额=&lt;amount&gt;: '%s'</translation>
</message>
<message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation>指定的区块目录"%s"不存在。</translation>
+ </message>
+ <message>
+ <source>Upgrading txindex database</source>
+ <translation>正在升级交易索引数据库</translation>
+ </message>
+ <message>
<source>Loading P2P addresses...</source>
<translation>正在加载P2P地址...</translation>
</message>
@@ -3184,7 +3353,7 @@
</message>
<message>
<source>Rewinding blocks...</source>
- <translation>回退区块</translation>
+ <translation>回退区块...</translation>
</message>
<message>
<source>The source code is available from %s.</source>
@@ -3192,13 +3361,17 @@
</message>
<message>
<source>Transaction fee and change calculation failed</source>
- <translation>计算交易手续费和找零失败了</translation>
+ <translation>计算交易手续费和找零失败</translation>
</message>
<message>
<source>Unable to bind to %s on this computer. %s is probably already running.</source>
<translation>无法在本机绑定 %s 端口。%s 可能已经在运行。</translation>
</message>
<message>
+ <source>Unable to generate keys</source>
+ <translation>无法生成密钥</translation>
+ </message>
+ <message>
<source>Unsupported argument -benchmark ignored, use -debug=bench.</source>
<translation>忽略不支持的选项 -benchmark,使用 -debug=bench</translation>
</message>
@@ -3420,7 +3593,7 @@
</message>
<message>
<source>Transaction has too long of a mempool chain</source>
- <translation>交易造成内存池中的交易链太长</translation>
+ <translation>此交易在内存池中的交易链太长</translation>
</message>
<message>
<source>Transaction must have at least one recipient</source>
@@ -3435,6 +3608,14 @@
<translation>金额不足</translation>
</message>
<message>
+ <source>Can't generate a change-address key. Private keys are disabled for this wallet.</source>
+ <translation>无法生成一个找零地址密钥。对于此钱包,私钥已被禁用。</translation>
+ </message>
+ <message>
+ <source>Cannot write to data directory '%s'; check permissions.</source>
+ <translation>不能写入到数据目录'%s';请检查文件权限。</translation>
+ </message>
+ <message>
<source>Loading block index...</source>
<translation>正在加载区块索引...</translation>
</message>
diff --git a/src/qt/locale/bitcoin_zh_TW.ts b/src/qt/locale/bitcoin_zh_TW.ts
index 896dd58246..635151bcc9 100644
--- a/src/qt/locale/bitcoin_zh_TW.ts
+++ b/src/qt/locale/bitcoin_zh_TW.ts
@@ -3336,6 +3336,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p
<translation>設定 -fallbackfee=&lt;金額&gt; 的金額無效: '%s'</translation>
</message>
<message>
+ <source>Specified blocks directory "%s" does not exist.</source>
+ <translation>指定的區塊目錄 "%s" 不存在。</translation>
+ </message>
+ <message>
<source>Upgrading txindex database</source>
<translation>正在升級 txindex 資料庫</translation>
</message>
@@ -3488,12 +3492,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p
<translation>以 -walletdir 指定的路徑 "%s" 不是個目錄</translation>
</message>
<message>
- <source>Specified blocks directory "%s" does not exist.
-</source>
- <translation>指定的區塊目錄 "%s" 不存在。
-</translation>
- </message>
- <message>
<source>The transaction amount is too small to pay the fee</source>
<translation>交易金額太少而付不起手續費</translation>
</message>
diff --git a/src/qt/modaloverlay.cpp b/src/qt/modaloverlay.cpp
index c5bedf007a..8ecc33da84 100644
--- a/src/qt/modaloverlay.cpp
+++ b/src/qt/modaloverlay.cpp
@@ -71,6 +71,7 @@ void ModalOverlay::setKnownBestHeight(int count, const QDateTime& blockDate)
if (count > bestHeaderHeight) {
bestHeaderHeight = count;
bestHeaderDate = blockDate;
+ UpdateHeaderSyncLabel();
}
}
@@ -136,11 +137,16 @@ void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVeri
if (estimateNumHeadersLeft < HEADER_HEIGHT_DELTA_SYNC && hasBestHeader) {
ui->numberOfBlocksLeft->setText(QString::number(bestHeaderHeight - count));
} else {
- ui->numberOfBlocksLeft->setText(tr("Unknown. Syncing Headers (%1)...").arg(bestHeaderHeight));
+ UpdateHeaderSyncLabel();
ui->expectedTimeLeft->setText(tr("Unknown..."));
}
}
+void ModalOverlay::UpdateHeaderSyncLabel() {
+ int est_headers_left = bestHeaderDate.secsTo(QDateTime::currentDateTime()) / Params().GetConsensus().nPowTargetSpacing;
+ ui->numberOfBlocksLeft->setText(tr("Unknown. Syncing Headers (%1, %2%)...").arg(bestHeaderHeight).arg(QString::number(100.0 / (bestHeaderHeight + est_headers_left) * bestHeaderHeight, 'f', 1)));
+}
+
void ModalOverlay::toggleVisibility()
{
showHide(layerIsVisible, true);
diff --git a/src/qt/modaloverlay.h b/src/qt/modaloverlay.h
index 66a6ad1e02..cf8b53f2b3 100644
--- a/src/qt/modaloverlay.h
+++ b/src/qt/modaloverlay.h
@@ -45,6 +45,7 @@ private:
QVector<QPair<qint64, double> > blockProcessTime;
bool layerIsVisible;
bool userClosed;
+ void UpdateHeaderSyncLabel();
};
#endif // BITCOIN_QT_MODALOVERLAY_H
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index 27cec06d4b..9094aeff56 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -10,6 +10,7 @@
#include <qt/forms/ui_optionsdialog.h>
#include <qt/bitcoinunits.h>
+#include <qt/guiconstants.h>
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
@@ -37,10 +38,6 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
/* Main elements init */
ui->databaseCache->setMinimum(nMinDbCache);
ui->databaseCache->setMaximum(nMaxDbCache);
- static const uint64_t GiB = 1024 * 1024 * 1024;
- static const uint64_t nMinDiskSpace = MIN_DISK_SPACE_FOR_BLOCK_FILES / GiB +
- (MIN_DISK_SPACE_FOR_BLOCK_FILES % GiB) ? 1 : 0;
- ui->pruneSize->setMinimum(nMinDiskSpace);
ui->threadsScriptVerif->setMinimum(-GetNumCores());
ui->threadsScriptVerif->setMaximum(MAX_SCRIPTCHECK_THREADS);
ui->pruneWarning->setVisible(false);
@@ -74,6 +71,12 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
#ifdef Q_OS_MAC
/* remove Window tab on Mac */
ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->tabWindow));
+#if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && MAC_OS_X_VERSION_MIN_REQUIRED > 101100
+ /* hide launch at startup option if compiled against macOS > 10.11 (removed API) */
+ ui->bitcoinAtStartup->setVisible(false);
+ ui->verticalLayout_Main->removeWidget(ui->bitcoinAtStartup);
+ ui->verticalLayout_Main->removeItem(ui->horizontalSpacer_0_Main);
+#endif
#endif
/* remove Wallet tab in case of -disablewallet */
@@ -161,6 +164,10 @@ void OptionsDialog::setModel(OptionsModel *_model)
mapper->toFirst();
updateDefaultProxyNets();
+
+ // Prune values are in GB to be consistent with intro.cpp
+ static constexpr uint64_t nMinDiskSpace = (MIN_DISK_SPACE_FOR_BLOCK_FILES / GB_BYTES) + (MIN_DISK_SPACE_FOR_BLOCK_FILES % GB_BYTES) ? 1 : 0;
+ ui->pruneSize->setRange(nMinDiskSpace, _model->node().getAssumedBlockchainSize());
}
/* warn when one of the following settings changes by user action (placed here so init via mapper doesn't trigger them) */
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index d04a2cf862..62496a57f4 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -9,6 +9,7 @@
#include <qt/optionsmodel.h>
#include <qt/bitcoinunits.h>
+#include <qt/guiconstants.h>
#include <qt/guiutil.h>
#include <interfaces/node.h>
@@ -92,10 +93,10 @@ void OptionsModel::Init(bool resetSettings)
settings.setValue("bPrune", false);
if (!settings.contains("nPruneSize"))
settings.setValue("nPruneSize", 2);
- // Convert prune size to MB:
- const uint64_t nPruneSizeMB = settings.value("nPruneSize").toInt() * 1000;
- if (!m_node.softSetArg("-prune", settings.value("bPrune").toBool() ? std::to_string(nPruneSizeMB) : "0")) {
- addOverriddenOption("-prune");
+ // Convert prune size from GB to MiB:
+ const uint64_t nPruneSizeMiB = (settings.value("nPruneSize").toInt() * GB_BYTES) >> 20;
+ if (!m_node.softSetArg("-prune", settings.value("bPrune").toBool() ? std::to_string(nPruneSizeMiB) : "0")) {
+ addOverriddenOption("-prune");
}
if (!settings.contains("nDatabaseCache"))
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index bc96b5a6f7..22a79a12bb 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -100,8 +100,13 @@ void ReceiveCoinsDialog::setModel(WalletModel *_model)
ui->useBech32->setCheckState(Qt::Unchecked);
}
- // eventually disable the main receive button if private key operations are disabled
- ui->receiveButton->setEnabled(!model->privateKeysDisabled());
+ // Set the button to be enabled or disabled based on whether the wallet can give out new addresses.
+ ui->receiveButton->setEnabled(model->canGetAddresses());
+
+ // Enable/disable the receive button if the wallet is now able/unable to give out new addresses.
+ connect(model, &WalletModel::canGetAddressesChanged, [this] {
+ ui->receiveButton->setEnabled(model->canGetAddresses());
+ });
}
}
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 96de18b2bf..fc1e14b031 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -1211,16 +1211,16 @@ void RPCConsole::banSelectedNode(int bantime)
// Get currently selected peer address
NodeId id = nodes.at(i).data().toLongLong();
- // Get currently selected peer address
- int detailNodeRow = clientModel->getPeerTableModel()->getRowByNodeId(id);
- if(detailNodeRow < 0)
- return;
-
- // Find possible nodes, ban it and clear the selected node
- const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow);
- if(stats) {
+ // Get currently selected peer address
+ int detailNodeRow = clientModel->getPeerTableModel()->getRowByNodeId(id);
+ if (detailNodeRow < 0) return;
+
+ // Find possible nodes, ban it and clear the selected node
+ const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow);
+ if (stats) {
m_node.ban(stats->nodeStats.addr, BanReasonManuallyAdded, bantime);
- }
+ m_node.disconnect(stats->nodeStats.addr);
+ }
}
clearSelectedNode();
clientModel->getBanTableModel()->refresh();
diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp
index 3e414df1f0..7f5e92ea9f 100644
--- a/src/qt/test/addressbooktests.cpp
+++ b/src/qt/test/addressbooktests.cpp
@@ -95,6 +95,7 @@ void TestAddAddressesToSendBook()
}
auto check_addbook_size = [&wallet](int expected_size) {
+ LOCK(wallet->cs_wallet);
QCOMPARE(static_cast<int>(wallet->mapAddressBook.size()), expected_size);
};
diff --git a/src/qt/test/paymentservertests.cpp b/src/qt/test/paymentservertests.cpp
index 94907595f5..f0eca899fc 100644
--- a/src/qt/test/paymentservertests.cpp
+++ b/src/qt/test/paymentservertests.cpp
@@ -181,12 +181,12 @@ void PaymentServerTests::paymentServerTests()
QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), true);
// Test BIP70 DoS protection:
- unsigned char randData[BIP70_MAX_PAYMENTREQUEST_SIZE + 1];
- GetRandBytes(randData, sizeof(randData));
+ auto randdata = FastRandomContext().randbytes(BIP70_MAX_PAYMENTREQUEST_SIZE + 1);
+
// Write data to a temp file:
QTemporaryFile tempFile;
tempFile.open();
- tempFile.write((const char*)randData, sizeof(randData));
+ tempFile.write((const char*)randdata.data(), randdata.size());
tempFile.close();
// compares 50001 <= BIP70_MAX_PAYMENTREQUEST_SIZE == false
QCOMPARE(PaymentServer::verifySize(tempFile.size()), false);
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index 610d83acb6..2b50a2ba81 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -1,6 +1,7 @@
#include <qt/test/wallettests.h>
#include <qt/test/util.h>
+#include <init.h>
#include <interfaces/chain.h>
#include <interfaces/node.h>
#include <base58.h>
@@ -146,13 +147,10 @@ void TestGUI()
auto locked_chain = wallet->chain().lock();
WalletRescanReserver reserver(wallet.get());
reserver.reserve();
- const CBlockIndex* const null_block = nullptr;
- const CBlockIndex *stop_block, *failed_block;
- QCOMPARE(
- wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, failed_block, stop_block, true /* fUpdate */),
- CWallet::ScanResult::SUCCESS);
- QCOMPARE(stop_block, chainActive.Tip());
- QCOMPARE(failed_block, null_block);
+ CWallet::ScanResult result = wallet->ScanForWalletTransactions(locked_chain->getBlockHash(0), {} /* stop_block */, reserver, true /* fUpdate */);
+ QCOMPARE(result.status, CWallet::ScanResult::SUCCESS);
+ QCOMPARE(result.last_scanned_block, chainActive.Tip()->GetBlockHash());
+ QVERIFY(result.last_failed_block.IsNull());
}
wallet->SetBroadcastTransactions(true);
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index eb6437eb31..762ec434a1 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -229,8 +229,8 @@ void TransactionView::setModel(WalletModel *_model)
transactionView->setAlternatingRowColors(true);
transactionView->setSelectionBehavior(QAbstractItemView::SelectRows);
transactionView->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ transactionView->horizontalHeader()->setSortIndicator(TransactionTableModel::Date, Qt::DescendingOrder);
transactionView->setSortingEnabled(true);
- transactionView->sortByColumn(TransactionTableModel::Date, Qt::DescendingOrder);
transactionView->verticalHeader()->hide();
transactionView->setColumnWidth(TransactionTableModel::Status, STATUS_COLUMN_WIDTH);
diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp
index df2b7a3f9b..3483c75970 100644
--- a/src/qt/walletcontroller.cpp
+++ b/src/qt/walletcontroller.cpp
@@ -9,6 +9,7 @@
#include <algorithm>
+#include <QMessageBox>
#include <QMutexLocker>
#include <QThread>
@@ -25,11 +26,17 @@ WalletController::WalletController(interfaces::Node& node, const PlatformStyle*
for (std::unique_ptr<interfaces::Wallet>& wallet : m_node.getWallets()) {
getOrCreateWallet(std::move(wallet));
}
+
+ m_activity_thread.start();
}
// Not using the default destructor because not all member types definitions are
// available in the header, just forward declared.
-WalletController::~WalletController() {}
+WalletController::~WalletController()
+{
+ m_activity_thread.quit();
+ m_activity_thread.wait();
+}
std::vector<WalletModel*> WalletController::getWallets() const
{
@@ -37,6 +44,25 @@ std::vector<WalletModel*> WalletController::getWallets() const
return m_wallets;
}
+std::vector<std::string> WalletController::getWalletsAvailableToOpen() const
+{
+ QMutexLocker locker(&m_mutex);
+ std::vector<std::string> wallets = m_node.listWalletDir();
+ for (WalletModel* wallet_model : m_wallets) {
+ auto it = std::remove(wallets.begin(), wallets.end(), wallet_model->wallet().getWalletName());
+ if (it != wallets.end()) wallets.erase(it);
+ }
+ return wallets;
+}
+
+OpenWalletActivity* WalletController::openWallet(const std::string& name, QWidget* parent)
+{
+ OpenWalletActivity* activity = new OpenWalletActivity(this, name);
+ activity->moveToThread(&m_activity_thread);
+ QMetaObject::invokeMethod(activity, "open", Qt::QueuedConnection);
+ return activity;
+}
+
WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wallet> wallet)
{
QMutexLocker locker(&m_mutex);
@@ -93,3 +119,24 @@ void WalletController::removeAndDeleteWallet(WalletModel* wallet_model)
// CWallet shared pointer.
delete wallet_model;
}
+
+
+OpenWalletActivity::OpenWalletActivity(WalletController* wallet_controller, const std::string& name)
+ : m_wallet_controller(wallet_controller)
+ , m_name(name)
+{}
+
+void OpenWalletActivity::open()
+{
+ std::string error, warning;
+ std::unique_ptr<interfaces::Wallet> wallet = m_wallet_controller->m_node.loadWallet(m_name, error, warning);
+ if (!warning.empty()) {
+ Q_EMIT message(QMessageBox::Warning, QString::fromStdString(warning));
+ }
+ if (wallet) {
+ Q_EMIT opened(m_wallet_controller->getOrCreateWallet(std::move(wallet)));
+ } else {
+ Q_EMIT message(QMessageBox::Critical, QString::fromStdString(error));
+ }
+ Q_EMIT finished();
+}
diff --git a/src/qt/walletcontroller.h b/src/qt/walletcontroller.h
index 22b71b07ff..f19c0e1f3d 100644
--- a/src/qt/walletcontroller.h
+++ b/src/qt/walletcontroller.h
@@ -12,7 +12,9 @@
#include <memory>
#include <vector>
+#include <QMessageBox>
#include <QMutex>
+#include <QThread>
class OptionsModel;
class PlatformStyle;
@@ -22,6 +24,8 @@ class Handler;
class Node;
} // namespace interfaces
+class OpenWalletActivity;
+
/**
* Controller between interfaces::Node, WalletModel instances and the GUI.
*/
@@ -37,6 +41,9 @@ public:
~WalletController();
std::vector<WalletModel*> getWallets() const;
+ std::vector<std::string> getWalletsAvailableToOpen() const;
+
+ OpenWalletActivity* openWallet(const std::string& name, QWidget* parent = nullptr);
private Q_SLOTS:
void addWallet(WalletModel* wallet_model);
@@ -48,12 +55,35 @@ Q_SIGNALS:
void coinsSent(WalletModel* wallet_model, SendCoinsRecipient recipient, QByteArray transaction);
private:
+ QThread m_activity_thread;
interfaces::Node& m_node;
const PlatformStyle* const m_platform_style;
OptionsModel* const m_options_model;
mutable QMutex m_mutex;
std::vector<WalletModel*> m_wallets;
std::unique_ptr<interfaces::Handler> m_handler_load_wallet;
+
+ friend class OpenWalletActivity;
+};
+
+class OpenWalletActivity : public QObject
+{
+ Q_OBJECT
+
+public:
+ OpenWalletActivity(WalletController* wallet_controller, const std::string& name);
+
+public Q_SLOTS:
+ void open();
+
+Q_SIGNALS:
+ void message(QMessageBox::Icon icon, const QString text);
+ void finished();
+ void opened(WalletModel* wallet_model);
+
+private:
+ WalletController* const m_wallet_controller;
+ std::string const m_name;
};
#endif // BITCOIN_QT_WALLETCONTROLLER_H
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index f139152042..f4f3be8f43 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -423,6 +423,11 @@ static void NotifyWatchonlyChanged(WalletModel *walletmodel, bool fHaveWatchonly
Q_ARG(bool, fHaveWatchonly));
}
+static void NotifyCanGetAddressesChanged(WalletModel* walletmodel)
+{
+ QMetaObject::invokeMethod(walletmodel, "canGetAddressesChanged");
+}
+
void WalletModel::subscribeToCoreSignals()
{
// Connect signals to wallet
@@ -432,6 +437,7 @@ void WalletModel::subscribeToCoreSignals()
m_handler_transaction_changed = m_wallet->handleTransactionChanged(std::bind(NotifyTransactionChanged, this, std::placeholders::_1, std::placeholders::_2));
m_handler_show_progress = m_wallet->handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2));
m_handler_watch_only_changed = m_wallet->handleWatchOnlyChanged(std::bind(NotifyWatchonlyChanged, this, std::placeholders::_1));
+ m_handler_can_get_addrs_changed = m_wallet->handleCanGetAddressesChanged(boost::bind(NotifyCanGetAddressesChanged, this));
}
void WalletModel::unsubscribeFromCoreSignals()
@@ -443,6 +449,7 @@ void WalletModel::unsubscribeFromCoreSignals()
m_handler_transaction_changed->disconnect();
m_handler_show_progress->disconnect();
m_handler_watch_only_changed->disconnect();
+ m_handler_can_get_addrs_changed->disconnect();
}
// WalletModel::UnlockContext implementation
@@ -571,6 +578,11 @@ bool WalletModel::privateKeysDisabled() const
return m_wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
}
+bool WalletModel::canGetAddresses() const
+{
+ return m_wallet->canGetAddresses();
+}
+
QString WalletModel::getWalletName() const
{
return QString::fromStdString(m_wallet->getWalletName());
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index c3c8f36909..b123befbb4 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -214,6 +214,7 @@ public:
static bool isWalletEnabled();
bool privateKeysDisabled() const;
+ bool canGetAddresses() const;
interfaces::Node& node() const { return m_node; }
interfaces::Wallet& wallet() const { return *m_wallet; }
@@ -232,6 +233,7 @@ private:
std::unique_ptr<interfaces::Handler> m_handler_transaction_changed;
std::unique_ptr<interfaces::Handler> m_handler_show_progress;
std::unique_ptr<interfaces::Handler> m_handler_watch_only_changed;
+ std::unique_ptr<interfaces::Handler> m_handler_can_get_addrs_changed;
interfaces::Node& m_node;
bool fHaveWatchOnly;
@@ -283,6 +285,9 @@ Q_SIGNALS:
// Signal that wallet is about to be removed
void unload();
+ // Notify that there are now keys in the keypool
+ void canGetAddressesChanged();
+
public Q_SLOTS:
/* Wallet status might have changed */
void updateStatus();
diff --git a/src/random.cpp b/src/random.cpp
index f8ffda136d..3277c34d3f 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -19,6 +19,8 @@
#include <chrono>
#include <thread>
+#include <support/allocators/secure.h>
+
#ifndef WIN32
#include <fcntl.h>
#include <sys/time.h>
@@ -47,6 +49,7 @@
#include <openssl/err.h>
#include <openssl/rand.h>
+#include <openssl/conf.h>
[[noreturn]] static void RandFailure()
{
@@ -54,7 +57,7 @@
std::abort();
}
-static inline int64_t GetPerformanceCounter()
+static inline int64_t GetPerformanceCounter() noexcept
{
// Read the hardware time stamp counter when available.
// See https://en.wikipedia.org/wiki/Time_Stamp_Counter for more information.
@@ -74,27 +77,38 @@ static inline int64_t GetPerformanceCounter()
#endif
}
-
#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
-static std::atomic<bool> hwrand_initialized{false};
static bool rdrand_supported = false;
static constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000;
-static void RDRandInit()
+static void InitHardwareRand()
{
uint32_t eax, ebx, ecx, edx;
if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) && (ecx & CPUID_F1_ECX_RDRAND)) {
- LogPrintf("Using RdRand as an additional entropy source\n");
rdrand_supported = true;
}
- hwrand_initialized.store(true);
}
+
+static void ReportHardwareRand()
+{
+ if (rdrand_supported) {
+ // This must be done in a separate function, as HWRandInit() may be indirectly called
+ // from global constructors, before logging is initialized.
+ LogPrintf("Using RdRand as an additional entropy source\n");
+ }
+}
+
#else
-static void RDRandInit() {}
+/* Access to other hardware random number generators could be added here later,
+ * assuming it is sufficiently fast (in the order of a few hundred CPU cycles).
+ * Slower sources should probably be invoked separately, and/or only from
+ * RandAddSeedSleep (which is called during idle background operation).
+ */
+static void InitHardwareRand() {}
+static void ReportHardwareRand() {}
#endif
-static bool GetHWRand(unsigned char* ent32) {
+static bool GetHardwareRand(unsigned char* ent32) noexcept {
#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
- assert(hwrand_initialized.load(std::memory_order_relaxed));
if (rdrand_supported) {
uint8_t ok;
// Not all assemblers support the rdrand instruction, write it in hex.
@@ -129,18 +143,8 @@ static bool GetHWRand(unsigned char* ent32) {
return false;
}
-void RandAddSeed()
+static void RandAddSeedPerfmon(CSHA512& hasher)
{
- // Seed with CPU performance counter
- int64_t nCounter = GetPerformanceCounter();
- RAND_add(&nCounter, sizeof(nCounter), 1.5);
- memory_cleanse((void*)&nCounter, sizeof(nCounter));
-}
-
-static void RandAddSeedPerfmon()
-{
- RandAddSeed();
-
#ifdef WIN32
// Don't need this on Linux, OpenSSL automatically uses /dev/urandom
// Seed with the entire set of perfmon data
@@ -164,15 +168,15 @@ static void RandAddSeedPerfmon()
}
RegCloseKey(HKEY_PERFORMANCE_DATA);
if (ret == ERROR_SUCCESS) {
- RAND_add(vData.data(), nSize, nSize / 100.0);
+ hasher.Write(vData.data(), nSize);
memory_cleanse(vData.data(), nSize);
- LogPrint(BCLog::RAND, "%s: %lu bytes\n", __func__, nSize);
} else {
- static bool warned = false; // Warn only once
- if (!warned) {
- LogPrintf("%s: Warning: RegQueryValueExA(HKEY_PERFORMANCE_DATA) failed with code %i\n", __func__, ret);
- warned = true;
- }
+ // Performance data is only a best-effort attempt at improving the
+ // situation when the OS randomness (and other sources) aren't
+ // adequate. As a result, failure to read it is isn't considered critical,
+ // so we don't call RandFailure().
+ // TODO: Add logging when the logger is made functional before global
+ // constructors have been invoked.
}
#endif
}
@@ -272,106 +276,257 @@ void GetOSRand(unsigned char *ent32)
#endif
}
-void GetRandBytes(unsigned char* buf, int num)
+void LockingCallbackOpenSSL(int mode, int i, const char* file, int line);
+
+namespace {
+
+class RNGState {
+ Mutex m_mutex;
+ /* The RNG state consists of 256 bits of entropy, taken from the output of
+ * one operation's SHA512 output, and fed as input to the next one.
+ * Carrying 256 bits of entropy should be sufficient to guarantee
+ * unpredictability as long as any entropy source was ever unpredictable
+ * to an attacker. To protect against situations where an attacker might
+ * observe the RNG's state, fresh entropy is always mixed when
+ * GetStrongRandBytes is called.
+ */
+ unsigned char m_state[32] GUARDED_BY(m_mutex) = {0};
+ uint64_t m_counter GUARDED_BY(m_mutex) = 0;
+ bool m_strongly_seeded GUARDED_BY(m_mutex) = false;
+ std::unique_ptr<Mutex[]> m_mutex_openssl;
+
+public:
+ RNGState() noexcept
+ {
+ InitHardwareRand();
+
+ // Init OpenSSL library multithreading support
+ m_mutex_openssl.reset(new Mutex[CRYPTO_num_locks()]);
+ CRYPTO_set_locking_callback(LockingCallbackOpenSSL);
+
+ // OpenSSL can optionally load a config file which lists optional loadable modules and engines.
+ // We don't use them so we don't require the config. However some of our libs may call functions
+ // which attempt to load the config file, possibly resulting in an exit() or crash if it is missing
+ // or corrupt. Explicitly tell OpenSSL not to try to load the file. The result for our libs will be
+ // that the config appears to have been loaded and there are no modules/engines available.
+ OPENSSL_no_config();
+ }
+
+ ~RNGState()
+ {
+ // Securely erase the memory used by the OpenSSL PRNG
+ RAND_cleanup();
+ // Shutdown OpenSSL library multithreading support
+ CRYPTO_set_locking_callback(nullptr);
+ }
+
+ /** Extract up to 32 bytes of entropy from the RNG state, mixing in new entropy from hasher.
+ *
+ * If this function has never been called with strong_seed = true, false is returned.
+ */
+ bool MixExtract(unsigned char* out, size_t num, CSHA512&& hasher, bool strong_seed) noexcept
+ {
+ assert(num <= 32);
+ unsigned char buf[64];
+ static_assert(sizeof(buf) == CSHA512::OUTPUT_SIZE, "Buffer needs to have hasher's output size");
+ bool ret;
+ {
+ LOCK(m_mutex);
+ ret = (m_strongly_seeded |= strong_seed);
+ // Write the current state of the RNG into the hasher
+ hasher.Write(m_state, 32);
+ // Write a new counter number into the state
+ hasher.Write((const unsigned char*)&m_counter, sizeof(m_counter));
+ ++m_counter;
+ // Finalize the hasher
+ hasher.Finalize(buf);
+ // Store the last 32 bytes of the hash output as new RNG state.
+ memcpy(m_state, buf + 32, 32);
+ }
+ // If desired, copy (up to) the first 32 bytes of the hash output as output.
+ if (num) {
+ assert(out != nullptr);
+ memcpy(out, buf, num);
+ }
+ // Best effort cleanup of internal state
+ hasher.Reset();
+ memory_cleanse(buf, 64);
+ return ret;
+ }
+
+ Mutex& GetOpenSSLMutex(int i) { return m_mutex_openssl[i]; }
+};
+
+RNGState& GetRNGState() noexcept
{
- if (RAND_bytes(buf, num) != 1) {
- RandFailure();
+ // This C++11 idiom relies on the guarantee that static variable are initialized
+ // on first call, even when multiple parallel calls are permitted.
+ static std::vector<RNGState, secure_allocator<RNGState>> g_rng(1);
+ return g_rng[0];
+}
+}
+
+void LockingCallbackOpenSSL(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS
+{
+ RNGState& rng = GetRNGState();
+
+ if (mode & CRYPTO_LOCK) {
+ rng.GetOpenSSLMutex(i).lock();
+ } else {
+ rng.GetOpenSSLMutex(i).unlock();
}
}
-static void AddDataToRng(void* data, size_t len);
+/* A note on the use of noexcept in the seeding functions below:
+ *
+ * None of the RNG code should ever throw any exception, with the sole exception
+ * of MilliSleep in SeedSleep, which can (and does) support interruptions which
+ * cause a boost::thread_interrupted to be thrown.
+ *
+ * This means that SeedSleep, and all functions that invoke it are throwing.
+ * However, we know that GetRandBytes() and GetStrongRandBytes() never trigger
+ * this sleeping logic, so they are noexcept. The same is true for all the
+ * GetRand*() functions that use GetRandBytes() indirectly.
+ *
+ * TODO: After moving away from interruptible boost-based thread management,
+ * everything can become noexcept here.
+ */
-void RandAddSeedSleep()
+static void SeedTimestamp(CSHA512& hasher) noexcept
{
- int64_t nPerfCounter1 = GetPerformanceCounter();
- std::this_thread::sleep_for(std::chrono::milliseconds(1));
- int64_t nPerfCounter2 = GetPerformanceCounter();
+ int64_t perfcounter = GetPerformanceCounter();
+ hasher.Write((const unsigned char*)&perfcounter, sizeof(perfcounter));
+}
- // Combine with and update state
- AddDataToRng(&nPerfCounter1, sizeof(nPerfCounter1));
- AddDataToRng(&nPerfCounter2, sizeof(nPerfCounter2));
+static void SeedFast(CSHA512& hasher) noexcept
+{
+ unsigned char buffer[32];
+
+ // Stack pointer to indirectly commit to thread/callstack
+ const unsigned char* ptr = buffer;
+ hasher.Write((const unsigned char*)&ptr, sizeof(ptr));
+
+ // Hardware randomness is very fast when available; use it always.
+ bool have_hw_rand = GetHardwareRand(buffer);
+ if (have_hw_rand) hasher.Write(buffer, sizeof(buffer));
- memory_cleanse(&nPerfCounter1, sizeof(nPerfCounter1));
- memory_cleanse(&nPerfCounter2, sizeof(nPerfCounter2));
+ // High-precision timestamp
+ SeedTimestamp(hasher);
}
+static void SeedSlow(CSHA512& hasher) noexcept
+{
+ unsigned char buffer[32];
-static Mutex cs_rng_state;
-static unsigned char rng_state[32] = {0};
-static uint64_t rng_counter = 0;
+ // Everything that the 'fast' seeder includes
+ SeedFast(hasher);
-static void AddDataToRng(void* data, size_t len) {
- CSHA512 hasher;
- hasher.Write((const unsigned char*)&len, sizeof(len));
- hasher.Write((const unsigned char*)data, len);
- unsigned char buf[64];
- {
- WAIT_LOCK(cs_rng_state, lock);
- hasher.Write(rng_state, sizeof(rng_state));
- hasher.Write((const unsigned char*)&rng_counter, sizeof(rng_counter));
- ++rng_counter;
- hasher.Finalize(buf);
- memcpy(rng_state, buf + 32, 32);
- }
- memory_cleanse(buf, 64);
+ // OS randomness
+ GetOSRand(buffer);
+ hasher.Write(buffer, sizeof(buffer));
+
+ // OpenSSL RNG (for now)
+ RAND_bytes(buffer, sizeof(buffer));
+ hasher.Write(buffer, sizeof(buffer));
+
+ // High-precision timestamp.
+ //
+ // Note that we also commit to a timestamp in the Fast seeder, so we indirectly commit to a
+ // benchmark of all the entropy gathering sources in this function).
+ SeedTimestamp(hasher);
}
-void GetStrongRandBytes(unsigned char* out, int num)
+static void SeedSleep(CSHA512& hasher)
{
- assert(num <= 32);
- CSHA512 hasher;
- unsigned char buf[64];
+ // Everything that the 'fast' seeder includes
+ SeedFast(hasher);
+
+ // High-precision timestamp
+ SeedTimestamp(hasher);
- // First source: OpenSSL's RNG
- RandAddSeedPerfmon();
- GetRandBytes(buf, 32);
- hasher.Write(buf, 32);
+ // Sleep for 1ms
+ MilliSleep(1);
- // Second source: OS RNG
- GetOSRand(buf);
- hasher.Write(buf, 32);
+ // High-precision timestamp after sleeping (as we commit to both the time before and after, this measures the delay)
+ SeedTimestamp(hasher);
- // Third source: HW RNG, if available.
- if (GetHWRand(buf)) {
- hasher.Write(buf, 32);
+ // Windows performance monitor data (once every 10 minutes)
+ RandAddSeedPerfmon(hasher);
+}
+
+static void SeedStartup(CSHA512& hasher) noexcept
+{
+#ifdef WIN32
+ RAND_screen();
+#endif
+
+ // Everything that the 'slow' seeder includes.
+ SeedSlow(hasher);
+
+ // Windows performance monitor data.
+ RandAddSeedPerfmon(hasher);
+}
+
+enum class RNGLevel {
+ FAST, //!< Automatically called by GetRandBytes
+ SLOW, //!< Automatically called by GetStrongRandBytes
+ SLEEP, //!< Called by RandAddSeedSleep()
+};
+
+static void ProcRand(unsigned char* out, int num, RNGLevel level)
+{
+ // Make sure the RNG is initialized first (as all Seed* function possibly need hwrand to be available).
+ RNGState& rng = GetRNGState();
+
+ assert(num <= 32);
+
+ CSHA512 hasher;
+ switch (level) {
+ case RNGLevel::FAST:
+ SeedFast(hasher);
+ break;
+ case RNGLevel::SLOW:
+ SeedSlow(hasher);
+ break;
+ case RNGLevel::SLEEP:
+ SeedSleep(hasher);
+ break;
}
// Combine with and update state
- {
- WAIT_LOCK(cs_rng_state, lock);
- hasher.Write(rng_state, sizeof(rng_state));
- hasher.Write((const unsigned char*)&rng_counter, sizeof(rng_counter));
- ++rng_counter;
- hasher.Finalize(buf);
- memcpy(rng_state, buf + 32, 32);
+ if (!rng.MixExtract(out, num, std::move(hasher), false)) {
+ // On the first invocation, also seed with SeedStartup().
+ CSHA512 startup_hasher;
+ SeedStartup(startup_hasher);
+ rng.MixExtract(out, num, std::move(startup_hasher), true);
}
- // Produce output
- memcpy(out, buf, num);
- memory_cleanse(buf, 64);
+ // For anything but the 'fast' level, feed the resulting RNG output (after an additional hashing step) back into OpenSSL.
+ if (level != RNGLevel::FAST) {
+ unsigned char buf[64];
+ CSHA512().Write(out, num).Finalize(buf);
+ RAND_add(buf, sizeof(buf), num);
+ memory_cleanse(buf, 64);
+ }
}
-uint64_t GetRand(uint64_t nMax)
-{
- if (nMax == 0)
- return 0;
+void GetRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNGLevel::FAST); }
+void GetStrongRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNGLevel::SLOW); }
+void RandAddSeedSleep() { ProcRand(nullptr, 0, RNGLevel::SLEEP); }
- // The range of the random source must be a multiple of the modulus
- // to give every possible output value an equal possibility
- uint64_t nRange = (std::numeric_limits<uint64_t>::max() / nMax) * nMax;
- uint64_t nRand = 0;
- do {
- GetRandBytes((unsigned char*)&nRand, sizeof(nRand));
- } while (nRand >= nRange);
- return (nRand % nMax);
+bool g_mock_deterministic_tests{false};
+
+uint64_t GetRand(uint64_t nMax) noexcept
+{
+ return FastRandomContext(g_mock_deterministic_tests).randrange(nMax);
}
-int GetRandInt(int nMax)
+int GetRandInt(int nMax) noexcept
{
return GetRand(nMax);
}
-uint256 GetRandHash()
+uint256 GetRandHash() noexcept
{
uint256 hash;
GetRandBytes((unsigned char*)&hash, sizeof(hash));
@@ -385,7 +540,7 @@ void FastRandomContext::RandomSeed()
requires_seed = false;
}
-uint256 FastRandomContext::rand256()
+uint256 FastRandomContext::rand256() noexcept
{
if (bytebuf_size < 32) {
FillByteBuffer();
@@ -406,7 +561,7 @@ std::vector<unsigned char> FastRandomContext::randbytes(size_t len)
return ret;
}
-FastRandomContext::FastRandomContext(const uint256& seed) : requires_seed(false), bytebuf_size(0), bitbuf_size(0)
+FastRandomContext::FastRandomContext(const uint256& seed) noexcept : requires_seed(false), bytebuf_size(0), bitbuf_size(0)
{
rng.SetKey(seed.begin(), 32);
}
@@ -449,13 +604,15 @@ bool Random_SanityCheck()
if (stop == start) return false;
// We called GetPerformanceCounter. Use it as entropy.
- RAND_add((const unsigned char*)&start, sizeof(start), 1);
- RAND_add((const unsigned char*)&stop, sizeof(stop), 1);
+ CSHA512 to_add;
+ to_add.Write((const unsigned char*)&start, sizeof(start));
+ to_add.Write((const unsigned char*)&stop, sizeof(stop));
+ GetRNGState().MixExtract(nullptr, 0, std::move(to_add), false);
return true;
}
-FastRandomContext::FastRandomContext(bool fDeterministic) : requires_seed(!fDeterministic), bytebuf_size(0), bitbuf_size(0)
+FastRandomContext::FastRandomContext(bool fDeterministic) noexcept : requires_seed(!fDeterministic), bytebuf_size(0), bitbuf_size(0)
{
if (!fDeterministic) {
return;
@@ -480,5 +637,8 @@ FastRandomContext& FastRandomContext::operator=(FastRandomContext&& from) noexce
void RandomInit()
{
- RDRandInit();
+ // Invoke RNG code to trigger initialization (if not already performed)
+ ProcRand(nullptr, 0, RNGLevel::FAST);
+
+ ReportHardwareRand();
}
diff --git a/src/random.h b/src/random.h
index 00e90abbc5..4c73f3822a 100644
--- a/src/random.h
+++ b/src/random.h
@@ -13,33 +13,83 @@
#include <stdint.h>
#include <limits>
-/* Seed OpenSSL PRNG with additional entropy data */
-void RandAddSeed();
+/**
+ * Overall design of the RNG and entropy sources.
+ *
+ * We maintain a single global 256-bit RNG state for all high-quality randomness.
+ * The following (classes of) functions interact with that state by mixing in new
+ * entropy, and optionally extracting random output from it:
+ *
+ * - The GetRand*() class of functions, as well as construction of FastRandomContext objects,
+ * perform 'fast' seeding, consisting of mixing in:
+ * - A stack pointer (indirectly committing to calling thread and call stack)
+ * - A high-precision timestamp (rdtsc when available, c++ high_resolution_clock otherwise)
+ * - Hardware RNG (rdrand) when available.
+ * These entropy sources are very fast, and only designed to protect against situations
+ * where a VM state restore/copy results in multiple systems with the same randomness.
+ * FastRandomContext on the other hand does not protect against this once created, but
+ * is even faster (and acceptable to use inside tight loops).
+ *
+ * - The GetStrongRand*() class of function perform 'slow' seeding, including everything
+ * that fast seeding includes, but additionally:
+ * - OS entropy (/dev/urandom, getrandom(), ...). The application will terminate if
+ * this entropy source fails.
+ * - Bytes from OpenSSL's RNG (which itself may be seeded from various sources)
+ * - Another high-precision timestamp (indirectly committing to a benchmark of all the
+ * previous sources).
+ * These entropy sources are slower, but designed to make sure the RNG state contains
+ * fresh data that is unpredictable to attackers.
+ *
+ * - RandAddSeedSleep() seeds everything that fast seeding includes, but additionally:
+ * - A high-precision timestamp before and after sleeping 1ms.
+ * - (On Windows) Once every 10 minutes, performance monitoring data from the OS.
+ * These just exploit the fact the system is idle to improve the quality of the RNG
+ * slightly.
+ *
+ * On first use of the RNG (regardless of what function is called first), all entropy
+ * sources used in the 'slow' seeder are included, but also:
+ * - (On Windows) Performance monitoring data from the OS.
+ * - (On Windows) Through OpenSSL, the screen contents.
+ *
+ * When mixing in new entropy, H = SHA512(entropy || old_rng_state) is computed, and
+ * (up to) the first 32 bytes of H are produced as output, while the last 32 bytes
+ * become the new RNG state.
+*/
/**
- * Functions to gather random data via the OpenSSL PRNG
+ * Generate random data via the internal PRNG.
+ *
+ * These functions are designed to be fast (sub microsecond), but do not necessarily
+ * meaningfully add entropy to the PRNG state.
+ *
+ * Thread-safe.
*/
-void GetRandBytes(unsigned char* buf, int num);
-uint64_t GetRand(uint64_t nMax);
-int GetRandInt(int nMax);
-uint256 GetRandHash();
+void GetRandBytes(unsigned char* buf, int num) noexcept;
+uint64_t GetRand(uint64_t nMax) noexcept;
+int GetRandInt(int nMax) noexcept;
+uint256 GetRandHash() noexcept;
/**
- * Add a little bit of randomness to the output of GetStrongRangBytes.
- * This sleeps for a millisecond, so should only be called when there is
- * no other work to be done.
+ * Gather entropy from various sources, feed it into the internal PRNG, and
+ * generate random data using it.
+ *
+ * This function will cause failure whenever the OS RNG fails.
+ *
+ * Thread-safe.
*/
-void RandAddSeedSleep();
+void GetStrongRandBytes(unsigned char* buf, int num) noexcept;
/**
- * Function to gather random data from multiple sources, failing whenever any
- * of those sources fail to provide a result.
+ * Sleep for 1ms, gather entropy from various sources, and feed them to the PRNG state.
+ *
+ * Thread-safe.
*/
-void GetStrongRandBytes(unsigned char* buf, int num);
+void RandAddSeedSleep();
/**
* Fast randomness source. This is seeded once with secure random data, but
- * is completely deterministic and insecure after that.
+ * is completely deterministic and does not gather more entropy after that.
+ *
* This class is not thread-safe.
*/
class FastRandomContext {
@@ -71,10 +121,10 @@ private:
}
public:
- explicit FastRandomContext(bool fDeterministic = false);
+ explicit FastRandomContext(bool fDeterministic = false) noexcept;
/** Initialize with explicit seed (only for testing) */
- explicit FastRandomContext(const uint256& seed);
+ explicit FastRandomContext(const uint256& seed) noexcept;
// Do not permit copying a FastRandomContext (move it, or create a new one to get reseeded).
FastRandomContext(const FastRandomContext&) = delete;
@@ -85,7 +135,7 @@ public:
FastRandomContext& operator=(FastRandomContext&& from) noexcept;
/** Generate a random 64-bit integer. */
- uint64_t rand64()
+ uint64_t rand64() noexcept
{
if (bytebuf_size < 8) FillByteBuffer();
uint64_t ret = ReadLE64(bytebuf + 64 - bytebuf_size);
@@ -94,7 +144,7 @@ public:
}
/** Generate a random (bits)-bit integer. */
- uint64_t randbits(int bits) {
+ uint64_t randbits(int bits) noexcept {
if (bits == 0) {
return 0;
} else if (bits > 32) {
@@ -109,7 +159,7 @@ public:
}
/** Generate a random integer in the range [0..range). */
- uint64_t randrange(uint64_t range)
+ uint64_t randrange(uint64_t range) noexcept
{
--range;
int bits = CountBits(range);
@@ -123,19 +173,19 @@ public:
std::vector<unsigned char> randbytes(size_t len);
/** Generate a random 32-bit integer. */
- uint32_t rand32() { return randbits(32); }
+ uint32_t rand32() noexcept { return randbits(32); }
/** generate a random uint256. */
- uint256 rand256();
+ uint256 rand256() noexcept;
/** Generate a random boolean. */
- bool randbool() { return randbits(1); }
+ bool randbool() noexcept { return randbits(1); }
// Compatibility with the C++11 UniformRandomBitGenerator concept
typedef uint64_t result_type;
static constexpr uint64_t min() { return 0; }
static constexpr uint64_t max() { return std::numeric_limits<uint64_t>::max(); }
- inline uint64_t operator()() { return rand64(); }
+ inline uint64_t operator()() noexcept { return rand64(); }
};
/** More efficient than using std::shuffle on a FastRandomContext.
@@ -178,7 +228,12 @@ void GetOSRand(unsigned char *ent32);
*/
bool Random_SanityCheck();
-/** Initialize the RNG. */
+/**
+ * Initialize global RNG state and log any CPU features that are used.
+ *
+ * Calling this function is optional. RNG state will be initialized when first
+ * needed if it is not called.
+ */
void RandomInit();
#endif // BITCOIN_RANDOM_H
diff --git a/src/rest.cpp b/src/rest.cpp
index 4f26e3afb5..326f7ae1d2 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -352,7 +352,7 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart)
CTransactionRef tx;
uint256 hashBlock = uint256();
- if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true))
+ if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock))
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
switch (rf) {
@@ -575,6 +575,52 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
}
}
+static bool rest_blockhash_by_height(HTTPRequest* req,
+ const std::string& str_uri_part)
+{
+ if (!CheckWarmup(req)) return false;
+ std::string height_str;
+ const RetFormat rf = ParseDataFormat(height_str, str_uri_part);
+
+ int32_t blockheight;
+ if (!ParseInt32(height_str, &blockheight) || blockheight < 0) {
+ return RESTERR(req, HTTP_BAD_REQUEST, "Invalid height: " + SanitizeString(height_str));
+ }
+
+ CBlockIndex* pblockindex = nullptr;
+ {
+ LOCK(cs_main);
+ if (blockheight > chainActive.Height()) {
+ return RESTERR(req, HTTP_NOT_FOUND, "Block height out of range");
+ }
+ pblockindex = chainActive[blockheight];
+ }
+ switch (rf) {
+ case RetFormat::BINARY: {
+ CDataStream ss_blockhash(SER_NETWORK, PROTOCOL_VERSION);
+ ss_blockhash << pblockindex->GetBlockHash();
+ req->WriteHeader("Content-Type", "application/octet-stream");
+ req->WriteReply(HTTP_OK, ss_blockhash.str());
+ return true;
+ }
+ case RetFormat::HEX: {
+ req->WriteHeader("Content-Type", "text/plain");
+ req->WriteReply(HTTP_OK, pblockindex->GetBlockHash().GetHex() + "\n");
+ return true;
+ }
+ case RetFormat::JSON: {
+ req->WriteHeader("Content-Type", "application/json");
+ UniValue resp = UniValue(UniValue::VOBJ);
+ resp.pushKV("blockhash", pblockindex->GetBlockHash().GetHex());
+ req->WriteReply(HTTP_OK, resp.write() + "\n");
+ return true;
+ }
+ default: {
+ return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
+ }
+ }
+}
+
static const struct {
const char* prefix;
bool (*handler)(HTTPRequest* req, const std::string& strReq);
@@ -587,6 +633,7 @@ static const struct {
{"/rest/mempool/contents", rest_mempool_contents},
{"/rest/headers/", rest_headers},
{"/rest/getutxos", rest_getutxos},
+ {"/rest/blockhashbyheight/", rest_blockhash_by_height},
};
void StartREST()
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 315f69d46b..fa0b62ec48 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -162,14 +162,16 @@ static UniValue getblockcount(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
RPCHelpMan{"getblockcount",
- "\nReturns the number of blocks in the longest blockchain.\n", {}}
- .ToString() +
- "\nResult:\n"
+ "\nReturns the number of blocks in the longest blockchain.\n",
+ {},
+ RPCResult{
"n (numeric) The current block count\n"
- "\nExamples:\n"
- + HelpExampleCli("getblockcount", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getblockcount", "")
+ HelpExampleRpc("getblockcount", "")
- );
+ },
+ }.ToString());
LOCK(cs_main);
return chainActive.Height();
@@ -180,14 +182,16 @@ static UniValue getbestblockhash(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
RPCHelpMan{"getbestblockhash",
- "\nReturns the hash of the best (tip) block in the longest blockchain.\n", {}}
- .ToString() +
- "\nResult:\n"
+ "\nReturns the hash of the best (tip) block in the longest blockchain.\n",
+ {},
+ RPCResult{
"\"hex\" (string) the block hash, hex-encoded\n"
- "\nExamples:\n"
- + HelpExampleCli("getbestblockhash", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getbestblockhash", "")
+ HelpExampleRpc("getbestblockhash", "")
- );
+ },
+ }.ToString());
LOCK(cs_main);
return chainActive.Tip()->GetBlockHash().GetHex();
@@ -212,17 +216,18 @@ static UniValue waitfornewblock(const JSONRPCRequest& request)
"\nReturns the current block on timeout or exit.\n",
{
{"timeout", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{ (json object)\n"
" \"hash\" : { (string) The blockhash\n"
" \"height\" : { (int) Block height\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("waitfornewblock", "1000")
+ },
+ RPCExamples{
+ HelpExampleCli("waitfornewblock", "1000")
+ HelpExampleRpc("waitfornewblock", "1000")
- );
+ },
+ }.ToString());
int timeout = 0;
if (!request.params[0].isNull())
timeout = request.params[0].get_int();
@@ -253,17 +258,18 @@ static UniValue waitforblock(const JSONRPCRequest& request)
{
{"blockhash", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "Block hash to wait for."},
{"timeout", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{ (json object)\n"
" \"hash\" : { (string) The blockhash\n"
" \"height\" : { (int) Block height\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
+ },
+ RPCExamples{
+ HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
+ HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
- );
+ },
+ }.ToString());
int timeout = 0;
uint256 hash(ParseHashV(request.params[0], "blockhash"));
@@ -298,17 +304,18 @@ static UniValue waitforblockheight(const JSONRPCRequest& request)
{
{"height", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "Block height to wait for."},
{"timeout", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{ (json object)\n"
" \"hash\" : { (string) The blockhash\n"
" \"height\" : { (int) Block height\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("waitforblockheight", "\"100\", 1000")
+ },
+ RPCExamples{
+ HelpExampleCli("waitforblockheight", "\"100\", 1000")
+ HelpExampleRpc("waitforblockheight", "\"100\", 1000")
- );
+ },
+ }.ToString());
int timeout = 0;
int height = request.params[0].get_int();
@@ -336,12 +343,14 @@ static UniValue syncwithvalidationinterfacequeue(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() > 0) {
throw std::runtime_error(
RPCHelpMan{"syncwithvalidationinterfacequeue",
- "\nWaits for the validation interface queue to catch up on everything that was there when we entered this function.\n", {}}
- .ToString() +
- "\nExamples:\n"
- + HelpExampleCli("syncwithvalidationinterfacequeue","")
+ "\nWaits for the validation interface queue to catch up on everything that was there when we entered this function.\n",
+ {},
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("syncwithvalidationinterfacequeue","")
+ HelpExampleRpc("syncwithvalidationinterfacequeue","")
- );
+ },
+ }.ToString());
}
SyncWithValidationInterfaceQueue();
return NullUniValue;
@@ -352,14 +361,16 @@ static UniValue getdifficulty(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
RPCHelpMan{"getdifficulty",
- "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n", {}}
- .ToString() +
- "\nResult:\n"
+ "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n",
+ {},
+ RPCResult{
"n.nnn (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty.\n"
- "\nExamples:\n"
- + HelpExampleCli("getdifficulty", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getdifficulty", "")
+ HelpExampleRpc("getdifficulty", "")
- );
+ },
+ }.ToString());
LOCK(cs_main);
return GetDifficulty(chainActive.Tip());
@@ -491,9 +502,8 @@ static UniValue getrawmempool(const JSONRPCRequest& request)
"\nHint: use getmempoolentry to fetch a specific transaction from the mempool.\n",
{
{"verbose", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "True for a json object, false for array of transaction ids"},
- }}
- .ToString() +
- "\nResult: (for verbose = false):\n"
+ },
+ RPCResult{"for verbose = false",
"[ (json array of string)\n"
" \"transactionid\" (string) The transaction id\n"
" ,...\n"
@@ -504,10 +514,12 @@ static UniValue getrawmempool(const JSONRPCRequest& request)
+ EntryDescriptionString()
+ " }, ...\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getrawmempool", "true")
+ },
+ RPCExamples{
+ HelpExampleCli("getrawmempool", "true")
+ HelpExampleRpc("getrawmempool", "true")
- );
+ },
+ }.ToString());
bool fVerbose = false;
if (!request.params[0].isNull())
@@ -525,23 +537,27 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request)
{
{"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id (must be in mempool)"},
{"verbose", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "True for a json object, false for array of transaction ids"},
- }}
- .ToString() +
- "\nResult (for verbose = false):\n"
+ },
+ {
+ RPCResult{"for verbose = false",
"[ (json array of strings)\n"
" \"transactionid\" (string) The transaction id of an in-mempool ancestor transaction\n"
" ,...\n"
"]\n"
- "\nResult (for verbose = true):\n"
+ },
+ RPCResult{"for verbose = true",
"{ (json object)\n"
" \"transactionid\" : { (json object)\n"
+ EntryDescriptionString()
+ " }, ...\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getmempoolancestors", "\"mytxid\"")
+ },
+ },
+ RPCExamples{
+ HelpExampleCli("getmempoolancestors", "\"mytxid\"")
+ HelpExampleRpc("getmempoolancestors", "\"mytxid\"")
- );
+ },
+ }.ToString());
}
bool fVerbose = false;
@@ -591,23 +607,27 @@ static UniValue getmempooldescendants(const JSONRPCRequest& request)
{
{"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id (must be in mempool)"},
{"verbose", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "True for a json object, false for array of transaction ids"},
- }}
- .ToString() +
- "\nResult (for verbose = false):\n"
+ },
+ {
+ RPCResult{"for verbose = false",
"[ (json array of strings)\n"
" \"transactionid\" (string) The transaction id of an in-mempool descendant transaction\n"
" ,...\n"
"]\n"
- "\nResult (for verbose = true):\n"
+ },
+ RPCResult{"for verbose = true",
"{ (json object)\n"
" \"transactionid\" : { (json object)\n"
+ EntryDescriptionString()
+ " }, ...\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getmempooldescendants", "\"mytxid\"")
+ },
+ },
+ RPCExamples{
+ HelpExampleCli("getmempooldescendants", "\"mytxid\"")
+ HelpExampleRpc("getmempooldescendants", "\"mytxid\"")
- );
+ },
+ }.ToString());
}
bool fVerbose = false;
@@ -656,16 +676,17 @@ static UniValue getmempoolentry(const JSONRPCRequest& request)
"\nReturns mempool data for given transaction\n",
{
{"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id (must be in mempool)"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{ (json object)\n"
+ EntryDescriptionString()
+ "}\n"
- "\nExamples:\n"
- + HelpExampleCli("getmempoolentry", "\"mytxid\"")
+ },
+ RPCExamples{
+ HelpExampleCli("getmempoolentry", "\"mytxid\"")
+ HelpExampleRpc("getmempoolentry", "\"mytxid\"")
- );
+ },
+ }.ToString());
}
uint256 hash = ParseHashV(request.params[0], "parameter 1");
@@ -691,14 +712,15 @@ static UniValue getblockhash(const JSONRPCRequest& request)
"\nReturns hash of block in best-block-chain at height provided.\n",
{
{"height", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The height index"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"\"hash\" (string) The block hash\n"
- "\nExamples:\n"
- + HelpExampleCli("getblockhash", "1000")
+ },
+ RPCExamples{
+ HelpExampleCli("getblockhash", "1000")
+ HelpExampleRpc("getblockhash", "1000")
- );
+ },
+ }.ToString());
LOCK(cs_main);
@@ -720,9 +742,9 @@ static UniValue getblockheader(const JSONRPCRequest& request)
{
{"blockhash", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The block hash"},
{"verbose", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "true for a json object, false for the hex-encoded data"},
- }}
- .ToString() +
- "\nResult (for verbose = true):\n"
+ },
+ {
+ RPCResult{"for verbose = true",
"{\n"
" \"hash\" : \"hash\", (string) the block hash (same as provided)\n"
" \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n"
@@ -740,12 +762,16 @@ static UniValue getblockheader(const JSONRPCRequest& request)
" \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n"
" \"nextblockhash\" : \"hash\", (string) The hash of the next block\n"
"}\n"
- "\nResult (for verbose=false):\n"
+ },
+ RPCResult{"for verbose=false",
"\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n"
- "\nExamples:\n"
- + HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
+ },
+ },
+ RPCExamples{
+ HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
+ HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
- );
+ },
+ }.ToString());
uint256 hash(ParseHashV(request.params[0], "hash"));
@@ -806,11 +832,12 @@ static UniValue getblock(const JSONRPCRequest& request)
{
{"blockhash", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The block hash"},
{"verbosity", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1", "0 for hex-encoded data, 1 for a json object, and 2 for json object with transaction data"},
- }}
- .ToString() +
- "\nResult (for verbosity = 0):\n"
+ },
+ {
+ RPCResult{"for verbosity = 0",
"\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n"
- "\nResult (for verbosity = 1):\n"
+ },
+ RPCResult{"for verbosity = 1",
"{\n"
" \"hash\" : \"hash\", (string) the block hash (same as provided)\n"
" \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n"
@@ -835,7 +862,8 @@ static UniValue getblock(const JSONRPCRequest& request)
" \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n"
" \"nextblockhash\" : \"hash\" (string) The hash of the next block\n"
"}\n"
- "\nResult (for verbosity = 2):\n"
+ },
+ RPCResult{"for verbosity = 2",
"{\n"
" ..., Same output as verbosity = 1.\n"
" \"tx\" : [ (array of Objects) The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 \"tx\" result.\n"
@@ -843,10 +871,13 @@ static UniValue getblock(const JSONRPCRequest& request)
" ],\n"
" ,... Same output as verbosity = 1.\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
+ },
+ },
+ RPCExamples{
+ HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
+ HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
- );
+ },
+ }.ToString());
LOCK(cs_main);
@@ -957,13 +988,15 @@ static UniValue pruneblockchain(const JSONRPCRequest& request)
{
{"height", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The block height to prune up to. May be set to a discrete height, or a unix timestamp\n"
" to prune blocks whose block time is at least 2 hours older than the provided timestamp."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"n (numeric) Height of the last block pruned.\n"
- "\nExamples:\n"
- + HelpExampleCli("pruneblockchain", "1000")
- + HelpExampleRpc("pruneblockchain", "1000"));
+ },
+ RPCExamples{
+ HelpExampleCli("pruneblockchain", "1000")
+ + HelpExampleRpc("pruneblockchain", "1000")
+ },
+ }.ToString());
if (!fPruneMode)
throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode.");
@@ -1007,9 +1040,8 @@ static UniValue gettxoutsetinfo(const JSONRPCRequest& request)
RPCHelpMan{"gettxoutsetinfo",
"\nReturns statistics about the unspent transaction output set.\n"
"Note this call may take some time.\n",
- {}}
- .ToString() +
- "\nResult:\n"
+ {},
+ RPCResult{
"{\n"
" \"height\":n, (numeric) The current block height (index)\n"
" \"bestblock\": \"hex\", (string) The hash of the block at the tip of the chain\n"
@@ -1020,10 +1052,12 @@ static UniValue gettxoutsetinfo(const JSONRPCRequest& request)
" \"disk_size\": n, (numeric) The estimated size of the chainstate on disk\n"
" \"total_amount\": x.xxx (numeric) The total amount\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("gettxoutsetinfo", "")
+ },
+ RPCExamples{
+ HelpExampleCli("gettxoutsetinfo", "")
+ HelpExampleRpc("gettxoutsetinfo", "")
- );
+ },
+ }.ToString());
UniValue ret(UniValue::VOBJ);
@@ -1054,9 +1088,8 @@ UniValue gettxout(const JSONRPCRequest& request)
{"txid", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The transaction id"},
{"n", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "vout number"},
{"include_mempool", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "Whether to include the mempool. Note that an unspent output that is spent in the mempool won't appear."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{\n"
" \"bestblock\": \"hash\", (string) The hash of the block at the tip of the chain\n"
" \"confirmations\" : n, (numeric) The number of confirmations\n"
@@ -1073,15 +1106,16 @@ UniValue gettxout(const JSONRPCRequest& request)
" },\n"
" \"coinbase\" : true|false (boolean) Coinbase or not\n"
"}\n"
-
- "\nExamples:\n"
+ },
+ RPCExamples{
"\nGet unspent transactions\n"
+ HelpExampleCli("listunspent", "") +
"\nView the details\n"
+ HelpExampleCli("gettxout", "\"txid\" 1") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("gettxout", "\"txid\", 1")
- );
+ },
+ }.ToString());
LOCK(cs_main);
@@ -1134,14 +1168,15 @@ static UniValue verifychain(const JSONRPCRequest& request)
{
{"checklevel", RPCArg::Type::NUM, /* opt */ true, /* default_val */ strprintf("%d, range=0-4", nCheckLevel), "How thorough the block verification is."},
{"nblocks", RPCArg::Type::NUM, /* opt */ true, /* default_val */ strprintf("%d, 0=all", nCheckDepth), "The number of blocks to check."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"true|false (boolean) Verified or not\n"
- "\nExamples:\n"
- + HelpExampleCli("verifychain", "")
+ },
+ RPCExamples{
+ HelpExampleCli("verifychain", "")
+ HelpExampleRpc("verifychain", "")
- );
+ },
+ }.ToString());
LOCK(cs_main);
@@ -1229,9 +1264,9 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
RPCHelpMan{"getblockchaininfo",
- "Returns an object containing various state info regarding blockchain processing.\n", {}}
- .ToString() +
- "\nResult:\n"
+ "Returns an object containing various state info regarding blockchain processing.\n",
+ {},
+ RPCResult{
"{\n"
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
" \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
@@ -1274,10 +1309,12 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
" }\n"
" \"warnings\" : \"...\", (string) any network and blockchain warnings.\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getblockchaininfo", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getblockchaininfo", "")
+ HelpExampleRpc("getblockchaininfo", "")
- );
+ },
+ }.ToString());
LOCK(cs_main);
@@ -1349,9 +1386,8 @@ static UniValue getchaintips(const JSONRPCRequest& request)
RPCHelpMan{"getchaintips",
"Return information about all known tips in the block tree,"
" including the main chain as well as orphaned branches.\n",
- {}}
- .ToString() +
- "\nResult:\n"
+ {},
+ RPCResult{
"[\n"
" {\n"
" \"height\": xxxx, (numeric) height of the chain tip\n"
@@ -1372,10 +1408,12 @@ static UniValue getchaintips(const JSONRPCRequest& request)
"3. \"valid-headers\" All blocks are available for this branch, but they were never fully validated\n"
"4. \"valid-fork\" This branch is not part of the active chain, but is fully validated\n"
"5. \"active\" This is the tip of the active main chain, which is certainly valid\n"
- "\nExamples:\n"
- + HelpExampleCli("getchaintips", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getchaintips", "")
+ HelpExampleRpc("getchaintips", "")
- );
+ },
+ }.ToString());
LOCK(cs_main);
@@ -1466,9 +1504,9 @@ static UniValue getmempoolinfo(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
RPCHelpMan{"getmempoolinfo",
- "\nReturns details on the active state of the TX memory pool.\n", {}}
- .ToString() +
- "\nResult:\n"
+ "\nReturns details on the active state of the TX memory pool.\n",
+ {},
+ RPCResult{
"{\n"
" \"size\": xxxxx, (numeric) Current tx count\n"
" \"bytes\": xxxxx, (numeric) Sum of all virtual transaction sizes as defined in BIP 141. Differs from actual serialized size because witness data is discounted\n"
@@ -1477,10 +1515,12 @@ static UniValue getmempoolinfo(const JSONRPCRequest& request)
" \"mempoolminfee\": xxxxx (numeric) Minimum fee rate in " + CURRENCY_UNIT + "/kB for tx to be accepted. Is the maximum of minrelaytxfee and minimum mempool fee\n"
" \"minrelaytxfee\": xxxxx (numeric) Current minimum relay fee for transactions\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getmempoolinfo", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getmempoolinfo", "")
+ HelpExampleRpc("getmempoolinfo", "")
- );
+ },
+ }.ToString());
return mempoolInfoToJSON();
}
@@ -1495,13 +1535,13 @@ static UniValue preciousblock(const JSONRPCRequest& request)
"\nThe effects of preciousblock are not retained across restarts.\n",
{
{"blockhash", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "the hash of the block to mark as precious"},
- }}
- .ToString() +
- "\nResult:\n"
- "\nExamples:\n"
- + HelpExampleCli("preciousblock", "\"blockhash\"")
+ },
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("preciousblock", "\"blockhash\"")
+ HelpExampleRpc("preciousblock", "\"blockhash\"")
- );
+ },
+ }.ToString());
uint256 hash(ParseHashV(request.params[0], "blockhash"));
CBlockIndex* pblockindex;
@@ -1532,13 +1572,13 @@ static UniValue invalidateblock(const JSONRPCRequest& request)
"\nPermanently marks a block as invalid, as if it violated a consensus rule.\n",
{
{"blockhash", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "the hash of the block to mark as invalid"},
- }}
- .ToString() +
- "\nResult:\n"
- "\nExamples:\n"
- + HelpExampleCli("invalidateblock", "\"blockhash\"")
+ },
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("invalidateblock", "\"blockhash\"")
+ HelpExampleRpc("invalidateblock", "\"blockhash\"")
- );
+ },
+ }.ToString());
uint256 hash(ParseHashV(request.params[0], "blockhash"));
CValidationState state;
@@ -1573,13 +1613,13 @@ static UniValue reconsiderblock(const JSONRPCRequest& request)
"This can be used to undo the effects of invalidateblock.\n",
{
{"blockhash", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "the hash of the block to reconsider"},
- }}
- .ToString() +
- "\nResult:\n"
- "\nExamples:\n"
- + HelpExampleCli("reconsiderblock", "\"blockhash\"")
+ },
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("reconsiderblock", "\"blockhash\"")
+ HelpExampleRpc("reconsiderblock", "\"blockhash\"")
- );
+ },
+ }.ToString());
uint256 hash(ParseHashV(request.params[0], "blockhash"));
@@ -1612,9 +1652,8 @@ static UniValue getchaintxstats(const JSONRPCRequest& request)
{
{"nblocks", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "one month", "Size of the window in number of blocks"},
{"blockhash", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "chain tip", "The hash of the block that ends the window."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{\n"
" \"time\": xxxxx, (numeric) The timestamp for the final block in the window in UNIX format.\n"
" \"txcount\": xxxxx, (numeric) The total number of transactions in the chain up to that point.\n"
@@ -1624,10 +1663,12 @@ static UniValue getchaintxstats(const JSONRPCRequest& request)
" \"window_interval\": xxxxx, (numeric) The elapsed time in the window in seconds. Only returned if \"window_block_count\" is > 0.\n"
" \"txrate\": x.xx, (numeric) The average rate of transactions per second in the window. Only returned if \"window_interval\" is > 0.\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getchaintxstats", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getchaintxstats", "")
+ HelpExampleRpc("getchaintxstats", "2016")
- );
+ },
+ }.ToString());
const CBlockIndex* pindex;
int blockcount = 30 * 24 * 60 * 60 / Params().GetConsensus().nPowTargetSpacing; // By default: 1 month
@@ -1751,9 +1792,8 @@ static UniValue getblockstats(const JSONRPCRequest& request)
{"time", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "Selected statistic"},
},
"stats"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{ (json object)\n"
" \"avgfee\": xxxxx, (numeric) Average fee in the block\n"
" \"avgfeerate\": xxxxx, (numeric) Average feerate (in satoshis per virtual byte)\n"
@@ -1791,10 +1831,12 @@ static UniValue getblockstats(const JSONRPCRequest& request)
" \"utxo_increase\": xxxxx, (numeric) The increase/decrease in the number of unspent outputs\n"
" \"utxo_size_inc\": xxxxx, (numeric) The increase/decrease in size for the utxo index (not discounting op_return and similar)\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getblockstats", "1000 '[\"minfeerate\",\"avgfeerate\"]'")
+ },
+ RPCExamples{
+ HelpExampleCli("getblockstats", "1000 '[\"minfeerate\",\"avgfeerate\"]'")
+ HelpExampleRpc("getblockstats", "1000 '[\"minfeerate\",\"avgfeerate\"]'")
- );
+ },
+ }.ToString());
}
LOCK(cs_main);
@@ -1918,7 +1960,7 @@ static UniValue getblockstats(const JSONRPCRequest& request)
for (const CTxIn& in : tx->vin) {
CTransactionRef tx_in;
uint256 hashBlock;
- if (!GetTransaction(in.prevout.hash, tx_in, Params().GetConsensus(), hashBlock, false)) {
+ if (!GetTransaction(in.prevout.hash, tx_in, Params().GetConsensus(), hashBlock)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, std::string("Unexpected internal error (tx index seems corrupt)"));
}
@@ -2006,12 +2048,14 @@ static UniValue savemempool(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 0) {
throw std::runtime_error(
RPCHelpMan{"savemempool",
- "\nDumps the mempool to disk. It will fail until the previous dump is fully loaded.\n", {}}
- .ToString() +
- "\nExamples:\n"
- + HelpExampleCli("savemempool", "")
+ "\nDumps the mempool to disk. It will fail until the previous dump is fully loaded.\n",
+ {},
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("savemempool", "")
+ HelpExampleRpc("savemempool", "")
- );
+ },
+ }.ToString());
}
if (!g_is_mempool_loaded) {
@@ -2120,9 +2164,8 @@ UniValue scantxoutset(const JSONRPCRequest& request)
},
},
"[scanobjects,...]"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{\n"
" \"unspents\": [\n"
" {\n"
@@ -2136,6 +2179,9 @@ UniValue scantxoutset(const JSONRPCRequest& request)
" ,...], \n"
" \"total_amount\" : x.xxx, (numeric) The total amount of all found unspent outputs in " + CURRENCY_UNIT + "\n"
"]\n"
+ },
+ RPCExamples{""},
+ }.ToString()
);
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR});
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 6f1bfb03d1..c5694e6d55 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -68,6 +68,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "sendmany", 4, "subtractfeefrom" },
{ "sendmany", 5 , "replaceable" },
{ "sendmany", 6 , "conf_target" },
+ { "deriveaddresses", 1, "begin" },
+ { "deriveaddresses", 2, "end" },
{ "scantxoutset", 1, "scanobjects" },
{ "addmultisigaddress", 0, "nrequired" },
{ "addmultisigaddress", 1, "keys" },
@@ -89,8 +91,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "createrawtransaction", 2, "locktime" },
{ "createrawtransaction", 3, "replaceable" },
{ "decoderawtransaction", 1, "iswitness" },
- { "signrawtransaction", 1, "prevtxs" },
- { "signrawtransaction", 2, "privkeys" },
{ "signrawtransactionwithkey", 1, "privkeys" },
{ "signrawtransactionwithkey", 2, "prevtxs" },
{ "signrawtransactionwithwallet", 1, "prevtxs" },
@@ -161,6 +161,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "rescanblockchain", 0, "start_height"},
{ "rescanblockchain", 1, "stop_height"},
{ "createwallet", 1, "disable_private_keys"},
+ { "createwallet", 2, "blank"},
{ "getnodeaddresses", 0, "count"},
{ "stop", 0, "wait" },
};
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 2fd6f99be5..35f55b0141 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -31,16 +31,6 @@
#include <memory>
#include <stdint.h>
-unsigned int ParseConfirmTarget(const UniValue& value)
-{
- int target = value.get_int();
- unsigned int max_target = ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
- if (target < 1 || (unsigned int)target > max_target) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid conf_target, must be between %u - %u", 1, max_target));
- }
- return (unsigned int)target;
-}
-
/**
* Return average network hashes per second based on the last 'lookup' blocks,
* or from the last difficulty change if 'lookup' is nonpositive.
@@ -94,14 +84,15 @@ static UniValue getnetworkhashps(const JSONRPCRequest& request)
{
{"nblocks", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "120", "The number of blocks, or -1 for blocks since last difficulty change."},
{"height", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "-1", "To estimate at the time of the given height."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"x (numeric) Hashes per second estimated\n"
- "\nExamples:\n"
- + HelpExampleCli("getnetworkhashps", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getnetworkhashps", "")
+ HelpExampleRpc("getnetworkhashps", "")
- );
+ },
+ }.ToString());
LOCK(cs_main);
return GetNetworkHashPS(!request.params[0].isNull() ? request.params[0].get_int() : 120, !request.params[1].isNull() ? request.params[1].get_int() : -1);
@@ -165,16 +156,17 @@ static UniValue generatetoaddress(const JSONRPCRequest& request)
{"nblocks", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "How many blocks are generated immediately."},
{"address", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The address to send the newly generated bitcoin to."},
{"maxtries", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1000000", "How many iterations to try."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"[ blockhashes ] (array) hashes of blocks generated\n"
- "\nExamples:\n"
+ },
+ RPCExamples{
"\nGenerate 11 blocks to myaddress\n"
+ HelpExampleCli("generatetoaddress", "11 \"myaddress\"")
+ "If you are running the bitcoin core wallet, you can get a new address to send the newly generated bitcoin to with:\n"
+ HelpExampleCli("getnewaddress", "")
- );
+ },
+ }.ToString());
int nGenerate = request.params[0].get_int();
uint64_t nMaxTries = 1000000;
@@ -198,9 +190,9 @@ static UniValue getmininginfo(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
RPCHelpMan{"getmininginfo",
- "\nReturns a json object containing mining-related information.", {}}
- .ToString() +
- "\nResult:\n"
+ "\nReturns a json object containing mining-related information.",
+ {},
+ RPCResult{
"{\n"
" \"blocks\": nnn, (numeric) The current block\n"
" \"currentblockweight\": nnn, (numeric) The last block weight\n"
@@ -211,10 +203,12 @@ static UniValue getmininginfo(const JSONRPCRequest& request)
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
" \"warnings\": \"...\" (string) any network and blockchain warnings\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getmininginfo", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getmininginfo", "")
+ HelpExampleRpc("getmininginfo", "")
- );
+ },
+ }.ToString());
LOCK(cs_main);
@@ -247,14 +241,15 @@ static UniValue prioritisetransaction(const JSONRPCRequest& request)
" Note, that this value is not a fee rate. It is a value to modify absolute fee of the TX.\n"
" The fee is not actually paid, only the algorithm for selecting transactions into a block\n"
" considers the transaction as it would have paid a higher (or lower) fee."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"true (boolean) Returns true\n"
- "\nExamples:\n"
- + HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000")
+ },
+ RPCExamples{
+ HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000")
+ HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000")
- );
+ },
+ }.ToString());
LOCK(cs_main);
@@ -326,9 +321,8 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
},
},
"\"template_request\""},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{\n"
" \"version\" : n, (numeric) The preferred block version\n"
" \"rules\" : [ \"rulename\", ... ], (array of strings) specific block rules that are to be enforced\n"
@@ -372,11 +366,12 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
" \"bits\" : \"xxxxxxxx\", (string) compressed target of next block\n"
" \"height\" : n (numeric) The height of the next block\n"
"}\n"
-
- "\nExamples:\n"
- + HelpExampleCli("getblocktemplate", "{\"rules\": [\"segwit\"]}")
+ },
+ RPCExamples{
+ HelpExampleCli("getblocktemplate", "{\"rules\": [\"segwit\"]}")
+ HelpExampleRpc("getblocktemplate", "{\"rules\": [\"segwit\"]}")
- );
+ },
+ }.ToString());
LOCK(cs_main);
@@ -713,13 +708,13 @@ static UniValue submitblock(const JSONRPCRequest& request)
{
{"hexdata", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "the hex-encoded block data to submit"},
{"dummy", RPCArg::Type::STR, /* opt */ true, /* default_val */ "ignored", "dummy value, for compatibility with BIP22. This value is ignored."},
- }}
- .ToString() +
- "\nResult:\n"
- "\nExamples:\n"
- + HelpExampleCli("submitblock", "\"mydata\"")
+ },
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("submitblock", "\"mydata\"")
+ HelpExampleRpc("submitblock", "\"mydata\"")
- );
+ },
+ }.ToString());
}
std::shared_ptr<CBlock> blockptr = std::make_shared<CBlock>();
@@ -777,13 +772,15 @@ static UniValue submitheader(const JSONRPCRequest& request)
"\nThrows when the header is invalid.\n",
{
{"hexdata", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "the hex-encoded block header data"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"None"
- "\nExamples:\n" +
- HelpExampleCli("submitheader", "\"aabbcc\"") +
- HelpExampleRpc("submitheader", "\"aabbcc\""));
+ },
+ RPCExamples{
+ HelpExampleCli("submitheader", "\"aabbcc\"") +
+ HelpExampleRpc("submitheader", "\"aabbcc\"")
+ },
+ }.ToString());
}
CBlockHeader h;
@@ -826,9 +823,8 @@ static UniValue estimatesmartfee(const JSONRPCRequest& request)
" \"UNSET\"\n"
" \"ECONOMICAL\"\n"
" \"CONSERVATIVE\""},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{\n"
" \"feerate\" : x.x, (numeric, optional) estimate fee rate in " + CURRENCY_UNIT + "/kB\n"
" \"errors\": [ str... ] (json array of strings, optional) Errors encountered during processing\n"
@@ -839,9 +835,11 @@ static UniValue estimatesmartfee(const JSONRPCRequest& request)
"fee estimation is able to return based on how long it has been running.\n"
"An error is returned if not enough transactions and blocks\n"
"have been observed to make an estimate for any number of blocks.\n"
- "\nExample:\n"
- + HelpExampleCli("estimatesmartfee", "6")
- );
+ },
+ RPCExamples{
+ HelpExampleCli("estimatesmartfee", "6")
+ },
+ }.ToString());
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VSTR});
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
@@ -886,9 +884,8 @@ static UniValue estimaterawfee(const JSONRPCRequest& request)
{"threshold", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0.95", "The proportion of transactions in a given feerate range that must have been\n"
" confirmed within conf_target in order to consider those feerates as high enough and proceed to check\n"
" lower buckets."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{\n"
" \"short\" : { (json object, optional) estimate for short time horizon\n"
" \"feerate\" : x.x, (numeric, optional) estimate fee rate in " + CURRENCY_UNIT + "/kB\n"
@@ -910,9 +907,11 @@ static UniValue estimaterawfee(const JSONRPCRequest& request)
"}\n"
"\n"
"Results are returned for any horizon which tracks blocks up to the confirmation target.\n"
- "\nExample:\n"
- + HelpExampleCli("estimaterawfee", "6 0.9")
- );
+ },
+ RPCExamples{
+ HelpExampleCli("estimaterawfee", "6 0.9")
+ },
+ }.ToString());
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM}, true);
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
diff --git a/src/rpc/mining.h b/src/rpc/mining.h
index 8d46273159..be9a973315 100644
--- a/src/rpc/mining.h
+++ b/src/rpc/mining.h
@@ -12,7 +12,4 @@
/** Generate blocks (mine) */
UniValue generateBlocks(std::shared_ptr<CReserveScript> coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript);
-/** Check bounds on a command line confirm target */
-unsigned int ParseConfirmTarget(const UniValue& value);
-
#endif
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 18c867bff3..9702dc47e8 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -16,6 +16,7 @@
#include <rpc/blockchain.h>
#include <rpc/server.h>
#include <rpc/util.h>
+#include <script/descriptor.h>
#include <timedata.h>
#include <util/system.h>
#include <util/strencodings.h>
@@ -40,9 +41,8 @@ static UniValue validateaddress(const JSONRPCRequest& request)
"script, hex, pubkeys, sigsrequired, pubkey, addresses, embedded, iscompressed, account, timestamp, hdkeypath, kdmasterkeyid.\n",
{
{"address", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The bitcoin address to validate"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{\n"
" \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n"
" \"address\" : \"address\", (string) The bitcoin address validated\n"
@@ -52,10 +52,12 @@ static UniValue validateaddress(const JSONRPCRequest& request)
" \"witness_version\" : version (numeric, optional) The version number of the witness program\n"
" \"witness_program\" : \"hex\" (string, optional) The hex value of the witness program\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
+ },
+ RPCExamples{
+ HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
+ HelpExampleRpc("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
- );
+ },
+ }.ToString());
CTxDestination dest = DecodeDestination(request.params[0].get_str());
bool isValid = IsValidDestination(dest);
@@ -91,20 +93,20 @@ static UniValue createmultisig(const JSONRPCRequest& request)
{"key", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The hex-encoded public key"},
}},
{"address_type", RPCArg::Type::STR, /* opt */ true, /* default_val */ "legacy", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{\n"
" \"address\":\"multisigaddress\", (string) The value of the new multisig address.\n"
" \"redeemScript\":\"script\" (string) The string value of the hex-encoded redemption script.\n"
"}\n"
-
- "\nExamples:\n"
+ },
+ RPCExamples{
"\nCreate a multisig address from 2 public keys\n"
+ HelpExampleCli("createmultisig", "2 \"[\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd342cf11ae157a7ace5fd\\\",\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e17e107ef3f6aa5a61626\\\"]\"") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("createmultisig", "2, \"[\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd342cf11ae157a7ace5fd\\\",\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e17e107ef3f6aa5a61626\\\"]\"")
- ;
+ },
+ }.ToString();
throw std::runtime_error(msg);
}
@@ -141,6 +143,95 @@ static UniValue createmultisig(const JSONRPCRequest& request)
return result;
}
+UniValue deriveaddresses(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.empty() || request.params.size() > 3) {
+ throw std::runtime_error(
+ RPCHelpMan{"deriveaddresses",
+ {"\nDerives one or more addresses corresponding to an output descriptor.\n"
+ "Examples of output descriptors are:\n"
+ " pkh(<pubkey>) P2PKH outputs for the given pubkey\n"
+ " wpkh(<pubkey>) Native segwit P2PKH outputs for the given pubkey\n"
+ " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys\n"
+ " raw(<hex script>) Outputs whose scriptPubKey equals the specified hex scripts\n"
+ "\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
+ "or more path elements separated by \"/\", where \"h\" represents a hardened child key.\n"
+ "For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n"},
+ {
+ {"descriptor", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The descriptor."},
+ {"begin", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", "If a ranged descriptor is used, this specifies the beginning of the range to import."},
+ {"end", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", "If a ranged descriptor is used, this specifies the end of the range to import."}
+ },
+ RPCResult{
+ "[ address ] (array) the derived addresses\n"
+ },
+ RPCExamples{
+ "First three native segwit receive addresses\n" +
+ HelpExampleCli("deriveaddresses", "\"wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)\" 0 2")
+ }}.ToString()
+ );
+ }
+
+ RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VNUM, UniValue::VNUM});
+ const std::string desc_str = request.params[0].get_str();
+
+ int range_begin = 0;
+ int range_end = 0;
+
+ if (request.params.size() >= 2) {
+ if (request.params.size() == 2) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Missing range end parameter");
+ }
+ range_begin = request.params[1].get_int();
+ range_end = request.params[2].get_int();
+ if (range_begin < 0) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should be greater or equal than 0");
+ }
+ if (range_begin > range_end) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Range end should be equal to or greater than begin");
+ }
+ }
+
+ FlatSigningProvider provider;
+ auto desc = Parse(desc_str, provider);
+ if (!desc) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Invalid descriptor"));
+ }
+
+ if (!desc->IsRange() && request.params.size() > 1) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should not be specified for an un-ranged descriptor");
+ }
+
+ if (desc->IsRange() && request.params.size() == 1) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Range must be specified for a ranged descriptor");
+ }
+
+ UniValue addresses(UniValue::VARR);
+
+ for (int i = range_begin; i <= range_end; ++i) {
+ std::vector<CScript> scripts;
+ if (!desc->Expand(i, provider, scripts, provider)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Cannot derive script without private keys"));
+ }
+
+ for (const CScript &script : scripts) {
+ CTxDestination dest;
+ if (!ExtractDestination(script, dest)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Descriptor does not have a corresponding address"));
+ }
+
+ addresses.push_back(EncodeDestination(dest));
+ }
+ }
+
+ // This should not be possible, but an assert seems overkill:
+ if (addresses.empty()) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Unexpected empty result");
+ }
+
+ return addresses;
+}
+
static UniValue verifymessage(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 3)
@@ -151,11 +242,11 @@ static UniValue verifymessage(const JSONRPCRequest& request)
{"address", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The bitcoin address to use for the signature."},
{"signature", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The signature provided by the signer in base 64 encoding (see signmessage)."},
{"message", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The message that was signed."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"true|false (boolean) If the signature is verified or not.\n"
- "\nExamples:\n"
+ },
+ RPCExamples{
"\nUnlock the wallet for 30 seconds\n"
+ HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
"\nCreate the signature\n"
@@ -164,7 +255,8 @@ static UniValue verifymessage(const JSONRPCRequest& request)
+ HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"signature\", \"my message\"")
- );
+ },
+ }.ToString());
LOCK(cs_main);
@@ -208,18 +300,19 @@ static UniValue signmessagewithprivkey(const JSONRPCRequest& request)
{
{"privkey", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The private key to sign the message with."},
{"message", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The message to create a signature of."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"\"signature\" (string) The signature of the message encoded in base 64\n"
- "\nExamples:\n"
+ },
+ RPCExamples{
"\nCreate the signature\n"
+ HelpExampleCli("signmessagewithprivkey", "\"privkey\" \"my message\"") +
"\nVerify the signature\n"
+ HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("signmessagewithprivkey", "\"privkey\", \"my message\"")
- );
+ },
+ }.ToString());
std::string strPrivkey = request.params[0].get_str();
std::string strMessage = request.params[1].get_str();
@@ -249,8 +342,10 @@ static UniValue setmocktime(const JSONRPCRequest& request)
{
{"timestamp", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "Unix seconds-since-epoch timestamp\n"
" Pass 0 to go back to using the system time."},
- }}
- .ToString()
+ },
+ RPCResults{},
+ RPCExamples{""},
+ }.ToString()
);
if (!Params().MineBlocksOnDemand())
@@ -314,9 +409,9 @@ static UniValue getmemoryinfo(const JSONRPCRequest& request)
{"mode", RPCArg::Type::STR, /* opt */ true, /* default_val */ "\"stats\"", "determines what kind of information is returned.\n"
" - \"stats\" returns general statistics about memory usage in the daemon.\n"
" - \"mallocinfo\" returns an XML string describing low-level heap state (only available if compiled with glibc 2.10+)."},
- }}
- .ToString() +
- "\nResult (mode \"stats\"):\n"
+ },
+ {
+ RPCResult{"mode \"stats\"",
"{\n"
" \"locked\": { (json object) Information about locked memory manager\n"
" \"used\": xxxxx, (numeric) Number of bytes used\n"
@@ -327,12 +422,16 @@ static UniValue getmemoryinfo(const JSONRPCRequest& request)
" \"chunks_free\": xxxxx, (numeric) Number unused chunks\n"
" }\n"
"}\n"
- "\nResult (mode \"mallocinfo\"):\n"
+ },
+ RPCResult{"mode \"mallocinfo\"",
"\"<malloc version=\"1\">...\"\n"
- "\nExamples:\n"
- + HelpExampleCli("getmemoryinfo", "")
+ },
+ },
+ RPCExamples{
+ HelpExampleCli("getmemoryinfo", "")
+ HelpExampleRpc("getmemoryinfo", "")
- );
+ },
+ }.ToString());
std::string mode = request.params[0].isNull() ? "stats" : request.params[0].get_str();
if (mode == "stats") {
@@ -357,9 +456,9 @@ static void EnableOrDisableLogCategories(UniValue cats, bool enable) {
bool success;
if (enable) {
- success = g_logger->EnableCategory(cat);
+ success = LogInstance().EnableCategory(cat);
} else {
- success = g_logger->DisableCategory(cat);
+ success = LogInstance().DisableCategory(cat);
}
if (!success) {
@@ -392,27 +491,28 @@ UniValue logging(const JSONRPCRequest& request)
{
{"exclude_category", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "the valid logging category"},
}},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{ (json object where keys are the logging categories, and values indicates its status\n"
- " \"category\": 0|1, (numeric) if being debug logged or not. 0:inactive, 1:active\n"
+ " \"category\": true|false, (bool) if being debug logged or not. false:inactive, true:active\n"
" ...\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("logging", "\"[\\\"all\\\"]\" \"[\\\"http\\\"]\"")
- + HelpExampleRpc("logging", "[\"all\"], \"[libevent]\"")
- );
+ },
+ RPCExamples{
+ HelpExampleCli("logging", "\"[\\\"all\\\"]\" \"[\\\"http\\\"]\"")
+ + HelpExampleRpc("logging", "[\"all\"], [\"libevent\"]")
+ },
+ }.ToString());
}
- uint32_t original_log_categories = g_logger->GetCategoryMask();
+ uint32_t original_log_categories = LogInstance().GetCategoryMask();
if (request.params[0].isArray()) {
EnableOrDisableLogCategories(request.params[0], true);
}
if (request.params[1].isArray()) {
EnableOrDisableLogCategories(request.params[1], false);
}
- uint32_t updated_log_categories = g_logger->GetCategoryMask();
+ uint32_t updated_log_categories = LogInstance().GetCategoryMask();
uint32_t changed_log_categories = original_log_categories ^ updated_log_categories;
// Update libevent logging if BCLog::LIBEVENT has changed.
@@ -421,8 +521,8 @@ UniValue logging(const JSONRPCRequest& request)
// Throw an error if the user has explicitly asked to change only the libevent
// flag and it failed.
if (changed_log_categories & BCLog::LIBEVENT) {
- if (!UpdateHTTPServerLogging(g_logger->WillLogCategory(BCLog::LIBEVENT))) {
- g_logger->DisableCategory(BCLog::LIBEVENT);
+ if (!UpdateHTTPServerLogging(LogInstance().WillLogCategory(BCLog::LIBEVENT))) {
+ LogInstance().DisableCategory(BCLog::LIBEVENT);
if (changed_log_categories == BCLog::LIBEVENT) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "libevent logging cannot be updated when using libevent before v2.1.1.");
}
@@ -446,9 +546,11 @@ static UniValue echo(const JSONRPCRequest& request)
"\nSimply echo back the input arguments. This command is for testing.\n"
"\nThe difference between echo and echojson is that echojson has argument conversion enabled in the client-side table in "
"bitcoin-cli and the GUI. There is no server-side difference.",
- {}}
- .ToString() +
- "");
+ {},
+ RPCResults{},
+ RPCExamples{""},
+ }.ToString()
+ );
return request.params;
}
@@ -461,6 +563,7 @@ static const CRPCCommand commands[] =
{ "control", "logging", &logging, {"include", "exclude"}},
{ "util", "validateaddress", &validateaddress, {"address"} },
{ "util", "createmultisig", &createmultisig, {"nrequired","keys","address_type"} },
+ { "util", "deriveaddresses", &deriveaddresses, {"descriptor", "begin", "end"} },
{ "util", "verifymessage", &verifymessage, {"address","signature","message"} },
{ "util", "signmessagewithprivkey", &signmessagewithprivkey, {"privkey","message"} },
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 6fdf80dc5f..b50038b085 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -4,6 +4,7 @@
#include <rpc/server.h>
+#include <banman.h>
#include <chainparams.h>
#include <clientversion.h>
#include <core_io.h>
@@ -29,14 +30,16 @@ static UniValue getconnectioncount(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
RPCHelpMan{"getconnectioncount",
- "\nReturns the number of connections to other nodes.\n", {}}
- .ToString() +
- "\nResult:\n"
+ "\nReturns the number of connections to other nodes.\n",
+ {},
+ RPCResult{
"n (numeric) The connection count\n"
- "\nExamples:\n"
- + HelpExampleCli("getconnectioncount", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getconnectioncount", "")
+ HelpExampleRpc("getconnectioncount", "")
- );
+ },
+ }.ToString());
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -52,12 +55,13 @@ static UniValue ping(const JSONRPCRequest& request)
"\nRequests that a ping be sent to all other nodes, to measure ping time.\n"
"Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\n"
"Ping command is handled in queue with all other commands, so it measures processing backlog, not just network ping.\n",
- {}}
- .ToString() +
- "\nExamples:\n"
- + HelpExampleCli("ping", "")
+ {},
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("ping", "")
+ HelpExampleRpc("ping", "")
- );
+ },
+ }.ToString());
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -74,9 +78,9 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
RPCHelpMan{"getpeerinfo",
- "\nReturns data about each connected network node as a json array of objects.\n", {}}
- .ToString() +
- "\nResult:\n"
+ "\nReturns data about each connected network node as a json array of objects.\n",
+ {},
+ RPCResult{
"[\n"
" {\n"
" \"id\": n, (numeric) Peer index\n"
@@ -123,10 +127,12 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
" }\n"
" ,...\n"
"]\n"
- "\nExamples:\n"
- + HelpExampleCli("getpeerinfo", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getpeerinfo", "")
+ HelpExampleRpc("getpeerinfo", "")
- );
+ },
+ }.ToString());
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -217,12 +223,13 @@ static UniValue addnode(const JSONRPCRequest& request)
{
{"node", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The node (see getpeerinfo for nodes)"},
{"command", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "'add' to add a node to the list, 'remove' to remove a node from the list, 'onetry' to try a connection to the node once"},
- }}
- .ToString() +
- "\nExamples:\n"
- + HelpExampleCli("addnode", "\"192.168.0.6:8333\" \"onetry\"")
+ },
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("addnode", "\"192.168.0.6:8333\" \"onetry\"")
+ HelpExampleRpc("addnode", "\"192.168.0.6:8333\", \"onetry\"")
- );
+ },
+ }.ToString());
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -261,14 +268,15 @@ static UniValue disconnectnode(const JSONRPCRequest& request)
{
{"address", RPCArg::Type::STR, /* opt */ true, /* default_val */ "fallback to nodeid", "The IP address/port of the node"},
{"nodeid", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "fallback to address", "The node ID (see getpeerinfo for node IDs)"},
- }}
- .ToString() +
- "\nExamples:\n"
- + HelpExampleCli("disconnectnode", "\"192.168.0.6:8333\"")
+ },
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("disconnectnode", "\"192.168.0.6:8333\"")
+ HelpExampleCli("disconnectnode", "\"\" 1")
+ HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"")
+ HelpExampleRpc("disconnectnode", "\"\", 1")
- );
+ },
+ }.ToString());
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -304,9 +312,8 @@ static UniValue getaddednodeinfo(const JSONRPCRequest& request)
"(note that onetry addnodes are not listed here)\n",
{
{"node", RPCArg::Type::STR, /* opt */ true, /* default_val */ "all nodes", "If provided, return information about this specific node, otherwise all nodes are returned."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"[\n"
" {\n"
" \"addednode\" : \"192.168.0.201\", (string) The node IP address or name (as provided to addnode)\n"
@@ -320,10 +327,12 @@ static UniValue getaddednodeinfo(const JSONRPCRequest& request)
" }\n"
" ,...\n"
"]\n"
- "\nExamples:\n"
- + HelpExampleCli("getaddednodeinfo", "\"192.168.0.201\"")
+ },
+ RPCExamples{
+ HelpExampleCli("getaddednodeinfo", "\"192.168.0.201\"")
+ HelpExampleRpc("getaddednodeinfo", "\"192.168.0.201\"")
- );
+ },
+ }.ToString());
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -371,9 +380,8 @@ static UniValue getnettotals(const JSONRPCRequest& request)
RPCHelpMan{"getnettotals",
"\nReturns information about network traffic, including bytes in, bytes out,\n"
"and current time.\n",
- {}}
- .ToString() +
- "\nResult:\n"
+ {},
+ RPCResult{
"{\n"
" \"totalbytesrecv\": n, (numeric) Total bytes received\n"
" \"totalbytessent\": n, (numeric) Total bytes sent\n"
@@ -388,10 +396,12 @@ static UniValue getnettotals(const JSONRPCRequest& request)
" \"time_left_in_cycle\": t (numeric) Seconds left in current time cycle\n"
" }\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getnettotals", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getnettotals", "")
+ HelpExampleRpc("getnettotals", "")
- );
+ },
+ }.ToString());
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -437,9 +447,9 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
RPCHelpMan{"getnetworkinfo",
- "Returns an object containing various state info regarding P2P networking.\n", {}}
- .ToString() +
- "\nResult:\n"
+ "Returns an object containing various state info regarding P2P networking.\n",
+ {},
+ RPCResult{
"{\n"
" \"version\": xxxxx, (numeric) the server version\n"
" \"subversion\": \"/Satoshi:x.x.x/\", (string) the server subversion string\n"
@@ -471,10 +481,12 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request)
" ]\n"
" \"warnings\": \"...\" (string) any network and blockchain warnings\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getnetworkinfo", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getnetworkinfo", "")
+ HelpExampleRpc("getnetworkinfo", "")
- );
+ },
+ }.ToString());
LOCK(cs_main);
UniValue obj(UniValue::VOBJ);
@@ -524,15 +536,17 @@ static UniValue setban(const JSONRPCRequest& request)
{"command", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "'add' to add an IP/Subnet to the list, 'remove' to remove an IP/Subnet from the list"},
{"bantime", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "time in seconds how long (or until when if [absolute] is set) the IP is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument)"},
{"absolute", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "If set, the bantime must be an absolute timestamp in seconds since epoch (Jan 1 1970 GMT)"},
- }}
- .ToString() +
- "\nExamples:\n"
- + HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400")
+ },
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400")
+ HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"")
+ HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400")
- );
- if(!g_connman)
- throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+ },
+ }.ToString());
+ if (!g_banman) {
+ throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
+ }
CSubNet subNet;
CNetAddr netAddr;
@@ -554,8 +568,9 @@ static UniValue setban(const JSONRPCRequest& request)
if (strCommand == "add")
{
- if (isSubnet ? g_connman->IsBanned(subNet) : g_connman->IsBanned(netAddr))
+ if (isSubnet ? g_banman->IsBanned(subNet) : g_banman->IsBanned(netAddr)) {
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned");
+ }
int64_t banTime = 0; //use standard bantime if not specified
if (!request.params[2].isNull())
@@ -565,12 +580,23 @@ static UniValue setban(const JSONRPCRequest& request)
if (request.params[3].isTrue())
absolute = true;
- isSubnet ? g_connman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : g_connman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
+ if (isSubnet) {
+ g_banman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute);
+ if (g_connman) {
+ g_connman->DisconnectNode(subNet);
+ }
+ } else {
+ g_banman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
+ if (g_connman) {
+ g_connman->DisconnectNode(netAddr);
+ }
+ }
}
else if(strCommand == "remove")
{
- if (!( isSubnet ? g_connman->Unban(subNet) : g_connman->Unban(netAddr) ))
+ if (!( isSubnet ? g_banman->Unban(subNet) : g_banman->Unban(netAddr) )) {
throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Unban failed. Requested address/subnet was not previously banned.");
+ }
}
return NullUniValue;
}
@@ -580,18 +606,21 @@ static UniValue listbanned(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
RPCHelpMan{"listbanned",
- "\nList all banned IPs/Subnets.\n", {}}
- .ToString() +
- "\nExamples:\n"
- + HelpExampleCli("listbanned", "")
+ "\nList all banned IPs/Subnets.\n",
+ {},
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("listbanned", "")
+ HelpExampleRpc("listbanned", "")
- );
+ },
+ }.ToString());
- if(!g_connman)
- throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+ if(!g_banman) {
+ throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
+ }
banmap_t banMap;
- g_connman->GetBanned(banMap);
+ g_banman->GetBanned(banMap);
UniValue bannedAddresses(UniValue::VARR);
for (const auto& entry : banMap)
@@ -614,16 +643,19 @@ static UniValue clearbanned(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
RPCHelpMan{"clearbanned",
- "\nClear all banned IPs.\n", {}}
- .ToString() +
- "\nExamples:\n"
- + HelpExampleCli("clearbanned", "")
+ "\nClear all banned IPs.\n",
+ {},
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("clearbanned", "")
+ HelpExampleRpc("clearbanned", "")
- );
- if(!g_connman)
- throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+ },
+ }.ToString());
+ if (!g_banman) {
+ throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
+ }
- g_connman->ClearBanned();
+ g_banman->ClearBanned();
return NullUniValue;
}
@@ -636,8 +668,10 @@ static UniValue setnetworkactive(const JSONRPCRequest& request)
"\nDisable/enable all p2p network activity.\n",
{
{"state", RPCArg::Type::BOOL, /* opt */ false, /* default_val */ "", "true to enable networking, false to disable"},
- }}
- .ToString()
+ },
+ RPCResults{},
+ RPCExamples{""},
+ }.ToString()
);
}
@@ -658,9 +692,8 @@ static UniValue getnodeaddresses(const JSONRPCRequest& request)
"\nReturn known addresses which can potentially be used to find new nodes in the network\n",
{
{"count", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1", "How many addresses to return. Limited to the smaller of " + std::to_string(ADDRMAN_GETADDR_MAX) + " or " + std::to_string(ADDRMAN_GETADDR_MAX_PCT) + "% of all known addresses."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"[\n"
" {\n"
" \"time\": ttt, (numeric) Timestamp in seconds since epoch (Jan 1 1970 GMT) keeping track of when the node was last seen\n"
@@ -670,10 +703,12 @@ static UniValue getnodeaddresses(const JSONRPCRequest& request)
" }\n"
" ,....\n"
"]\n"
- "\nExamples:\n"
- + HelpExampleCli("getnodeaddresses", "8")
+ },
+ RPCExamples{
+ HelpExampleCli("getnodeaddresses", "8")
+ HelpExampleRpc("getnodeaddresses", "8")
- );
+ },
+ }.ToString());
}
if (!g_connman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index bf00870107..cce62bacef 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -66,28 +66,31 @@ static UniValue getrawtransaction(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
throw std::runtime_error(
- RPCHelpMan{"getrawtransaction",
- "\nNOTE: By default this function only works for mempool transactions. If the -txindex option is\n"
- "enabled, it also works for blockchain transactions. If the block which contains the transaction\n"
- "is known, its hash can be provided even for nodes without -txindex. Note that if a blockhash is\n"
- "provided, only that block will be searched and if the transaction is in the mempool or other\n"
- "blocks, or if this node does not have the given block available, the transaction will not be found.\n"
- "DEPRECATED: for now, it also works for transactions with unspent outputs.\n"
-
- "\nReturn the raw transaction data.\n"
- "\nIf verbose is 'true', returns an Object with information about 'txid'.\n"
- "If verbose is 'false' or omitted, returns a string that is serialized, hex-encoded data for 'txid'.\n"
- ,
+ RPCHelpMan{
+ "getrawtransaction",
+ "\nReturn the raw transaction data.\n"
+
+ "\nBy default this function only works for mempool transactions. When called with a blockhash\n"
+ "argument, getrawtransaction will return the transaction if the specified block is available and\n"
+ "the transaction is found in that block. When called without a blockhash argument, getrawtransaction\n"
+ "will return the transaction if it is in the mempool, or if -txindex is enabled and the transaction\n"
+ "is in a block in the blockchain.\n"
+
+ "\nHint: use getmempoolentry to fetch a specific transaction from the mempool.\n"
+ "Or use gettransaction for wallet transactions.\n"
+
+ "\nIf verbose is 'true', returns an Object with information about 'txid'.\n"
+ "If verbose is 'false' or omitted, returns a string that is serialized, hex-encoded data for 'txid'.\n",
{
{"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id"},
{"verbose", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "If false, return a string, otherwise return a json object"},
{"blockhash", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "null", "The block in which to look for the transaction"},
- }}
- .ToString() +
- "\nResult (if verbose is not set or set to false):\n"
+ },
+ {
+ RPCResult{"if verbose is not set or set to false",
"\"data\" (string) The serialized, hex-encoded data for 'txid'\n"
-
- "\nResult (if verbose is set to true):\n"
+ },
+ RPCResult{"if verbose is set to true",
"{\n"
" \"in_active_chain\": b, (bool) Whether specified block is in the active chain or not (only present with explicit \"blockhash\" argument)\n"
" \"hex\" : \"data\", (string) The serialized, hex-encoded data for 'txid'\n"
@@ -133,14 +136,16 @@ static UniValue getrawtransaction(const JSONRPCRequest& request)
" \"blocktime\" : ttt (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n"
" \"time\" : ttt, (numeric) Same as \"blocktime\"\n"
"}\n"
-
- "\nExamples:\n"
- + HelpExampleCli("getrawtransaction", "\"mytxid\"")
+ },
+ },
+ RPCExamples{
+ HelpExampleCli("getrawtransaction", "\"mytxid\"")
+ HelpExampleCli("getrawtransaction", "\"mytxid\" true")
+ HelpExampleRpc("getrawtransaction", "\"mytxid\", true")
+ HelpExampleCli("getrawtransaction", "\"mytxid\" false \"myblockhash\"")
+ HelpExampleCli("getrawtransaction", "\"mytxid\" true \"myblockhash\"")
- );
+ },
+ }.ToString());
bool in_active_chain = true;
uint256 hash = ParseHashV(request.params[0], "parameter 1");
@@ -175,7 +180,7 @@ static UniValue getrawtransaction(const JSONRPCRequest& request)
CTransactionRef tx;
uint256 hash_block;
- if (!GetTransaction(hash, tx, Params().GetConsensus(), hash_block, true, blockindex)) {
+ if (!GetTransaction(hash, tx, Params().GetConsensus(), hash_block, blockindex)) {
std::string errmsg;
if (blockindex) {
if (!(blockindex->nStatus & BLOCK_HAVE_DATA)) {
@@ -219,10 +224,12 @@ static UniValue gettxoutproof(const JSONRPCRequest& request)
},
},
{"blockhash", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "null", "If specified, looks for txid in the block with this hash"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"\"data\" (string) A string that is a serialized, hex-encoded data for the proof.\n"
+ },
+ RPCExamples{""},
+ }.ToString()
);
std::set<uint256> setTxids;
@@ -270,7 +277,7 @@ static UniValue gettxoutproof(const JSONRPCRequest& request)
if (pblockindex == nullptr)
{
CTransactionRef tx;
- if (!GetTransaction(oneTxid, tx, Params().GetConsensus(), hashBlock, false) || hashBlock.IsNull())
+ if (!GetTransaction(oneTxid, tx, Params().GetConsensus(), hashBlock) || hashBlock.IsNull())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block");
pblockindex = LookupBlockIndex(hashBlock);
if (!pblockindex) {
@@ -305,10 +312,12 @@ static UniValue verifytxoutproof(const JSONRPCRequest& request)
"and throwing an RPC error if the block is not in our best chain\n",
{
{"proof", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The hex-encoded proof generated by gettxoutproof"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"[\"txid\"] (array, strings) The txid(s) which the proof commits to, or empty array if the proof can not be validated.\n"
+ },
+ RPCExamples{""},
+ }.ToString()
);
CDataStream ssMB(ParseHexV(request.params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
@@ -445,7 +454,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
}
}
- if (!rbf.isNull() && rawTx.vin.size() > 0 && rbfOptIn != SignalsOptInRBF(rawTx)) {
+ if (!rbf.isNull() && rawTx.vin.size() > 0 && rbfOptIn != SignalsOptInRBF(CTransaction(rawTx))) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter combination: Sequence number(s) contradict replaceable option");
}
@@ -494,17 +503,17 @@ static UniValue createrawtransaction(const JSONRPCRequest& request)
{"locktime", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"},
{"replaceable", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Marks this transaction as BIP125-replaceable.\n"
" Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"\"transaction\" (string) hex string of the transaction\n"
-
- "\nExamples:\n"
- + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"address\\\":0.01}]\"")
+ },
+ RPCExamples{
+ HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"address\\\":0.01}]\"")
+ HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"[{\\\"address\\\":0.01}]\"")
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
- );
+ },
+ }.ToString());
}
RPCTypeCheck(request.params, {
@@ -517,7 +526,7 @@ static UniValue createrawtransaction(const JSONRPCRequest& request)
CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], request.params[3]);
- return EncodeHexTx(rawTx);
+ return EncodeHexTx(CTransaction(rawTx));
}
static UniValue decoderawtransaction(const JSONRPCRequest& request)
@@ -530,9 +539,8 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request)
{"hexstring", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction hex string"},
{"iswitness", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction\n"
" If iswitness is not present, heuristic tests will be used in decoding"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{\n"
" \"txid\" : \"id\", (string) The transaction id\n"
" \"hash\" : \"id\", (string) The transaction hash (differs from txid for witness transactions)\n"
@@ -572,11 +580,12 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request)
" ,...\n"
" ],\n"
"}\n"
-
- "\nExamples:\n"
- + HelpExampleCli("decoderawtransaction", "\"hexstring\"")
+ },
+ RPCExamples{
+ HelpExampleCli("decoderawtransaction", "\"hexstring\"")
+ HelpExampleRpc("decoderawtransaction", "\"hexstring\"")
- );
+ },
+ }.ToString());
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL});
@@ -603,9 +612,8 @@ static UniValue decodescript(const JSONRPCRequest& request)
"\nDecode a hex-encoded script.\n",
{
{"hexstring", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "the hex-encoded script"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{\n"
" \"asm\":\"asm\", (string) Script public key\n"
" \"hex\":\"hex\", (string) hex-encoded public key\n"
@@ -617,10 +625,12 @@ static UniValue decodescript(const JSONRPCRequest& request)
" ],\n"
" \"p2sh\",\"address\" (string) address of P2SH script wrapping this redeem script (not returned if the script is already a P2SH).\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("decodescript", "\"hexstring\"")
+ },
+ RPCExamples{
+ HelpExampleCli("decodescript", "\"hexstring\"")
+ HelpExampleRpc("decodescript", "\"hexstring\"")
- );
+ },
+ }.ToString());
RPCTypeCheck(request.params, {UniValue::VSTR});
@@ -706,14 +716,14 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request)
{"hexstring", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "A transaction hash"},
},
},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"\"hex\" (string) The hex-encoded raw transaction with signature(s)\n"
-
- "\nExamples:\n"
- + HelpExampleCli("combinerawtransaction", "[\"myhex1\", \"myhex2\", \"myhex3\"]")
- );
+ },
+ RPCExamples{
+ HelpExampleCli("combinerawtransaction", "[\"myhex1\", \"myhex2\", \"myhex3\"]")
+ },
+ }.ToString());
UniValue txs = request.params[0].get_array();
@@ -773,7 +783,7 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request)
UpdateInput(txin, sigdata);
}
- return EncodeHexTx(mergedTx);
+ return EncodeHexTx(CTransaction(mergedTx));
}
UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, const UniValue& prevTxsUnival, CBasicKeyStore *keystore, bool is_temp_keystore, const UniValue& hashType)
@@ -906,7 +916,7 @@ UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, con
bool fComplete = vErrors.empty();
UniValue result(UniValue::VOBJ);
- result.pushKV("hex", EncodeHexTx(mtx));
+ result.pushKV("hex", EncodeHexTx(CTransaction(mtx)));
result.pushKV("complete", fComplete);
if (!vErrors.empty()) {
result.pushKV("errors", vErrors);
@@ -953,9 +963,8 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
" \"NONE|ANYONECANPAY\"\n"
" \"SINGLE|ANYONECANPAY\"\n"
},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{\n"
" \"hex\" : \"value\", (string) The hex-encoded raw transaction with signature(s)\n"
" \"complete\" : true|false, (boolean) If the transaction has a complete set of signatures\n"
@@ -970,11 +979,12 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
" ,...\n"
" ]\n"
"}\n"
-
- "\nExamples:\n"
- + HelpExampleCli("signrawtransactionwithkey", "\"myhex\"")
+ },
+ RPCExamples{
+ HelpExampleCli("signrawtransactionwithkey", "\"myhex\"")
+ HelpExampleRpc("signrawtransactionwithkey", "\"myhex\"")
- );
+ },
+ }.ToString());
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VARR, UniValue::VSTR}, true);
@@ -1015,11 +1025,11 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request)
{
{"hexstring", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The hex string of the raw transaction"},
{"allowhighfees", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Allow high fees"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"\"hex\" (string) The transaction hash in hex\n"
- "\nExamples:\n"
+ },
+ RPCExamples{
"\nCreate a transaction\n"
+ HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") +
"Sign the transaction, and get back the hex\n"
@@ -1028,7 +1038,8 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request)
+ HelpExampleCli("sendrawtransaction", "\"signedhex\"") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("sendrawtransaction", "\"signedhex\"")
- );
+ },
+ }.ToString());
std::promise<void> promise;
@@ -1118,9 +1129,8 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
},
},
{"allowhighfees", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Allow high fees"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"[ (array) The result of the mempool acceptance test for each raw transaction in the input array.\n"
" Length is exactly one for now.\n"
" {\n"
@@ -1129,7 +1139,8 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
" \"reject-reason\" (string) Rejection string (only present when 'allowed' is false)\n"
" }\n"
"]\n"
- "\nExamples:\n"
+ },
+ RPCExamples{
"\nCreate a transaction\n"
+ HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") +
"Sign the transaction, and get back the hex\n"
@@ -1138,7 +1149,8 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
+ HelpExampleCli("testmempoolaccept", "[\"signedhex\"]") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]")
- );
+ },
+ }.ToString());
}
RPCTypeCheck(request.params, {UniValue::VARR, UniValue::VBOOL});
@@ -1212,9 +1224,8 @@ UniValue decodepsbt(const JSONRPCRequest& request)
"\nReturn a JSON object representing the serialized, base64-encoded partially signed Bitcoin transaction.\n",
{
{"psbt", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The PSBT base64 string"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{\n"
" \"tx\" : { (json object) The decoded network-serialized unsigned transaction.\n"
" ... The layout is the same as the output of decoderawtransaction.\n"
@@ -1301,10 +1312,11 @@ UniValue decodepsbt(const JSONRPCRequest& request)
" ]\n"
" \"fee\" : fee (numeric, optional) The transaction fee paid if all UTXOs slots in the PSBT have been filled.\n"
"}\n"
-
- "\nExamples:\n"
- + HelpExampleCli("decodepsbt", "\"psbt\"")
- );
+ },
+ RPCExamples{
+ HelpExampleCli("decodepsbt", "\"psbt\"")
+ },
+ }.ToString());
RPCTypeCheck(request.params, {UniValue::VSTR});
@@ -1492,19 +1504,23 @@ UniValue combinepsbt(const JSONRPCRequest& request)
{"psbt", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "A base64 string of a PSBT"},
},
},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
" \"psbt\" (string) The base64-encoded partially signed transaction\n"
- "\nExamples:\n"
- + HelpExampleCli("combinepsbt", "[\"mybase64_1\", \"mybase64_2\", \"mybase64_3\"]")
- );
+ },
+ RPCExamples{
+ HelpExampleCli("combinepsbt", "[\"mybase64_1\", \"mybase64_2\", \"mybase64_3\"]")
+ },
+ }.ToString());
RPCTypeCheck(request.params, {UniValue::VARR}, true);
// Unserialize the transactions
std::vector<PartiallySignedTransaction> psbtxs;
UniValue txs = request.params[0].get_array();
+ if (txs.empty()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter 'txs' cannot be empty");
+ }
for (unsigned int i = 0; i < txs.size(); ++i) {
PartiallySignedTransaction psbtx;
std::string error;
@@ -1546,19 +1562,19 @@ UniValue finalizepsbt(const JSONRPCRequest& request)
{"psbt", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "A base64 string of a PSBT"},
{"extract", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "If true and the transaction is complete,\n"
" extract and return the complete transaction in normal network serialization instead of the PSBT."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{\n"
" \"psbt\" : \"value\", (string) The base64-encoded partially signed transaction if not extracted\n"
" \"hex\" : \"value\", (string) The hex-encoded network transaction if extracted\n"
" \"complete\" : true|false, (boolean) If the transaction has a complete set of signatures\n"
" ]\n"
"}\n"
-
- "\nExamples:\n"
- + HelpExampleCli("finalizepsbt", "\"psbt\"")
- );
+ },
+ RPCExamples{
+ HelpExampleCli("finalizepsbt", "\"psbt\"")
+ },
+ }.ToString());
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL}, true);
@@ -1637,13 +1653,14 @@ UniValue createpsbt(const JSONRPCRequest& request)
{"locktime", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"},
{"replaceable", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Marks this transaction as BIP125 replaceable.\n"
" Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
" \"psbt\" (string) The resulting raw transaction (base64-encoded string)\n"
- "\nExamples:\n"
- + HelpExampleCli("createpsbt", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
- );
+ },
+ RPCExamples{
+ HelpExampleCli("createpsbt", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
+ },
+ }.ToString());
RPCTypeCheck(request.params, {
@@ -1688,16 +1705,17 @@ UniValue converttopsbt(const JSONRPCRequest& request)
" If iswitness is not present, heuristic tests will be used in decoding. If true, only witness deserializaion\n"
" will be tried. If false, only non-witness deserialization will be tried. Only has an effect if\n"
" permitsigdata is true."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
" \"psbt\" (string) The resulting raw transaction (base64-encoded string)\n"
- "\nExamples:\n"
+ },
+ RPCExamples{
"\nCreate a transaction\n"
+ HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"") +
"\nConvert the transaction to a PSBT\n"
+ HelpExampleCli("converttopsbt", "\"rawtransaction\"")
- );
+ },
+ }.ToString());
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VBOOL}, true);
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index edaf64f3e1..2ed74547b9 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -51,7 +51,7 @@ struct RPCCommandExecution
explicit RPCCommandExecution(const std::string& method)
{
LOCK(g_rpc_server_info.mutex);
- it = g_rpc_server_info.active_commands.insert(g_rpc_server_info.active_commands.cend(), {method, GetTimeMicros()});
+ it = g_rpc_server_info.active_commands.insert(g_rpc_server_info.active_commands.end(), {method, GetTimeMicros()});
}
~RPCCommandExecution()
{
@@ -231,10 +231,12 @@ UniValue help(const JSONRPCRequest& jsonRequest)
"\nList all commands, or get help for a specified command.\n",
{
{"command", RPCArg::Type::STR, /* opt */ true, /* default_val */ "all commands", "The command to get help on"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"\"text\" (string) The help text\n"
+ },
+ RPCExamples{""},
+ }.ToString()
);
std::string strCommand;
@@ -254,8 +256,11 @@ UniValue stop(const JSONRPCRequest& jsonRequest)
if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
throw std::runtime_error(
RPCHelpMan{"stop",
- "\nStop Bitcoin server.", {}}
- .ToString());
+ "\nStop Bitcoin server.",
+ {},
+ RPCResults{},
+ RPCExamples{""},
+ }.ToString());
// Event loop will exit after current HTTP requests have been handled, so
// this reply will get back to the client.
StartShutdown();
@@ -270,14 +275,16 @@ static UniValue uptime(const JSONRPCRequest& jsonRequest)
if (jsonRequest.fHelp || jsonRequest.params.size() > 0)
throw std::runtime_error(
RPCHelpMan{"uptime",
- "\nReturns the total uptime of the server.\n", {}}
- .ToString() +
- "\nResult:\n"
+ "\nReturns the total uptime of the server.\n",
+ {},
+ RPCResult{
"ttt (numeric) The number of seconds that the server has been running\n"
- "\nExamples:\n"
- + HelpExampleCli("uptime", "")
+ },
+ RPCExamples{
+ HelpExampleCli("uptime", "")
+ HelpExampleRpc("uptime", "")
- );
+ },
+ }.ToString());
return GetTime() - GetStartupTime();
}
@@ -287,8 +294,11 @@ static UniValue getrpcinfo(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() > 0) {
throw std::runtime_error(
RPCHelpMan{"getrpcinfo",
- "\nReturns details of the RPC server.\n", {}}
- .ToString()
+ "\nReturns details of the RPC server.\n",
+ {},
+ RPCResults{},
+ RPCExamples{""},
+ }.ToString()
);
}
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index b91baee4ac..aa5076cd8e 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -4,10 +4,12 @@
#include <key_io.h>
#include <keystore.h>
+#include <policy/fees.h>
#include <rpc/protocol.h>
#include <rpc/util.h>
#include <tinyformat.h>
#include <util/strencodings.h>
+#include <validation.h>
InitInterfaces* g_rpc_interfaces = nullptr;
@@ -129,6 +131,16 @@ UniValue DescribeAddress(const CTxDestination& dest)
return boost::apply_visitor(DescribeAddressVisitor(), dest);
}
+unsigned int ParseConfirmTarget(const UniValue& value)
+{
+ int target = value.get_int();
+ unsigned int max_target = ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
+ if (target < 1 || (unsigned int)target > max_target) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid conf_target, must be between %u - %u", 1, max_target));
+ }
+ return (unsigned int)target;
+}
+
struct Section {
Section(const std::string& left, const std::string& right)
: m_left{left}, m_right{right} {}
@@ -242,8 +254,12 @@ struct Sections {
}
};
-RPCHelpMan::RPCHelpMan(const std::string& name, const std::string& description, const std::vector<RPCArg>& args)
- : m_name{name}, m_description{description}, m_args{args}
+RPCHelpMan::RPCHelpMan(std::string name, std::string description, std::vector<RPCArg> args, RPCResults results, RPCExamples examples)
+ : m_name{std::move(name)},
+ m_description{std::move(description)},
+ m_args{std::move(args)},
+ m_results{std::move(results)},
+ m_examples{std::move(examples)}
{
std::set<std::string> named_args;
for (const auto& arg : m_args) {
@@ -252,6 +268,25 @@ RPCHelpMan::RPCHelpMan(const std::string& name, const std::string& description,
}
}
+std::string RPCResults::ToDescriptionString() const
+{
+ std::string result;
+ for (const auto& r : m_results) {
+ if (r.m_cond.empty()) {
+ result += "\nResult:\n";
+ } else {
+ result += "\nResult (" + r.m_cond + "):\n";
+ }
+ result += r.m_result;
+ }
+ return result;
+}
+
+std::string RPCExamples::ToDescriptionString() const
+{
+ return m_examples.empty() ? m_examples : "\nExamples:\n" + m_examples;
+}
+
std::string RPCHelpMan::ToString() const
{
std::string ret;
@@ -292,6 +327,12 @@ std::string RPCHelpMan::ToString() const
}
ret += sections.ToString();
+ // Result
+ ret += m_results.ToDescriptionString();
+
+ // Examples
+ ret += m_examples.ToDescriptionString();
+
return ret;
}
diff --git a/src/rpc/util.h b/src/rpc/util.h
index 9e97b3ae0b..d34c9cfdbb 100644
--- a/src/rpc/util.h
+++ b/src/rpc/util.h
@@ -28,6 +28,9 @@ CScript CreateMultisigRedeemscript(const int required, const std::vector<CPubKey
UniValue DescribeAddress(const CTxDestination& dest);
+//! Parse a confirm target option and raise an RPC error if it is invalid.
+unsigned int ParseConfirmTarget(const UniValue& value);
+
struct RPCArg {
enum class Type {
OBJ,
@@ -106,10 +109,62 @@ struct RPCArg {
std::string ToDescriptionString(bool implicitly_required = false) const;
};
+struct RPCResult {
+ const std::string m_cond;
+ const std::string m_result;
+
+ explicit RPCResult(std::string result)
+ : m_cond{}, m_result{std::move(result)}
+ {
+ assert(!m_result.empty());
+ }
+
+ RPCResult(std::string cond, std::string result)
+ : m_cond{std::move(cond)}, m_result{std::move(result)}
+ {
+ assert(!m_cond.empty());
+ assert(!m_result.empty());
+ }
+};
+
+struct RPCResults {
+ const std::vector<RPCResult> m_results;
+
+ RPCResults()
+ : m_results{}
+ {
+ }
+
+ RPCResults(RPCResult result)
+ : m_results{{result}}
+ {
+ }
+
+ RPCResults(std::initializer_list<RPCResult> results)
+ : m_results{results}
+ {
+ }
+
+ /**
+ * Return the description string.
+ */
+ std::string ToDescriptionString() const;
+};
+
+struct RPCExamples {
+ const std::string m_examples;
+ RPCExamples(
+ std::string examples)
+ : m_examples(std::move(examples))
+ {
+ }
+ std::string ToDescriptionString() const;
+};
+
class RPCHelpMan
{
public:
- RPCHelpMan(const std::string& name, const std::string& description, const std::vector<RPCArg>& args);
+ RPCHelpMan(std::string name, std::string description, std::vector<RPCArg> args, RPCResults results, RPCExamples examples);
std::string ToString() const;
@@ -117,6 +172,8 @@ private:
const std::string m_name;
const std::string m_description;
const std::vector<RPCArg> m_args;
+ const RPCResults m_results;
+ const RPCExamples m_examples;
};
#endif // BITCOIN_RPC_UTIL_H
diff --git a/src/scheduler.cpp b/src/scheduler.cpp
index b2da62fc75..fdc859b3a0 100644
--- a/src/scheduler.cpp
+++ b/src/scheduler.cpp
@@ -41,7 +41,7 @@ void CScheduler::serviceQueue()
try {
if (!shouldStop() && taskQueue.empty()) {
reverse_lock<boost::unique_lock<boost::mutex> > rlock(lock);
- // Use this chance to get a tiny bit more entropy
+ // Use this chance to get more entropy
RandAddSeedSleep();
}
while (!shouldStop() && taskQueue.empty()) {
diff --git a/src/scheduler.h b/src/scheduler.h
index 6d7f42cf9f..436f661c59 100644
--- a/src/scheduler.h
+++ b/src/scheduler.h
@@ -45,13 +45,13 @@ public:
// Call func at/after time t
void schedule(Function f, boost::chrono::system_clock::time_point t=boost::chrono::system_clock::now());
- // Convenience method: call f once deltaSeconds from now
+ // Convenience method: call f once deltaMilliSeconds from now
void scheduleFromNow(Function f, int64_t deltaMilliSeconds);
// Another convenience method: call f approximately
- // every deltaSeconds forever, starting deltaSeconds from now.
+ // every deltaMilliSeconds forever, starting deltaMilliSeconds from now.
// To be more precise: every time f is finished, it
- // is rescheduled to run deltaSeconds later. If you
+ // is rescheduled to run deltaMilliSeconds later. If you
// need more accurate scheduling, don't use this method.
void scheduleEvery(Function f, int64_t deltaMilliSeconds);
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index a702be5b78..41e0f2e117 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -226,7 +226,7 @@ protected:
* @param pubkeys The evaluations of the m_pubkey_args field.
* @param script The evaluation of m_script_arg (or nullptr when m_script_arg is nullptr).
* @param out A FlatSigningProvider to put scripts or public keys in that are necessary to the solver.
- * The script and pubkeys argument to this function are automatically added.
+ * The script arguments to this function are automatically added, as is the origin info of the provided pubkeys.
* @return A vector with scriptPubKeys for this descriptor.
*/
virtual std::vector<CScript> MakeScripts(const std::vector<CPubKey>& pubkeys, const CScript* script, FlatSigningProvider& out) const = 0;
@@ -322,7 +322,6 @@ public:
for (auto& entry : entries) {
pubkeys.push_back(entry.first);
out.origins.emplace(entry.first.GetID(), std::move(entry.second));
- out.pubkeys.emplace(entry.first.GetID(), entry.first);
}
if (m_script_arg) {
for (const auto& subscript : subscripts) {
@@ -396,7 +395,12 @@ public:
class PKHDescriptor final : public DescriptorImpl
{
protected:
- std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(keys[0].GetID())); }
+ std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider& out) const override
+ {
+ CKeyID id = keys[0].GetID();
+ out.pubkeys.emplace(id, keys[0]);
+ return Singleton(GetScriptForDestination(id));
+ }
public:
PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "pkh") {}
};
@@ -405,7 +409,12 @@ public:
class WPKHDescriptor final : public DescriptorImpl
{
protected:
- std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(WitnessV0KeyHash(keys[0].GetID()))); }
+ std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, const CScript*, FlatSigningProvider& out) const override
+ {
+ CKeyID id = keys[0].GetID();
+ out.pubkeys.emplace(id, keys[0]);
+ return Singleton(GetScriptForDestination(WitnessV0KeyHash(id)));
+ }
public:
WPKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "wpkh") {}
};
@@ -418,6 +427,7 @@ protected:
{
std::vector<CScript> ret;
CKeyID id = keys[0].GetID();
+ out.pubkeys.emplace(id, keys[0]);
ret.emplace_back(GetScriptForRawPubKey(keys[0])); // P2PK
ret.emplace_back(GetScriptForDestination(id)); // P2PKH
if (keys[0].IsCompressed()) {
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 635e4fa3d2..792fb2997f 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -509,7 +509,7 @@ bool IsSolvable(const SigningProvider& provider, const CScript& script)
return false;
}
-PartiallySignedTransaction::PartiallySignedTransaction(const CTransaction& tx) : tx(tx)
+PartiallySignedTransaction::PartiallySignedTransaction(const CMutableTransaction& tx) : tx(tx)
{
inputs.resize(tx.vin.size());
outputs.resize(tx.vout.size());
diff --git a/src/script/sign.h b/src/script/sign.h
index 20c7203b26..e884f4c480 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -574,7 +574,7 @@ struct PartiallySignedTransaction
bool IsSane() const;
PartiallySignedTransaction() {}
PartiallySignedTransaction(const PartiallySignedTransaction& psbt_in) : tx(psbt_in.tx), inputs(psbt_in.inputs), outputs(psbt_in.outputs), unknown(psbt_in.unknown) {}
- explicit PartiallySignedTransaction(const CTransaction& tx);
+ explicit PartiallySignedTransaction(const CMutableTransaction& tx);
// Only checks if they refer to the same transaction
friend bool operator==(const PartiallySignedTransaction& a, const PartiallySignedTransaction &b)
diff --git a/src/streams.h b/src/streams.h
index 0809c96be1..4e600f1826 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -139,7 +139,7 @@ private:
public:
- /*
+ /**
* @param[in] type Serialization Type
* @param[in] version Serialization Version (including any flags)
* @param[in] data Referenced byte vector to overwrite/append
@@ -153,7 +153,7 @@ public:
}
}
- /*
+ /**
* (other params same as above)
* @param[in] args A list of items to deserialize starting at pos.
*/
@@ -715,15 +715,15 @@ private:
const int nType;
const int nVersion;
- FILE *src; // source file
- uint64_t nSrcPos; // how many bytes have been read from source
- uint64_t nReadPos; // how many bytes have been read from this
- uint64_t nReadLimit; // up to which position we're allowed to read
- uint64_t nRewind; // how many bytes we guarantee to rewind
- std::vector<char> vchBuf; // the buffer
+ FILE *src; //!< source file
+ uint64_t nSrcPos; //!< how many bytes have been read from source
+ uint64_t nReadPos; //!< how many bytes have been read from this
+ uint64_t nReadLimit; //!< up to which position we're allowed to read
+ uint64_t nRewind; //!< how many bytes we guarantee to rewind
+ std::vector<char> vchBuf; //!< the buffer
protected:
- // read data from the source to fill the buffer
+ //! read data from the source to fill the buffer
bool Fill() {
unsigned int pos = nSrcPos % vchBuf.size();
unsigned int readNow = vchBuf.size() - pos;
@@ -768,12 +768,12 @@ public:
}
}
- // check whether we're at the end of the source file
+ //! check whether we're at the end of the source file
bool eof() const {
return nReadPos == nSrcPos && feof(src);
}
- // read a number of bytes
+ //! read a number of bytes
void read(char *pch, size_t nSize) {
if (nSize + nReadPos > nReadLimit)
throw std::ios_base::failure("Read attempted past buffer limit");
@@ -795,12 +795,12 @@ public:
}
}
- // return the current reading position
+ //! return the current reading position
uint64_t GetPos() const {
return nReadPos;
}
- // rewind to a given reading position
+ //! rewind to a given reading position
bool SetPos(uint64_t nPos) {
nReadPos = nPos;
if (nReadPos + nRewind < nSrcPos) {
@@ -826,8 +826,8 @@ public:
return true;
}
- // prevent reading beyond a certain position
- // no argument removes the limit
+ //! prevent reading beyond a certain position
+ //! no argument removes the limit
bool SetLimit(uint64_t nPos = std::numeric_limits<uint64_t>::max()) {
if (nPos < nReadPos)
return false;
@@ -842,7 +842,7 @@ public:
return (*this);
}
- // search for a given byte in the stream, and remain positioned on it
+ //! search for a given byte in the stream, and remain positioned on it
void FindByte(char ch) {
while (true) {
if (nReadPos == nSrcPos)
diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp
index 627018083e..5c2050e4a2 100644
--- a/src/support/lockedpool.cpp
+++ b/src/support/lockedpool.cpp
@@ -10,10 +10,6 @@
#endif
#ifdef WIN32
-#ifdef _WIN32_WINNT
-#undef _WIN32_WINNT
-#endif
-#define _WIN32_WINNT 0x0501
#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
diff --git a/src/sync.cpp b/src/sync.cpp
index 30811f5f89..23ca866e53 100644
--- a/src/sync.cpp
+++ b/src/sync.cpp
@@ -73,7 +73,11 @@ struct LockData {
LockOrders lockorders;
InvLockOrders invlockorders;
std::mutex dd_mutex;
-} static lockdata;
+};
+LockData& GetLockData() {
+ static LockData lockdata;
+ return lockdata;
+}
static thread_local LockStack g_lockstack;
@@ -109,6 +113,7 @@ static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch,
static void push_lock(void* c, const CLockLocation& locklocation)
{
+ LockData& lockdata = GetLockData();
std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
g_lockstack.push_back(std::make_pair(c, locklocation));
@@ -173,6 +178,7 @@ void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLi
void DeleteLock(void* cs)
{
+ LockData& lockdata = GetLockData();
if (!lockdata.available) {
// We're already shutting down.
return;
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp
index c900bee199..f58dd20efc 100644
--- a/src/test/bloom_tests.cpp
+++ b/src/test/bloom_tests.cpp
@@ -461,6 +461,9 @@ static std::vector<unsigned char> RandomData()
BOOST_AUTO_TEST_CASE(rolling_bloom)
{
+ SeedInsecureRand(/* deterministic */ true);
+ g_mock_deterministic_tests = true;
+
// last-100-entry, 1% false positive:
CRollingBloomFilter rb1(100, 0.01);
@@ -485,12 +488,8 @@ BOOST_AUTO_TEST_CASE(rolling_bloom)
if (rb1.contains(RandomData()))
++nHits;
}
- // Run test_bitcoin with --log_level=message to see BOOST_TEST_MESSAGEs:
- BOOST_TEST_MESSAGE("RollingBloomFilter got " << nHits << " false positives (~100 expected)");
-
- // Insanely unlikely to get a fp count outside this range:
- BOOST_CHECK(nHits > 25);
- BOOST_CHECK(nHits < 175);
+ // Expect about 100 hits
+ BOOST_CHECK_EQUAL(nHits, 75);
BOOST_CHECK(rb1.contains(data[DATASIZE-1]));
rb1.reset();
@@ -517,10 +516,8 @@ BOOST_AUTO_TEST_CASE(rolling_bloom)
if (rb1.contains(data[i]))
++nHits;
}
- // Expect about 5 false positives, more than 100 means
- // something is definitely broken.
- BOOST_TEST_MESSAGE("RollingBloomFilter got " << nHits << " false positives (~5 expected)");
- BOOST_CHECK(nHits < 100);
+ // Expect about 5 false positives
+ BOOST_CHECK_EQUAL(nHits, 6);
// last-1000-entry, 0.01% false positive:
CRollingBloomFilter rb2(1000, 0.001);
@@ -531,6 +528,7 @@ BOOST_AUTO_TEST_CASE(rolling_bloom)
for (int i = 0; i < DATASIZE; i++) {
BOOST_CHECK(rb2.contains(data[i]));
}
+ g_mock_deterministic_tests = false;
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index aa2e88477d..f6b97a6868 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -279,6 +279,8 @@ UtxoData::iterator FindRandomFrom(const std::set<COutPoint> &utxoSet) {
// has the expected effect (the other duplicate is overwritten at all cache levels)
BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
{
+ SeedInsecureRand(/* deterministic */ true);
+
bool spent_a_duplicate_coinbase = false;
// A simple map to track what we expect the cache stack to represent.
std::map<COutPoint, Coin> result;
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index 8cf614bc8d..e5d62a3ab2 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -4,6 +4,7 @@
// Unit tests for denial-of-service detection/prevention code
+#include <banman.h>
#include <chainparams.h>
#include <keystore.h>
#include <net.h>
@@ -20,6 +21,23 @@
#include <boost/test/unit_test.hpp>
+struct CConnmanTest : public CConnman {
+ using CConnman::CConnman;
+ void AddNode(CNode& node)
+ {
+ LOCK(cs_vNodes);
+ vNodes.push_back(&node);
+ }
+ void ClearNodes()
+ {
+ LOCK(cs_vNodes);
+ for (CNode* node : vNodes) {
+ delete node;
+ }
+ vNodes.clear();
+ }
+};
+
// Tests these internal-to-net_processing.cpp methods:
extern bool AddOrphanTx(const CTransactionRef& tx, NodeId peer);
extern void EraseOrphansFor(NodeId peer);
@@ -57,6 +75,8 @@ BOOST_FIXTURE_TEST_SUITE(denialofservice_tests, TestingSetup)
// work.
BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
{
+ auto connman = MakeUnique<CConnman>(0x1337, 0x1337);
+ auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), nullptr, scheduler, false);
// Mock an outbound peer
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
@@ -109,7 +129,7 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
peerLogic->FinalizeNode(dummyNode1.GetId(), dummy);
}
-static void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerLogicValidation &peerLogic)
+static void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerLogicValidation &peerLogic, CConnmanTest* connman)
{
CAddress addr(ip(g_insecure_rand_ctx.randbits(32)), NODE_NONE);
vNodes.emplace_back(new CNode(id++, ServiceFlags(NODE_NETWORK|NODE_WITNESS), 0, INVALID_SOCKET, addr, 0, 0, CAddress(), "", /*fInboundIn=*/ false));
@@ -120,11 +140,14 @@ static void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerLogicValidat
node.nVersion = 1;
node.fSuccessfullyConnected = true;
- CConnmanTest::AddNode(node);
+ connman->AddNode(node);
}
BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
{
+ auto connman = MakeUnique<CConnmanTest>(0x1337, 0x1337);
+ auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), nullptr, scheduler, false);
+
const Consensus::Params& consensusParams = Params().GetConsensus();
constexpr int nMaxOutbound = 8;
CConnman::Options options;
@@ -137,7 +160,7 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
// Mock some outbound peers
for (int i=0; i<nMaxOutbound; ++i) {
- AddRandomOutboundPeer(vNodes, *peerLogic);
+ AddRandomOutboundPeer(vNodes, *peerLogic, connman.get());
}
peerLogic->CheckForStaleTipAndEvictPeers(consensusParams);
@@ -162,7 +185,7 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
// If we add one more peer, something should get marked for eviction
// on the next check (since we're mocking the time to be in the future, the
// required time connected check should be satisfied).
- AddRandomOutboundPeer(vNodes, *peerLogic);
+ AddRandomOutboundPeer(vNodes, *peerLogic, connman.get());
peerLogic->CheckForStaleTipAndEvictPeers(consensusParams);
for (int i=0; i<nMaxOutbound; ++i) {
@@ -189,13 +212,16 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
peerLogic->FinalizeNode(node->GetId(), dummy);
}
- CConnmanTest::ClearNodes();
+ connman->ClearNodes();
}
BOOST_AUTO_TEST_CASE(DoS_banning)
{
+ auto banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
+ auto connman = MakeUnique<CConnman>(0x1337, 0x1337);
+ auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), banman.get(), scheduler, false);
- connman->ClearBanned();
+ banman->ClearBanned();
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", true);
dummyNode1.SetSendVersion(PROTOCOL_VERSION);
@@ -210,8 +236,8 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
LOCK2(cs_main, dummyNode1.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode1));
}
- BOOST_CHECK(connman->IsBanned(addr1));
- BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
+ BOOST_CHECK(banman->IsBanned(addr1));
+ BOOST_CHECK(!banman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
CAddress addr2(ip(0xa0b0c002), NODE_NONE);
CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, CAddress(), "", true);
@@ -227,8 +253,8 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
LOCK2(cs_main, dummyNode2.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode2));
}
- BOOST_CHECK(!connman->IsBanned(addr2)); // 2 not banned yet...
- BOOST_CHECK(connman->IsBanned(addr1)); // ... but 1 still should be
+ BOOST_CHECK(!banman->IsBanned(addr2)); // 2 not banned yet...
+ BOOST_CHECK(banman->IsBanned(addr1)); // ... but 1 still should be
{
LOCK(cs_main);
Misbehaving(dummyNode2.GetId(), 50);
@@ -237,7 +263,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
LOCK2(cs_main, dummyNode2.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode2));
}
- BOOST_CHECK(connman->IsBanned(addr2));
+ BOOST_CHECK(banman->IsBanned(addr2));
bool dummy;
peerLogic->FinalizeNode(dummyNode1.GetId(), dummy);
@@ -246,8 +272,11 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
BOOST_AUTO_TEST_CASE(DoS_banscore)
{
+ auto banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
+ auto connman = MakeUnique<CConnman>(0x1337, 0x1337);
+ auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), banman.get(), scheduler, false);
- connman->ClearBanned();
+ banman->ClearBanned();
gArgs.ForceSetArg("-banscore", "111"); // because 11 is my favorite number
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, CAddress(), "", true);
@@ -263,7 +292,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
LOCK2(cs_main, dummyNode1.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode1));
}
- BOOST_CHECK(!connman->IsBanned(addr1));
+ BOOST_CHECK(!banman->IsBanned(addr1));
{
LOCK(cs_main);
Misbehaving(dummyNode1.GetId(), 10);
@@ -272,7 +301,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
LOCK2(cs_main, dummyNode1.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode1));
}
- BOOST_CHECK(!connman->IsBanned(addr1));
+ BOOST_CHECK(!banman->IsBanned(addr1));
{
LOCK(cs_main);
Misbehaving(dummyNode1.GetId(), 1);
@@ -281,7 +310,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
LOCK2(cs_main, dummyNode1.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode1));
}
- BOOST_CHECK(connman->IsBanned(addr1));
+ BOOST_CHECK(banman->IsBanned(addr1));
gArgs.ForceSetArg("-banscore", std::to_string(DEFAULT_BANSCORE_THRESHOLD));
bool dummy;
@@ -290,8 +319,11 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
BOOST_AUTO_TEST_CASE(DoS_bantime)
{
+ auto banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
+ auto connman = MakeUnique<CConnman>(0x1337, 0x1337);
+ auto peerLogic = MakeUnique<PeerLogicValidation>(connman.get(), banman.get(), scheduler, false);
- connman->ClearBanned();
+ banman->ClearBanned();
int64_t nStartTime = GetTime();
SetMockTime(nStartTime); // Overrides future calls to GetTime()
@@ -310,13 +342,13 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
LOCK2(cs_main, dummyNode.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode));
}
- BOOST_CHECK(connman->IsBanned(addr));
+ BOOST_CHECK(banman->IsBanned(addr));
SetMockTime(nStartTime+60*60);
- BOOST_CHECK(connman->IsBanned(addr));
+ BOOST_CHECK(banman->IsBanned(addr));
SetMockTime(nStartTime+60*60*24+1);
- BOOST_CHECK(!connman->IsBanned(addr));
+ BOOST_CHECK(!banman->IsBanned(addr));
bool dummy;
peerLogic->FinalizeNode(dummyNode.GetId(), dummy);
diff --git a/src/test/fuzz/fuzz.cpp b/src/test/fuzz/fuzz.cpp
new file mode 100644
index 0000000000..0709da5563
--- /dev/null
+++ b/src/test/fuzz/fuzz.cpp
@@ -0,0 +1,77 @@
+// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <test/fuzz/fuzz.h>
+
+#include <unistd.h>
+
+#include <pubkey.h>
+#include <util/memory.h>
+
+
+static bool read_stdin(std::vector<uint8_t>& data)
+{
+ uint8_t buffer[1024];
+ ssize_t length = 0;
+ while ((length = read(STDIN_FILENO, buffer, 1024)) > 0) {
+ data.insert(data.end(), buffer, buffer + length);
+
+ if (data.size() > (1 << 20)) return false;
+ }
+ return length == 0;
+}
+
+static void initialize()
+{
+ const static auto verify_handle = MakeUnique<ECCVerifyHandle>();
+}
+
+// This function is used by libFuzzer
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
+{
+ test_one_input(std::vector<uint8_t>(data, data + size));
+ return 0;
+}
+
+// This function is used by libFuzzer
+extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
+{
+ initialize();
+ return 0;
+}
+
+// Disabled under WIN32 due to clash with Cygwin's WinMain.
+#ifndef WIN32
+// Declare main(...) "weak" to allow for libFuzzer linking. libFuzzer provides
+// the main(...) function.
+__attribute__((weak))
+#endif
+int main(int argc, char **argv)
+{
+ initialize();
+#ifdef __AFL_INIT
+ // Enable AFL deferred forkserver mode. Requires compilation using
+ // afl-clang-fast++. See fuzzing.md for details.
+ __AFL_INIT();
+#endif
+
+#ifdef __AFL_LOOP
+ // Enable AFL persistent mode. Requires compilation using afl-clang-fast++.
+ // See fuzzing.md for details.
+ while (__AFL_LOOP(1000)) {
+ std::vector<uint8_t> buffer;
+ if (!read_stdin(buffer)) {
+ continue;
+ }
+ test_one_input(buffer);
+ }
+#else
+ std::vector<uint8_t> buffer;
+ if (!read_stdin(buffer)) {
+ return 0;
+ }
+ test_one_input(buffer);
+#endif
+ return 0;
+}
diff --git a/src/test/fuzz/fuzz.h b/src/test/fuzz/fuzz.h
new file mode 100644
index 0000000000..ad62a5faf0
--- /dev/null
+++ b/src/test/fuzz/fuzz.h
@@ -0,0 +1,17 @@
+// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_TEST_FUZZ_FUZZ_H
+#define BITCOIN_TEST_FUZZ_FUZZ_H
+
+#include <functional>
+#include <stdint.h>
+#include <vector>
+
+
+const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
+
+void test_one_input(std::vector<uint8_t> buffer);
+
+#endif // BITCOIN_TEST_FUZZ_FUZZ_H
diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp
index 1057d09471..8194070aba 100644
--- a/src/test/random_tests.cpp
+++ b/src/test/random_tests.cpp
@@ -21,9 +21,14 @@ BOOST_AUTO_TEST_CASE(osrandom_tests)
BOOST_AUTO_TEST_CASE(fastrandom_tests)
{
// Check that deterministic FastRandomContexts are deterministic
+ g_mock_deterministic_tests = true;
FastRandomContext ctx1(true);
FastRandomContext ctx2(true);
+ for (int i = 10; i > 0; --i) {
+ BOOST_CHECK_EQUAL(GetRand(std::numeric_limits<uint64_t>::max()), uint64_t{10393729187455219830U});
+ BOOST_CHECK_EQUAL(GetRandInt(std::numeric_limits<int>::max()), int{769702006});
+ }
BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());
BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());
BOOST_CHECK_EQUAL(ctx1.rand64(), ctx2.rand64());
@@ -38,6 +43,11 @@ BOOST_AUTO_TEST_CASE(fastrandom_tests)
BOOST_CHECK(ctx1.randbytes(50) == ctx2.randbytes(50));
// Check that a nondeterministic ones are not
+ g_mock_deterministic_tests = false;
+ for (int i = 10; i > 0; --i) {
+ BOOST_CHECK(GetRand(std::numeric_limits<uint64_t>::max()) != uint64_t{10393729187455219830U});
+ BOOST_CHECK(GetRandInt(std::numeric_limits<int>::max()) != int{769702006});
+ }
{
FastRandomContext ctx3, ctx4;
BOOST_CHECK(ctx3.rand64() != ctx4.rand64()); // extremely unlikely to be equal
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 858bb512fc..0c3fb7c398 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -4,6 +4,7 @@
#include <test/test_bitcoin.h>
+#include <banman.h>
#include <chainparams.h>
#include <consensus/consensus.h>
#include <consensus/params.h>
@@ -24,21 +25,6 @@ const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
FastRandomContext g_insecure_rand_ctx;
-void CConnmanTest::AddNode(CNode& node)
-{
- LOCK(g_connman->cs_vNodes);
- g_connman->vNodes.push_back(&node);
-}
-
-void CConnmanTest::ClearNodes()
-{
- LOCK(g_connman->cs_vNodes);
- for (const CNode* node : g_connman->vNodes) {
- delete node;
- }
- g_connman->vNodes.clear();
-}
-
std::ostream& operator<<(std::ostream& os, const uint256& num)
{
os << num.ToString();
@@ -49,7 +35,6 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
: m_path_root(fs::temp_directory_path() / "test_bitcoin" / strprintf("%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(1 << 30))))
{
SHA256AutoDetect();
- RandomInit();
ECC_Start();
SetupEnvironment();
SetupNetworking();
@@ -108,9 +93,9 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
nScriptCheckThreads = 3;
for (int i=0; i < nScriptCheckThreads-1; i++)
threadGroup.create_thread(&ThreadScriptCheck);
+
+ g_banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
g_connman = MakeUnique<CConnman>(0x1337, 0x1337); // Deterministic randomness for tests.
- connman = g_connman.get();
- peerLogic.reset(new PeerLogicValidation(connman, scheduler, /*enable_bip61=*/true));
}
TestingSetup::~TestingSetup()
@@ -120,7 +105,7 @@ TestingSetup::~TestingSetup()
GetMainSignals().FlushBackgroundCallbacks();
GetMainSignals().UnregisterBackgroundSignalScheduler();
g_connman.reset();
- peerLogic.reset();
+ g_banman.reset();
UnloadBlockIndex();
pcoinsTip.reset();
pcoinsdbview.reset();
diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h
index 31d90c0151..4a06845683 100644
--- a/src/test/test_bitcoin.h
+++ b/src/test/test_bitcoin.h
@@ -35,6 +35,11 @@ std::ostream& operator<<(typename std::enable_if<std::is_enum<T>::value, std::os
*/
extern FastRandomContext g_insecure_rand_ctx;
+/**
+ * Flag to make GetRand in random.h return the same number
+ */
+extern bool g_mock_deterministic_tests;
+
static inline void SeedInsecureRand(bool deterministic = false)
{
g_insecure_rand_ctx = FastRandomContext(deterministic);
@@ -68,17 +73,11 @@ private:
*/
class CConnman;
class CNode;
-struct CConnmanTest {
- static void AddNode(CNode& node);
- static void ClearNodes();
-};
class PeerLogicValidation;
struct TestingSetup : public BasicTestingSetup {
boost::thread_group threadGroup;
- CConnman* connman;
CScheduler scheduler;
- std::unique_ptr<PeerLogicValidation> peerLogic;
explicit TestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~TestingSetup();
diff --git a/src/test/test_bitcoin_fuzzy.cpp b/src/test/test_bitcoin_fuzzy.cpp
index 88c082ff66..859fba0bdc 100644
--- a/src/test/test_bitcoin_fuzzy.cpp
+++ b/src/test/test_bitcoin_fuzzy.cpp
@@ -2,10 +2,6 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#if defined(HAVE_CONFIG_H)
-#include <config/bitcoin-config.h>
-#endif
-
#include <addrman.h>
#include <blockencodings.h>
#include <chain.h>
@@ -28,304 +24,144 @@
#include <memory>
#include <vector>
-const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
-
-enum TEST_ID {
- CBLOCK_DESERIALIZE=0,
- CTRANSACTION_DESERIALIZE,
- CBLOCKLOCATOR_DESERIALIZE,
- CBLOCKMERKLEROOT,
- CADDRMAN_DESERIALIZE,
- CBLOCKHEADER_DESERIALIZE,
- CBANENTRY_DESERIALIZE,
- CTXUNDO_DESERIALIZE,
- CBLOCKUNDO_DESERIALIZE,
- CCOINS_DESERIALIZE,
- CNETADDR_DESERIALIZE,
- CSERVICE_DESERIALIZE,
- CMESSAGEHEADER_DESERIALIZE,
- CADDRESS_DESERIALIZE,
- CINV_DESERIALIZE,
- CBLOOMFILTER_DESERIALIZE,
- CDISKBLOCKINDEX_DESERIALIZE,
- CTXOUTCOMPRESSOR_DESERIALIZE,
- BLOCKTRANSACTIONS_DESERIALIZE,
- BLOCKTRANSACTIONSREQUEST_DESERIALIZE,
- TEST_ID_END
-};
-
-static bool read_stdin(std::vector<uint8_t> &data) {
- uint8_t buffer[1024];
- ssize_t length=0;
- while((length = read(STDIN_FILENO, buffer, 1024)) > 0) {
- data.insert(data.end(), buffer, buffer+length);
-
- if (data.size() > (1<<20)) return false;
- }
- return length==0;
-}
-
-static int test_one_input(std::vector<uint8_t> buffer) {
- if (buffer.size() < sizeof(uint32_t)) return 0;
-
- uint32_t test_id = 0xffffffff;
- memcpy(&test_id, buffer.data(), sizeof(uint32_t));
- buffer.erase(buffer.begin(), buffer.begin() + sizeof(uint32_t));
-
- if (test_id >= TEST_ID_END) return 0;
+#include <test/fuzz/fuzz.h>
+void test_one_input(std::vector<uint8_t> buffer)
+{
CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION);
try {
int nVersion;
ds >> nVersion;
ds.SetVersion(nVersion);
} catch (const std::ios_base::failure& e) {
- return 0;
+ return;
}
- switch(test_id) {
- case CBLOCK_DESERIALIZE:
- {
+#if BLOCK_DESERIALIZE
try
{
CBlock block;
ds >> block;
- } catch (const std::ios_base::failure& e) {return 0;}
- break;
- }
- case CTRANSACTION_DESERIALIZE:
- {
+ } catch (const std::ios_base::failure& e) {return;}
+#elif TRANSACTION_DESERIALIZE
try
{
CTransaction tx(deserialize, ds);
- } catch (const std::ios_base::failure& e) {return 0;}
- break;
- }
- case CBLOCKLOCATOR_DESERIALIZE:
- {
+ } catch (const std::ios_base::failure& e) {return;}
+#elif BLOCKLOCATOR_DESERIALIZE
try
{
CBlockLocator bl;
ds >> bl;
- } catch (const std::ios_base::failure& e) {return 0;}
- break;
- }
- case CBLOCKMERKLEROOT:
- {
+ } catch (const std::ios_base::failure& e) {return;}
+#elif BLOCKMERKLEROOT
try
{
CBlock block;
ds >> block;
bool mutated;
BlockMerkleRoot(block, &mutated);
- } catch (const std::ios_base::failure& e) {return 0;}
- break;
- }
- case CADDRMAN_DESERIALIZE:
- {
+ } catch (const std::ios_base::failure& e) {return;}
+#elif ADDRMAN_DESERIALIZE
try
{
CAddrMan am;
ds >> am;
- } catch (const std::ios_base::failure& e) {return 0;}
- break;
- }
- case CBLOCKHEADER_DESERIALIZE:
- {
+ } catch (const std::ios_base::failure& e) {return;}
+#elif BLOCKHEADER_DESERIALIZE
try
{
CBlockHeader bh;
ds >> bh;
- } catch (const std::ios_base::failure& e) {return 0;}
- break;
- }
- case CBANENTRY_DESERIALIZE:
- {
+ } catch (const std::ios_base::failure& e) {return;}
+#elif BANENTRY_DESERIALIZE
try
{
CBanEntry be;
ds >> be;
- } catch (const std::ios_base::failure& e) {return 0;}
- break;
- }
- case CTXUNDO_DESERIALIZE:
- {
+ } catch (const std::ios_base::failure& e) {return;}
+#elif TXUNDO_DESERIALIZE
try
{
CTxUndo tu;
ds >> tu;
- } catch (const std::ios_base::failure& e) {return 0;}
- break;
- }
- case CBLOCKUNDO_DESERIALIZE:
- {
+ } catch (const std::ios_base::failure& e) {return;}
+#elif BLOCKUNDO_DESERIALIZE
try
{
CBlockUndo bu;
ds >> bu;
- } catch (const std::ios_base::failure& e) {return 0;}
- break;
- }
- case CCOINS_DESERIALIZE:
- {
+ } catch (const std::ios_base::failure& e) {return;}
+#elif COINS_DESERIALIZE
try
{
Coin coin;
ds >> coin;
- } catch (const std::ios_base::failure& e) {return 0;}
- break;
- }
- case CNETADDR_DESERIALIZE:
- {
+ } catch (const std::ios_base::failure& e) {return;}
+#elif NETADDR_DESERIALIZE
try
{
CNetAddr na;
ds >> na;
- } catch (const std::ios_base::failure& e) {return 0;}
- break;
- }
- case CSERVICE_DESERIALIZE:
- {
+ } catch (const std::ios_base::failure& e) {return;}
+#elif SERVICE_DESERIALIZE
try
{
CService s;
ds >> s;
- } catch (const std::ios_base::failure& e) {return 0;}
- break;
- }
- case CMESSAGEHEADER_DESERIALIZE:
- {
+ } catch (const std::ios_base::failure& e) {return;}
+#elif MESSAGEHEADER_DESERIALIZE
CMessageHeader::MessageStartChars pchMessageStart = {0x00, 0x00, 0x00, 0x00};
try
{
CMessageHeader mh(pchMessageStart);
ds >> mh;
- if (!mh.IsValid(pchMessageStart)) {return 0;}
- } catch (const std::ios_base::failure& e) {return 0;}
- break;
- }
- case CADDRESS_DESERIALIZE:
- {
+ if (!mh.IsValid(pchMessageStart)) {return;}
+ } catch (const std::ios_base::failure& e) {return;}
+#elif ADDRESS_DESERIALIZE
try
{
CAddress a;
ds >> a;
- } catch (const std::ios_base::failure& e) {return 0;}
- break;
- }
- case CINV_DESERIALIZE:
- {
+ } catch (const std::ios_base::failure& e) {return;}
+#elif INV_DESERIALIZE
try
{
CInv i;
ds >> i;
- } catch (const std::ios_base::failure& e) {return 0;}
- break;
- }
- case CBLOOMFILTER_DESERIALIZE:
- {
+ } catch (const std::ios_base::failure& e) {return;}
+#elif BLOOMFILTER_DESERIALIZE
try
{
CBloomFilter bf;
ds >> bf;
- } catch (const std::ios_base::failure& e) {return 0;}
- break;
- }
- case CDISKBLOCKINDEX_DESERIALIZE:
- {
+ } catch (const std::ios_base::failure& e) {return;}
+#elif DISKBLOCKINDEX_DESERIALIZE
try
{
CDiskBlockIndex dbi;
ds >> dbi;
- } catch (const std::ios_base::failure& e) {return 0;}
- break;
- }
- case CTXOUTCOMPRESSOR_DESERIALIZE:
- {
+ } catch (const std::ios_base::failure& e) {return;}
+#elif TXOUTCOMPRESSOR_DESERIALIZE
CTxOut to;
CTxOutCompressor toc(to);
try
{
ds >> toc;
- } catch (const std::ios_base::failure& e) {return 0;}
-
- break;
- }
- case BLOCKTRANSACTIONS_DESERIALIZE:
- {
+ } catch (const std::ios_base::failure& e) {return;}
+#elif BLOCKTRANSACTIONS_DESERIALIZE
try
{
BlockTransactions bt;
ds >> bt;
- } catch (const std::ios_base::failure& e) {return 0;}
-
- break;
- }
- case BLOCKTRANSACTIONSREQUEST_DESERIALIZE:
- {
+ } catch (const std::ios_base::failure& e) {return;}
+#elif BLOCKTRANSACTIONSREQUEST_DESERIALIZE
try
{
BlockTransactionsRequest btr;
ds >> btr;
- } catch (const std::ios_base::failure& e) {return 0;}
-
- break;
- }
- default:
- return 0;
- }
- return 0;
-}
-
-static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle;
-void initialize() {
- globalVerifyHandle = MakeUnique<ECCVerifyHandle>();
-}
-
-// This function is used by libFuzzer
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
- test_one_input(std::vector<uint8_t>(data, data + size));
- return 0;
-}
-
-// This function is used by libFuzzer
-extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
- initialize();
- return 0;
-}
-
-// Disabled under WIN32 due to clash with Cygwin's WinMain.
-#ifndef WIN32
-// Declare main(...) "weak" to allow for libFuzzer linking. libFuzzer provides
-// the main(...) function.
-__attribute__((weak))
-#endif
-int main(int argc, char **argv)
-{
- initialize();
-#ifdef __AFL_INIT
- // Enable AFL deferred forkserver mode. Requires compilation using
- // afl-clang-fast++. See fuzzing.md for details.
- __AFL_INIT();
-#endif
-
-#ifdef __AFL_LOOP
- // Enable AFL persistent mode. Requires compilation using afl-clang-fast++.
- // See fuzzing.md for details.
- int ret = 0;
- while (__AFL_LOOP(1000)) {
- std::vector<uint8_t> buffer;
- if (!read_stdin(buffer)) {
- continue;
- }
- ret = test_one_input(buffer);
- }
- return ret;
+ } catch (const std::ios_base::failure& e) {return;}
#else
- std::vector<uint8_t> buffer;
- if (!read_stdin(buffer)) {
- return 0;
- }
- return test_one_input(buffer);
+#error Need at least one fuzz target to compile
#endif
}
diff --git a/src/test/test_bitcoin_main.cpp b/src/test/test_bitcoin_main.cpp
index 6c066d3fea..46b63b93b4 100644
--- a/src/test/test_bitcoin_main.cpp
+++ b/src/test/test_bitcoin_main.cpp
@@ -4,6 +4,7 @@
#define BOOST_TEST_MODULE Bitcoin Test Suite
+#include <banman.h>
#include <net.h>
#include <memory>
@@ -11,6 +12,7 @@
#include <boost/test/unit_test.hpp>
std::unique_ptr<CConnman> g_connman;
+std::unique_ptr<BanMan> g_banman;
[[noreturn]] void Shutdown(void* parg)
{
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 71b6ec7425..860f64bb11 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -169,11 +169,6 @@ BOOST_AUTO_TEST_CASE(util_FormatISO8601Date)
BOOST_CHECK_EQUAL(FormatISO8601Date(1317425777), "2011-09-30");
}
-BOOST_AUTO_TEST_CASE(util_FormatISO8601Time)
-{
- BOOST_CHECK_EQUAL(FormatISO8601Time(1317425777), "23:36:17Z");
-}
-
struct TestArgsManager : public ArgsManager
{
TestArgsManager() { m_network_only_args.clear(); }
diff --git a/src/txmempool.h b/src/txmempool.h
index b10c9f099f..f7afaec8fc 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -746,7 +746,8 @@ private:
* This allows transaction replacement to work as expected, as you want to
* have all inputs "available" to check signatures, and any cycles in the
* dependency graph are checked directly in AcceptToMemoryPool.
- * It also allows you to sign a double-spend directly in signrawtransaction,
+ * It also allows you to sign a double-spend directly in
+ * signrawtransactionwithkey and signrawtransactionwithwallet,
* as long as the conflicting transaction is not yet confirmed.
*/
class CCoinsViewMemPool : public CCoinsViewBacked
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 3ef8111b32..27ed24d012 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -44,11 +44,6 @@
#pragma warning(disable:4717)
#endif
-#ifdef _WIN32_WINNT
-#undef _WIN32_WINNT
-#endif
-#define _WIN32_WINNT 0x0501
-
#ifdef _WIN32_IE
#undef _WIN32_IE
#endif
@@ -73,9 +68,6 @@
#include <malloc.h>
#endif
-#include <openssl/crypto.h>
-#include <openssl/rand.h>
-#include <openssl/conf.h>
#include <thread>
// Application startup time (used for uptime calculation)
@@ -86,54 +78,6 @@ const char * const BITCOIN_PID_FILENAME = "bitcoind.pid";
ArgsManager gArgs;
-/** Init OpenSSL library multithreading support */
-static std::unique_ptr<CCriticalSection[]> ppmutexOpenSSL;
-void locking_callback(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS
-{
- if (mode & CRYPTO_LOCK) {
- ENTER_CRITICAL_SECTION(ppmutexOpenSSL[i]);
- } else {
- LEAVE_CRITICAL_SECTION(ppmutexOpenSSL[i]);
- }
-}
-
-// Singleton for wrapping OpenSSL setup/teardown.
-class CInit
-{
-public:
- CInit()
- {
- // Init OpenSSL library multithreading support
- ppmutexOpenSSL.reset(new CCriticalSection[CRYPTO_num_locks()]);
- CRYPTO_set_locking_callback(locking_callback);
-
- // OpenSSL can optionally load a config file which lists optional loadable modules and engines.
- // We don't use them so we don't require the config. However some of our libs may call functions
- // which attempt to load the config file, possibly resulting in an exit() or crash if it is missing
- // or corrupt. Explicitly tell OpenSSL not to try to load the file. The result for our libs will be
- // that the config appears to have been loaded and there are no modules/engines available.
- OPENSSL_no_config();
-
-#ifdef WIN32
- // Seed OpenSSL PRNG with current contents of the screen
- RAND_screen();
-#endif
-
- // Seed OpenSSL PRNG with performance counter
- RandAddSeed();
- }
- ~CInit()
- {
- // Securely erase the memory used by the PRNG
- RAND_cleanup();
- // Shutdown OpenSSL library multithreading support
- CRYPTO_set_locking_callback(nullptr);
- // Clear the set of locks now to maintain symmetry with the constructor.
- ppmutexOpenSSL.reset();
- }
-}
-instance_of_cinit;
-
/** A map that contains all the currently held directory locks. After
* successful locking, these will be held here until the global destructor
* cleans them up and thus automatically unlocks them, or ReleaseDirectoryLocks
@@ -167,6 +111,12 @@ bool LockDirectory(const fs::path& directory, const std::string lockfile_name, b
return true;
}
+void UnlockDirectory(const fs::path& directory, const std::string& lockfile_name)
+{
+ std::lock_guard<std::mutex> lock(cs_dir_locks);
+ dir_locks.erase((directory / lockfile_name).string());
+}
+
void ReleaseDirectoryLocks()
{
std::lock_guard<std::mutex> ulock(cs_dir_locks);
@@ -685,6 +635,12 @@ bool HelpRequested(const ArgsManager& args)
return args.IsArgSet("-?") || args.IsArgSet("-h") || args.IsArgSet("-help") || args.IsArgSet("-help-debug");
}
+void SetupHelpOptions(ArgsManager& args)
+{
+ args.AddArg("-?", "Print this help message and exit", false, OptionsCategory::OPTIONS);
+ args.AddHiddenArgs({"-h", "-help"});
+}
+
static const int screenWidth = 79;
static const int optIndent = 2;
static const int msgIndent = 7;
diff --git a/src/util/system.h b/src/util/system.h
index 5932e55793..54d4cf2e58 100644
--- a/src/util/system.h
+++ b/src/util/system.h
@@ -70,6 +70,7 @@ int RaiseFileDescriptorLimit(int nMinFD);
void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length);
bool RenameOver(fs::path src, fs::path dest);
bool LockDirectory(const fs::path& directory, const std::string lockfile_name, bool probe_only=false);
+void UnlockDirectory(const fs::path& directory, const std::string& lockfile_name);
bool DirIsWritable(const fs::path& directory);
/** Release all directory locks. This is used for unit testing only, at runtime
@@ -294,6 +295,9 @@ extern ArgsManager gArgs;
*/
bool HelpRequested(const ArgsManager& args);
+/** Add help options to the args manager */
+void SetupHelpOptions(ArgsManager& args);
+
/**
* Format a string to be used as group of options in help messages
*
diff --git a/src/util/time.cpp b/src/util/time.cpp
index 83a7937d8f..c0ede98701 100644
--- a/src/util/time.cpp
+++ b/src/util/time.cpp
@@ -97,14 +97,3 @@ std::string FormatISO8601Date(int64_t nTime) {
#endif
return strprintf("%04i-%02i-%02i", ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday);
}
-
-std::string FormatISO8601Time(int64_t nTime) {
- struct tm ts;
- time_t time_val = nTime;
-#ifdef _MSC_VER
- gmtime_s(&ts, &time_val);
-#else
- gmtime_r(&time_val, &ts);
-#endif
- return strprintf("%02i:%02i:%02iZ", ts.tm_hour, ts.tm_min, ts.tm_sec);
-}
diff --git a/src/util/time.h b/src/util/time.h
index f2e2747434..68de1c156e 100644
--- a/src/util/time.h
+++ b/src/util/time.h
@@ -33,6 +33,5 @@ void MilliSleep(int64_t n);
*/
std::string FormatISO8601DateTime(int64_t nTime);
std::string FormatISO8601Date(int64_t nTime);
-std::string FormatISO8601Time(int64_t nTime);
#endif // BITCOIN_UTIL_TIME_H
diff --git a/src/validation.cpp b/src/validation.cpp
index 6a26bf9baa..dbdc1afb35 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -152,7 +152,7 @@ private:
public:
CChain chainActive;
- BlockMap mapBlockIndex;
+ BlockMap mapBlockIndex GUARDED_BY(cs_main);
std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
CBlockIndex *pindexBestInvalid = nullptr;
@@ -1002,13 +1002,11 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
* Return transaction in txOut, and if it was found inside a block, its hash is placed in hashBlock.
* If blockIndex is provided, the transaction is fetched from the corresponding block.
*/
-bool GetTransaction(const uint256& hash, CTransactionRef& txOut, const Consensus::Params& consensusParams, uint256& hashBlock, bool fAllowSlow, CBlockIndex* blockIndex)
+bool GetTransaction(const uint256& hash, CTransactionRef& txOut, const Consensus::Params& consensusParams, uint256& hashBlock, const CBlockIndex* const block_index)
{
- CBlockIndex* pindexSlow = blockIndex;
-
LOCK(cs_main);
- if (!blockIndex) {
+ if (!block_index) {
CTransactionRef ptx = mempool.get(hash);
if (ptx) {
txOut = ptx;
@@ -1018,20 +1016,13 @@ bool GetTransaction(const uint256& hash, CTransactionRef& txOut, const Consensus
if (g_txindex) {
return g_txindex->FindTx(hash, hashBlock, txOut);
}
-
- if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it
- const Coin& coin = AccessByTxid(*pcoinsTip, hash);
- if (!coin.IsSpent()) pindexSlow = chainActive[coin.nHeight];
- }
- }
-
- if (pindexSlow) {
+ } else {
CBlock block;
- if (ReadBlockFromDisk(block, pindexSlow, consensusParams)) {
+ if (ReadBlockFromDisk(block, block_index, consensusParams)) {
for (const auto& tx : block.vtx) {
if (tx->GetHash() == hash) {
txOut = tx;
- hashBlock = pindexSlow->GetBlockHash();
+ hashBlock = block_index->GetBlockHash();
return true;
}
}
diff --git a/src/validation.h b/src/validation.h
index b5548a9293..49f73e4c9b 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -50,7 +50,7 @@ struct LockPoints;
/** Default for -whitelistrelay. */
static const bool DEFAULT_WHITELISTRELAY = true;
/** Default for -whitelistforcerelay. */
-static const bool DEFAULT_WHITELISTFORCERELAY = true;
+static const bool DEFAULT_WHITELISTFORCERELAY = false;
/** Default for -minrelaytxfee, minimum relay fee for transactions */
static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 1000;
//! -maxtxfee default
@@ -151,7 +151,7 @@ extern CBlockPolicyEstimator feeEstimator;
extern CTxMemPool mempool;
extern std::atomic_bool g_is_mempool_loaded;
typedef std::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap;
-extern BlockMap& mapBlockIndex;
+extern BlockMap& mapBlockIndex GUARDED_BY(cs_main);
extern uint64_t nLastBlockTx;
extern uint64_t nLastBlockWeight;
extern const std::string strMessageMagic;
@@ -201,14 +201,14 @@ static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288;
static const signed int DEFAULT_CHECKBLOCKS = 6;
static const unsigned int DEFAULT_CHECKLEVEL = 3;
-// Require that user allocate at least 550MB for block & undo files (blk???.dat and rev???.dat)
+// Require that user allocate at least 550 MiB for block & undo files (blk???.dat and rev???.dat)
// At 1MB per block, 288 blocks = 288MB.
// Add 15% for Undo data = 331MB
// Add 20% for Orphan block rate = 397MB
// We want the low water mark after pruning to be at least 397 MB and since we prune in
// full block file chunks, we need the high water mark which triggers the prune to be
// one 128MB block file + added 15% undo data = 147MB greater for a total of 545MB
-// Setting the target to > than 550MB will make it likely we can respect the target.
+// Setting the target to >= 550 MiB will make it likely we can respect the target.
static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024;
/**
@@ -269,7 +269,7 @@ void ThreadScriptCheck();
/** Check whether we are doing an initial block download (synchronizing from disk or network) */
bool IsInitialBlockDownload();
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
-bool GetTransaction(const uint256& hash, CTransactionRef& tx, const Consensus::Params& params, uint256& hashBlock, bool fAllowSlow = false, CBlockIndex* blockIndex = nullptr);
+bool GetTransaction(const uint256& hash, CTransactionRef& tx, const Consensus::Params& params, uint256& hashBlock, const CBlockIndex* const blockIndex = nullptr);
/**
* Find the best known block, and make it the tip of the block chain
*
@@ -288,7 +288,7 @@ uint64_t CalculateCurrentUsage();
/**
* Mark one block file as pruned.
*/
-void PruneOneBlockFile(const int fileNumber);
+void PruneOneBlockFile(const int fileNumber) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Actually unlink the specified files
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index 533d412888..70c274d20e 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -14,6 +14,7 @@
#include <list>
#include <atomic>
#include <future>
+#include <utility>
#include <boost/signals2/signal.hpp>
@@ -77,7 +78,10 @@ size_t CMainSignals::CallbacksPending() {
}
void CMainSignals::RegisterWithMempoolSignals(CTxMemPool& pool) {
- g_connNotifyEntryRemoved.emplace(&pool, pool.NotifyEntryRemoved.connect(std::bind(&CMainSignals::MempoolEntryRemoved, this, std::placeholders::_1, std::placeholders::_2)));
+ g_connNotifyEntryRemoved.emplace(std::piecewise_construct,
+ std::forward_as_tuple(&pool),
+ std::forward_as_tuple(pool.NotifyEntryRemoved.connect(std::bind(&CMainSignals::MempoolEntryRemoved, this, std::placeholders::_1, std::placeholders::_2)))
+ );
}
void CMainSignals::UnregisterWithMempoolSignals(CTxMemPool& pool) {
@@ -103,7 +107,9 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
}
void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
- g_signals.m_internals->m_connMainSignals.erase(pwalletIn);
+ if (g_signals.m_internals) {
+ g_signals.m_internals->m_connMainSignals.erase(pwalletIn);
+ }
}
void UnregisterAllValidationInterfaces() {
diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp
index f5ac6e98b2..a255177e36 100644
--- a/src/wallet/crypter.cpp
+++ b/src/wallet/crypter.cpp
@@ -175,14 +175,14 @@ bool CCryptoKeyStore::Lock()
return true;
}
-bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
+bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys)
{
{
LOCK(cs_KeyStore);
if (!SetCrypted())
return false;
- bool keyPass = false;
+ bool keyPass = mapCryptedKeys.empty(); // Always pass when there are no encrypted keys
bool keyFail = false;
CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
for (; mi != mapCryptedKeys.end(); ++mi)
@@ -204,7 +204,7 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
throw std::runtime_error("Error unlocking wallet: some keys decrypt but not all. Your wallet file may be corrupt.");
}
- if (keyFail || !keyPass)
+ if (keyFail || (!keyPass && !accept_no_keys))
return false;
vMasterKey = vMasterKeyIn;
fDecryptionThoroughlyChecked = true;
diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h
index 418316c398..8e195ca8fa 100644
--- a/src/wallet/crypter.h
+++ b/src/wallet/crypter.h
@@ -133,7 +133,7 @@ protected:
//! will encrypt previously unencrypted keys
bool EncryptKeys(CKeyingMaterial& vMasterKeyIn);
- bool Unlock(const CKeyingMaterial& vMasterKeyIn);
+ bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys = false);
CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore);
public:
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index a2e795056a..c64a85c910 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -48,7 +48,7 @@ void CheckUniqueFileid(const BerkeleyEnvironment& env, const std::string& filena
}
CCriticalSection cs_db;
-std::map<std::string, BerkeleyEnvironment> g_dbenvs GUARDED_BY(cs_db); //!< Map from directory name to open db environment.
+std::map<std::string, std::weak_ptr<BerkeleyEnvironment>> g_dbenvs GUARDED_BY(cs_db); //!< Map from directory name to db environment.
} // namespace
bool WalletDatabaseFileId::operator==(const WalletDatabaseFileId& rhs) const
@@ -80,19 +80,29 @@ bool IsWalletLoaded(const fs::path& wallet_path)
LOCK(cs_db);
auto env = g_dbenvs.find(env_directory.string());
if (env == g_dbenvs.end()) return false;
- return env->second.IsDatabaseLoaded(database_filename);
+ auto database = env->second.lock();
+ return database && database->IsDatabaseLoaded(database_filename);
}
-BerkeleyEnvironment* GetWalletEnv(const fs::path& wallet_path, std::string& database_filename)
+/**
+ * @param[in] wallet_path Path to wallet directory. Or (for backwards compatibility only) a path to a berkeley btree data file inside a wallet directory.
+ * @param[out] database_filename Filename of berkeley btree data file inside the wallet directory.
+ * @return A shared pointer to the BerkeleyEnvironment object for the wallet directory, never empty because ~BerkeleyEnvironment
+ * erases the weak pointer from the g_dbenvs map.
+ * @post A new BerkeleyEnvironment weak pointer is inserted into g_dbenvs if the directory path key was not already in the map.
+ */
+std::shared_ptr<BerkeleyEnvironment> GetWalletEnv(const fs::path& wallet_path, std::string& database_filename)
{
fs::path env_directory;
SplitWalletPath(wallet_path, env_directory, database_filename);
LOCK(cs_db);
- // Note: An unused temporary BerkeleyEnvironment object may be created inside the
- // emplace function if the key already exists. This is a little inefficient,
- // but not a big concern since the map will be changed in the future to hold
- // pointers instead of objects, anyway.
- return &g_dbenvs.emplace(std::piecewise_construct, std::forward_as_tuple(env_directory.string()), std::forward_as_tuple(env_directory)).first->second;
+ auto inserted = g_dbenvs.emplace(env_directory.string(), std::weak_ptr<BerkeleyEnvironment>());
+ if (inserted.second) {
+ auto env = std::make_shared<BerkeleyEnvironment>(env_directory.string());
+ inserted.first->second = env;
+ return env;
+ }
+ return inserted.first->second.lock();
}
//
@@ -116,11 +126,18 @@ void BerkeleyEnvironment::Close()
}
}
+ FILE* error_file = nullptr;
+ dbenv->get_errfile(&error_file);
+
int ret = dbenv->close(0);
if (ret != 0)
LogPrintf("BerkeleyEnvironment::Close: Error %d closing database environment: %s\n", ret, DbEnv::strerror(ret));
if (!fMockDb)
DbEnv((u_int32_t)0).remove(strPath.c_str(), 0);
+
+ if (error_file) fclose(error_file);
+
+ UnlockDirectory(strPath, ".walletlock");
}
void BerkeleyEnvironment::Reset()
@@ -137,6 +154,8 @@ BerkeleyEnvironment::BerkeleyEnvironment(const fs::path& dir_path) : strPath(dir
BerkeleyEnvironment::~BerkeleyEnvironment()
{
+ LOCK(cs_db);
+ g_dbenvs.erase(strPath);
Close();
}
@@ -214,10 +233,10 @@ bool BerkeleyEnvironment::Open(bool retry)
return true;
}
-void BerkeleyEnvironment::MakeMock()
+//! Construct an in-memory mock Berkeley environment for testing and as a place-holder for g_dbenvs emplace
+BerkeleyEnvironment::BerkeleyEnvironment()
{
- if (fDbEnvInit)
- throw std::runtime_error("BerkeleyEnvironment::MakeMock: Already initialized");
+ Reset();
boost::this_thread::interruption_point();
@@ -305,7 +324,7 @@ BerkeleyBatch::SafeDbt::operator Dbt*()
bool BerkeleyBatch::Recover(const fs::path& file_path, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& newFilename)
{
std::string filename;
- BerkeleyEnvironment* env = GetWalletEnv(file_path, filename);
+ std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(file_path, filename);
// Recovery procedure:
// move wallet file to walletfilename.timestamp.bak
@@ -374,7 +393,7 @@ bool BerkeleyBatch::Recover(const fs::path& file_path, void *callbackDataIn, boo
bool BerkeleyBatch::VerifyEnvironment(const fs::path& file_path, std::string& errorStr)
{
std::string walletFile;
- BerkeleyEnvironment* env = GetWalletEnv(file_path, walletFile);
+ std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(file_path, walletFile);
fs::path walletDir = env->Directory();
LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(nullptr, nullptr, nullptr));
@@ -398,7 +417,7 @@ bool BerkeleyBatch::VerifyEnvironment(const fs::path& file_path, std::string& er
bool BerkeleyBatch::VerifyDatabaseFile(const fs::path& file_path, std::string& warningStr, std::string& errorStr, BerkeleyEnvironment::recoverFunc_type recoverFunc)
{
std::string walletFile;
- BerkeleyEnvironment* env = GetWalletEnv(file_path, walletFile);
+ std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(file_path, walletFile);
fs::path walletDir = env->Directory();
if (fs::exists(walletDir / walletFile))
@@ -502,7 +521,7 @@ BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bo
{
fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w'));
fFlushOnClose = fFlushOnCloseIn;
- env = database.env;
+ env = database.env.get();
if (database.IsDummy()) {
return;
}
@@ -559,7 +578,7 @@ BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bo
// versions of BDB have an set_lk_exclusive method for this
// purpose, but the older version we use does not.)
for (const auto& env : g_dbenvs) {
- CheckUniqueFileid(env.second, strFilename, *pdb_temp, this->env->m_fileids[strFilename]);
+ CheckUniqueFileid(*env.second.lock().get(), strFilename, *pdb_temp, this->env->m_fileids[strFilename]);
}
pdb = pdb_temp.release();
@@ -660,7 +679,7 @@ bool BerkeleyBatch::Rewrite(BerkeleyDatabase& database, const char* pszSkip)
if (database.IsDummy()) {
return true;
}
- BerkeleyEnvironment *env = database.env;
+ BerkeleyEnvironment *env = database.env.get();
const std::string& strFile = database.strFile;
while (true) {
{
@@ -791,7 +810,7 @@ bool BerkeleyBatch::PeriodicFlush(BerkeleyDatabase& database)
return true;
}
bool ret = false;
- BerkeleyEnvironment *env = database.env;
+ BerkeleyEnvironment *env = database.env.get();
const std::string& strFile = database.strFile;
TRY_LOCK(cs_db, lockDb);
if (lockDb)
diff --git a/src/wallet/db.h b/src/wallet/db.h
index 9dc373c89b..9df965305a 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -50,10 +50,10 @@ public:
std::condition_variable_any m_db_in_use;
BerkeleyEnvironment(const fs::path& env_directory);
+ BerkeleyEnvironment();
~BerkeleyEnvironment();
void Reset();
- void MakeMock();
bool IsMock() const { return fMockDb; }
bool IsInitialized() const { return fDbEnvInit; }
bool IsDatabaseLoaded(const std::string& db_filename) const { return m_databases.find(db_filename) != m_databases.end(); }
@@ -102,7 +102,7 @@ public:
bool IsWalletLoaded(const fs::path& wallet_path);
/** Get BerkeleyEnvironment and database filename given a wallet path. */
-BerkeleyEnvironment* GetWalletEnv(const fs::path& wallet_path, std::string& database_filename);
+std::shared_ptr<BerkeleyEnvironment> GetWalletEnv(const fs::path& wallet_path, std::string& database_filename);
/** An instance of this class represents one database.
* For BerkeleyDB this is just a (env, strFile) tuple.
@@ -117,17 +117,11 @@ public:
}
/** Create DB handle to real database */
- BerkeleyDatabase(const fs::path& wallet_path, bool mock = false) :
- nUpdateCounter(0), nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0)
+ BerkeleyDatabase(std::shared_ptr<BerkeleyEnvironment> env, std::string filename) :
+ nUpdateCounter(0), nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0), env(std::move(env)), strFile(std::move(filename))
{
- env = GetWalletEnv(wallet_path, strFile);
- auto inserted = env->m_databases.emplace(strFile, std::ref(*this));
+ auto inserted = this->env->m_databases.emplace(strFile, std::ref(*this));
assert(inserted.second);
- if (mock) {
- env->Close();
- env->Reset();
- env->MakeMock();
- }
}
~BerkeleyDatabase() {
@@ -140,7 +134,8 @@ public:
/** Return object for accessing database at specified path. */
static std::unique_ptr<BerkeleyDatabase> Create(const fs::path& path)
{
- return MakeUnique<BerkeleyDatabase>(path);
+ std::string filename;
+ return MakeUnique<BerkeleyDatabase>(GetWalletEnv(path, filename), std::move(filename));
}
/** Return object for accessing dummy database with no read/write capabilities. */
@@ -152,7 +147,7 @@ public:
/** Return object for accessing temporary in-memory database. */
static std::unique_ptr<BerkeleyDatabase> CreateMock()
{
- return MakeUnique<BerkeleyDatabase>("", true /* mock */);
+ return MakeUnique<BerkeleyDatabase>(std::make_shared<BerkeleyEnvironment>(), "");
}
/** Rewrite the entire database on disk, with the exception of key pszSkip if non-zero
@@ -176,12 +171,21 @@ public:
unsigned int nLastFlushed;
int64_t nLastWalletUpdate;
+ /**
+ * Pointer to shared database environment.
+ *
+ * Normally there is only one BerkeleyDatabase object per
+ * BerkeleyEnvivonment, but in the special, backwards compatible case where
+ * multiple wallet BDB data files are loaded from the same directory, this
+ * will point to a shared instance that gets freed when the last data file
+ * is closed.
+ */
+ std::shared_ptr<BerkeleyEnvironment> env;
+
/** Database pointer. This is initialized lazily and reset during flushes, so it can be null. */
std::unique_ptr<Db> m_db;
private:
- /** BerkeleyDB specific */
- BerkeleyEnvironment *env;
std::string strFile;
/** Return whether this database handle is a dummy for testing.
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index 87cd264c3d..20d540c8db 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -127,21 +127,6 @@ bool WalletInit::ParameterInteraction() const
InitWarning(AmountHighWarn("-minrelaytxfee") + " " +
_("The wallet will avoid paying less than the minimum relay fee."));
- if (gArgs.IsArgSet("-maxtxfee"))
- {
- CAmount nMaxFee = 0;
- if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee))
- return InitError(AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", "")));
- if (nMaxFee > HIGH_MAX_TX_FEE)
- InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
- maxTxFee = nMaxFee;
- if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee)
- {
- return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
- gArgs.GetArg("-maxtxfee", ""), ::minRelayTxFee.ToString()));
- }
- }
-
return true;
}
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 295dfcc63f..7552722a8e 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -9,6 +9,7 @@
#include <merkleblock.h>
#include <rpc/server.h>
#include <rpc/util.h>
+#include <script/descriptor.h>
#include <script/script.h>
#include <script/standard.h>
#include <sync.h>
@@ -66,7 +67,7 @@ static std::string DecodeDumpString(const std::string &str) {
return ret.str();
}
-static bool GetWalletAddressesForKey(CWallet * const pwallet, const CKeyID &keyid, std::string &strAddr, std::string &strLabel)
+static bool GetWalletAddressesForKey(CWallet* const pwallet, const CKeyID& keyid, std::string& strAddr, std::string& strLabel) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
{
bool fLabelFound = false;
CKey key;
@@ -111,16 +112,16 @@ UniValue importprivkey(const JSONRPCRequest& request)
throw std::runtime_error(
RPCHelpMan{"importprivkey",
"\nAdds a private key (as returned by dumpprivkey) to your wallet. Requires a new wallet backup.\n"
- "Hint: use importmulti to import more than one private key.\n",
+ "Hint: use importmulti to import more than one private key.\n"
+ "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
+ "may report that the imported key exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n",
{
{"privkey", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The private key (see dumpprivkey)"},
{"label", RPCArg::Type::STR, /* opt */ true, /* default_val */ "current label if address exists, otherwise \"\"", "An optional label"},
{"rescan", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "Rescan the wallet for transactions"},
- }}
- .ToString() +
- "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
- "may report that the imported key exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
- "\nExamples:\n"
+ },
+ RPCResults{},
+ RPCExamples{
"\nDump a private key\n"
+ HelpExampleCli("dumpprivkey", "\"myaddress\"") +
"\nImport the private key with rescan\n"
@@ -131,8 +132,12 @@ UniValue importprivkey(const JSONRPCRequest& request)
+ HelpExampleCli("importprivkey", "\"mykey\" \"\" false") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")
- );
+ },
+ }.ToString());
+ if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled");
+ }
WalletRescanReserver reserver(pwallet);
bool fRescan = true;
@@ -209,16 +214,18 @@ UniValue abortrescan(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() > 0)
throw std::runtime_error(
RPCHelpMan{"abortrescan",
- "\nStops current wallet rescan triggered by an RPC call, e.g. by an importprivkey call.\n", {}}
- .ToString() +
- "\nExamples:\n"
+ "\nStops current wallet rescan triggered by an RPC call, e.g. by an importprivkey call.\n",
+ {},
+ RPCResults{},
+ RPCExamples{
"\nImport a private key\n"
+ HelpExampleCli("importprivkey", "\"mykey\"") +
"\nAbort the running wallet rescan\n"
+ HelpExampleCli("abortrescan", "") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("abortrescan", "")
- );
+ },
+ }.ToString());
if (!pwallet->IsScanning() || pwallet->IsAbortingRescan()) return false;
pwallet->AbortRescan();
@@ -272,27 +279,28 @@ UniValue importaddress(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
throw std::runtime_error(
RPCHelpMan{"importaddress",
- "\nAdds an address or script (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n",
+ "\nAdds an address or script (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n"
+ "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
+ "may report that the imported address exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
+ "If you have the full public key, you should call importpubkey instead of this.\n"
+ "\nNote: If you import a non-standard raw script in hex form, outputs sending to it will be treated\n"
+ "as change, and not show up in many RPCs.\n",
{
{"address", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The Bitcoin address (or hex-encoded script)"},
{"label", RPCArg::Type::STR, /* opt */ true, /* default_val */ "\"\"", "An optional label"},
{"rescan", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "Rescan the wallet for transactions"},
{"p2sh", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Add the P2SH version of the script as well"},
- }}
- .ToString() +
- "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
- "may report that the imported address exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
- "If you have the full public key, you should call importpubkey instead of this.\n"
- "\nNote: If you import a non-standard raw script in hex form, outputs sending to it will be treated\n"
- "as change, and not show up in many RPCs.\n"
- "\nExamples:\n"
+ },
+ RPCResults{},
+ RPCExamples{
"\nImport an address with rescan\n"
+ HelpExampleCli("importaddress", "\"myaddress\"") +
"\nImport using a label without rescan\n"
+ HelpExampleCli("importaddress", "\"myaddress\" \"testing\" false") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("importaddress", "\"myaddress\", \"testing\", false")
- );
+ },
+ }.ToString());
std::string strLabel;
@@ -358,8 +366,10 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
{
{"rawtransaction", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "A raw transaction in hex funding an already-existing address in wallet"},
{"txoutproof", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The hex output from gettxoutproof that contains the transaction"},
- }}
- .ToString()
+ },
+ RPCResults{},
+ RPCExamples{""},
+ }.ToString()
);
CMutableTransaction tx;
@@ -379,8 +389,7 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) == merkleBlock.header.hashMerkleRoot) {
auto locked_chain = pwallet->chain().lock();
- const CBlockIndex* pindex = LookupBlockIndex(merkleBlock.header.GetHash());
- if (!pindex || !chainActive.Contains(pindex)) {
+ if (locked_chain->getBlockHeight(merkleBlock.header.GetHash()) == nullopt) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
}
@@ -423,13 +432,14 @@ UniValue removeprunedfunds(const JSONRPCRequest& request)
"\nDeletes the specified transaction from the wallet. Meant for use with pruned wallets and as a companion to importprunedfunds. This will affect wallet balances.\n",
{
{"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The hex-encoded id of the transaction you are deleting"},
- }}
- .ToString() +
- "\nExamples:\n"
- + HelpExampleCli("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"") +
+ },
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"")
- );
+ },
+ }.ToString());
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
@@ -461,23 +471,24 @@ UniValue importpubkey(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
throw std::runtime_error(
RPCHelpMan{"importpubkey",
- "\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n",
+ "\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n"
+ "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
+ "may report that the imported pubkey exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n",
{
{"pubkey", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The hex-encoded public key"},
{"label", RPCArg::Type::STR, /* opt */ true, /* default_val */ "\"\"", "An optional label"},
{"rescan", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "Rescan the wallet for transactions"},
- }}
- .ToString() +
- "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
- "may report that the imported pubkey exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
- "\nExamples:\n"
+ },
+ RPCResults{},
+ RPCExamples{
"\nImport a public key with rescan\n"
+ HelpExampleCli("importpubkey", "\"mypubkey\"") +
"\nImport using a label without rescan\n"
+ HelpExampleCli("importpubkey", "\"mypubkey\" \"testing\" false") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("importpubkey", "\"mypubkey\", \"testing\", false")
- );
+ },
+ }.ToString());
std::string strLabel;
@@ -538,16 +549,17 @@ UniValue importwallet(const JSONRPCRequest& request)
"\nImports keys from a wallet dump file (see dumpwallet). Requires a new wallet backup to include imported keys.\n",
{
{"filename", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The wallet file"},
- }}
- .ToString() +
- "\nExamples:\n"
+ },
+ RPCResults{},
+ RPCExamples{
"\nDump the wallet\n"
+ HelpExampleCli("dumpwallet", "\"test\"") +
"\nImport the wallet\n"
+ HelpExampleCli("importwallet", "\"test\"") +
"\nImport using the json rpc call\n"
+ HelpExampleRpc("importwallet", "\"test\"")
- );
+ },
+ }.ToString());
if (fPruneMode)
throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled in pruned mode");
@@ -570,7 +582,8 @@ UniValue importwallet(const JSONRPCRequest& request)
if (!file.is_open()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
}
- nTimeBegin = chainActive.Tip()->GetBlockTime();
+ Optional<int> tip_height = locked_chain->getHeight();
+ nTimeBegin = tip_height ? locked_chain->getBlockTime(*tip_height) : 0;
int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg());
file.seekg(0, file.beg);
@@ -578,8 +591,10 @@ UniValue importwallet(const JSONRPCRequest& request)
// Use uiInterface.ShowProgress instead of pwallet.ShowProgress because pwallet.ShowProgress has a cancel button tied to AbortRescan which
// we don't want for this progress bar showing the import progress. uiInterface.ShowProgress does not have a cancel button.
uiInterface.ShowProgress(strprintf("%s " + _("Importing..."), pwallet->GetDisplayName()), 0, false); // show progress dialog in GUI
+ std::vector<std::tuple<CKey, int64_t, bool, std::string>> keys;
+ std::vector<std::pair<CScript, int64_t>> scripts;
while (file.good()) {
- uiInterface.ShowProgress("", std::max(1, std::min(99, (int)(((double)file.tellg() / (double)nFilesize) * 100))), false);
+ uiInterface.ShowProgress("", std::max(1, std::min(50, (int)(((double)file.tellg() / (double)nFilesize) * 100))), false);
std::string line;
std::getline(file, line);
if (line.empty() || line[0] == '#')
@@ -591,13 +606,6 @@ UniValue importwallet(const JSONRPCRequest& request)
continue;
CKey key = DecodeSecret(vstr[0]);
if (key.IsValid()) {
- CPubKey pubkey = key.GetPubKey();
- assert(key.VerifyPubKey(pubkey));
- CKeyID keyid = pubkey.GetID();
- if (pwallet->HaveKey(keyid)) {
- pwallet->WalletLogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid));
- continue;
- }
int64_t nTime = DecodeDumpTime(vstr[1]);
std::string strLabel;
bool fLabel = true;
@@ -613,36 +621,67 @@ UniValue importwallet(const JSONRPCRequest& request)
fLabel = true;
}
}
- pwallet->WalletLogPrintf("Importing %s...\n", EncodeDestination(keyid));
- if (!pwallet->AddKeyPubKey(key, pubkey)) {
- fGood = false;
- continue;
- }
- pwallet->mapKeyMetadata[keyid].nCreateTime = nTime;
- if (fLabel)
- pwallet->SetAddressBook(keyid, strLabel, "receive");
- nTimeBegin = std::min(nTimeBegin, nTime);
+ keys.push_back(std::make_tuple(key, nTime, fLabel, strLabel));
} else if(IsHex(vstr[0])) {
- std::vector<unsigned char> vData(ParseHex(vstr[0]));
- CScript script = CScript(vData.begin(), vData.end());
- CScriptID id(script);
- if (pwallet->HaveCScript(id)) {
- pwallet->WalletLogPrintf("Skipping import of %s (script already present)\n", vstr[0]);
- continue;
- }
- if(!pwallet->AddCScript(script)) {
- pwallet->WalletLogPrintf("Error importing script %s\n", vstr[0]);
- fGood = false;
- continue;
- }
- int64_t birth_time = DecodeDumpTime(vstr[1]);
- if (birth_time > 0) {
- pwallet->m_script_metadata[id].nCreateTime = birth_time;
- nTimeBegin = std::min(nTimeBegin, birth_time);
- }
+ std::vector<unsigned char> vData(ParseHex(vstr[0]));
+ CScript script = CScript(vData.begin(), vData.end());
+ int64_t birth_time = DecodeDumpTime(vstr[1]);
+ scripts.push_back(std::pair<CScript, int64_t>(script, birth_time));
}
}
file.close();
+ // We now know whether we are importing private keys, so we can error if private keys are disabled
+ if (keys.size() > 0 && pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
+ uiInterface.ShowProgress("", 100, false); // hide progress dialog in GUI
+ throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled when private keys are disabled");
+ }
+ double total = (double)(keys.size() + scripts.size());
+ double progress = 0;
+ for (const auto& key_tuple : keys) {
+ uiInterface.ShowProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false);
+ const CKey& key = std::get<0>(key_tuple);
+ int64_t time = std::get<1>(key_tuple);
+ bool has_label = std::get<2>(key_tuple);
+ std::string label = std::get<3>(key_tuple);
+
+ CPubKey pubkey = key.GetPubKey();
+ assert(key.VerifyPubKey(pubkey));
+ CKeyID keyid = pubkey.GetID();
+ if (pwallet->HaveKey(keyid)) {
+ pwallet->WalletLogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid));
+ continue;
+ }
+ pwallet->WalletLogPrintf("Importing %s...\n", EncodeDestination(keyid));
+ if (!pwallet->AddKeyPubKey(key, pubkey)) {
+ fGood = false;
+ continue;
+ }
+ pwallet->mapKeyMetadata[keyid].nCreateTime = time;
+ if (has_label)
+ pwallet->SetAddressBook(keyid, label, "receive");
+ nTimeBegin = std::min(nTimeBegin, time);
+ progress++;
+ }
+ for (const auto& script_pair : scripts) {
+ uiInterface.ShowProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false);
+ const CScript& script = script_pair.first;
+ int64_t time = script_pair.second;
+ CScriptID id(script);
+ if (pwallet->HaveCScript(id)) {
+ pwallet->WalletLogPrintf("Skipping import of %s (script already present)\n", HexStr(script));
+ continue;
+ }
+ if(!pwallet->AddCScript(script)) {
+ pwallet->WalletLogPrintf("Error importing script %s\n", HexStr(script));
+ fGood = false;
+ continue;
+ }
+ if (time > 0) {
+ pwallet->m_script_metadata[id].nCreateTime = time;
+ nTimeBegin = std::min(nTimeBegin, time);
+ }
+ progress++;
+ }
uiInterface.ShowProgress("", 100, false); // hide progress dialog in GUI
pwallet->UpdateTimeFirstKey(nTimeBegin);
}
@@ -671,15 +710,16 @@ UniValue dumpprivkey(const JSONRPCRequest& request)
"Then the importprivkey can be used with this output\n",
{
{"address", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The bitcoin address for the private key"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"\"key\" (string) The private key\n"
- "\nExamples:\n"
- + HelpExampleCli("dumpprivkey", "\"myaddress\"")
+ },
+ RPCExamples{
+ HelpExampleCli("dumpprivkey", "\"myaddress\"")
+ HelpExampleCli("importprivkey", "\"mykey\"")
+ HelpExampleRpc("dumpprivkey", "\"myaddress\"")
- );
+ },
+ }.ToString());
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
@@ -720,16 +760,17 @@ UniValue dumpwallet(const JSONRPCRequest& request)
"only backing up the seed itself, and must be backed up too (e.g. ensure you back up the whole dumpfile).\n",
{
{"filename", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The filename with path (either absolute or relative to bitcoind)"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{ (json object)\n"
" \"filename\" : { (string) The filename with full absolute path\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("dumpwallet", "\"test\"")
+ },
+ RPCExamples{
+ HelpExampleCli("dumpwallet", "\"test\"")
+ HelpExampleRpc("dumpwallet", "\"test\"")
- );
+ },
+ }.ToString());
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
@@ -773,8 +814,9 @@ UniValue dumpwallet(const JSONRPCRequest& request)
// produce output
file << strprintf("# Wallet dump created by Bitcoin %s\n", CLIENT_BUILD);
file << strprintf("# * Created on %s\n", FormatISO8601DateTime(GetTime()));
- file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString());
- file << strprintf("# mined on %s\n", FormatISO8601DateTime(chainActive.Tip()->GetBlockTime()));
+ const Optional<int> tip_height = locked_chain->getHeight();
+ file << strprintf("# * Best block at time of backup was %i (%s),\n", tip_height.get_value_or(-1), tip_height ? locked_chain->getBlockHash(*tip_height).ToString() : "(missing block hash)");
+ file << strprintf("# mined on %s\n", tip_height ? FormatISO8601DateTime(locked_chain->getBlockTime(*tip_height)) : "(missing block time)");
file << "\n";
// add the base58check encoded extended master if the wallet uses HD
@@ -849,9 +891,9 @@ struct ImportData
enum class ScriptContext
{
- TOP, //! Top-level scriptPubKey
- P2SH, //! P2SH redeemScript
- WITNESS_V0, //! P2WSH witnessScript
+ TOP, //!< Top-level scriptPubKey
+ P2SH, //!< P2SH redeemScript
+ WITNESS_V0, //!< P2WSH witnessScript
};
// Analyse the provided scriptPubKey, determining which keys and which redeem scripts from the ImportData struct are needed to spend it, and mark them as used.
@@ -923,154 +965,273 @@ static std::string RecurseImportData(const CScript& script, ImportData& import_d
}
}
-static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
+static UniValue ProcessImportLegacy(ImportData& import_data, std::map<CKeyID, CPubKey>& pubkey_map, std::map<CKeyID, CKey>& privkey_map, std::set<CScript>& script_pub_keys, bool& have_solving_data, const UniValue& data)
{
UniValue warnings(UniValue::VARR);
- UniValue result(UniValue::VOBJ);
- try {
- // First ensure scriptPubKey has either a script or JSON with "address" string
- const UniValue& scriptPubKey = data["scriptPubKey"];
- bool isScript = scriptPubKey.getType() == UniValue::VSTR;
- if (!isScript && !(scriptPubKey.getType() == UniValue::VOBJ && scriptPubKey.exists("address"))) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "scriptPubKey must be string with script or JSON with address string");
+ // First ensure scriptPubKey has either a script or JSON with "address" string
+ const UniValue& scriptPubKey = data["scriptPubKey"];
+ bool isScript = scriptPubKey.getType() == UniValue::VSTR;
+ if (!isScript && !(scriptPubKey.getType() == UniValue::VOBJ && scriptPubKey.exists("address"))) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "scriptPubKey must be string with script or JSON with address string");
+ }
+ const std::string& output = isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str();
+
+ // Optional fields.
+ const std::string& strRedeemScript = data.exists("redeemscript") ? data["redeemscript"].get_str() : "";
+ const std::string& witness_script_hex = data.exists("witnessscript") ? data["witnessscript"].get_str() : "";
+ const UniValue& pubKeys = data.exists("pubkeys") ? data["pubkeys"].get_array() : UniValue();
+ const UniValue& keys = data.exists("keys") ? data["keys"].get_array() : UniValue();
+ const bool internal = data.exists("internal") ? data["internal"].get_bool() : false;
+ const bool watchOnly = data.exists("watchonly") ? data["watchonly"].get_bool() : false;
+
+ if (data.exists("range")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should not be specified for a non-descriptor import");
+ }
+
+ // Generate the script and destination for the scriptPubKey provided
+ CScript script;
+ if (!isScript) {
+ CTxDestination dest = DecodeDestination(output);
+ if (!IsValidDestination(dest)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address \"" + output + "\"");
+ }
+ script = GetScriptForDestination(dest);
+ } else {
+ if (!IsHex(output)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid scriptPubKey \"" + output + "\"");
+ }
+ std::vector<unsigned char> vData(ParseHex(output));
+ script = CScript(vData.begin(), vData.end());
+ CTxDestination dest;
+ if (!ExtractDestination(script, dest) && !internal) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal must be set to true for nonstandard scriptPubKey imports.");
}
- const std::string& output = isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str();
+ }
+ script_pub_keys.emplace(script);
- // Optional fields.
- const std::string& strRedeemScript = data.exists("redeemscript") ? data["redeemscript"].get_str() : "";
- const std::string& witness_script_hex = data.exists("witnessscript") ? data["witnessscript"].get_str() : "";
- const UniValue& pubKeys = data.exists("pubkeys") ? data["pubkeys"].get_array() : UniValue();
- const UniValue& keys = data.exists("keys") ? data["keys"].get_array() : UniValue();
- const bool internal = data.exists("internal") ? data["internal"].get_bool() : false;
- const bool watchOnly = data.exists("watchonly") ? data["watchonly"].get_bool() : false;
- const std::string& label = data.exists("label") ? data["label"].get_str() : "";
+ // Parse all arguments
+ if (strRedeemScript.size()) {
+ if (!IsHex(strRedeemScript)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid redeem script \"" + strRedeemScript + "\": must be hex string");
+ }
+ auto parsed_redeemscript = ParseHex(strRedeemScript);
+ import_data.redeemscript = MakeUnique<CScript>(parsed_redeemscript.begin(), parsed_redeemscript.end());
+ }
+ if (witness_script_hex.size()) {
+ if (!IsHex(witness_script_hex)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid witness script \"" + witness_script_hex + "\": must be hex string");
+ }
+ auto parsed_witnessscript = ParseHex(witness_script_hex);
+ import_data.witnessscript = MakeUnique<CScript>(parsed_witnessscript.begin(), parsed_witnessscript.end());
+ }
+ for (size_t i = 0; i < pubKeys.size(); ++i) {
+ const auto& str = pubKeys[i].get_str();
+ if (!IsHex(str)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey \"" + str + "\" must be a hex string");
+ }
+ auto parsed_pubkey = ParseHex(str);
+ CPubKey pubkey(parsed_pubkey.begin(), parsed_pubkey.end());
+ if (!pubkey.IsFullyValid()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey \"" + str + "\" is not a valid public key");
+ }
+ pubkey_map.emplace(pubkey.GetID(), pubkey);
+ }
+ for (size_t i = 0; i < keys.size(); ++i) {
+ const auto& str = keys[i].get_str();
+ CKey key = DecodeSecret(str);
+ if (!key.IsValid()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
+ }
+ CPubKey pubkey = key.GetPubKey();
+ CKeyID id = pubkey.GetID();
+ if (pubkey_map.count(id)) {
+ pubkey_map.erase(id);
+ }
+ privkey_map.emplace(id, key);
+ }
- // Generate the script and destination for the scriptPubKey provided
- CScript script;
- CTxDestination dest;
- if (!isScript) {
- dest = DecodeDestination(output);
- if (!IsValidDestination(dest)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address \"" + output + "\"");
+
+ // Verify and process input data
+ have_solving_data = import_data.redeemscript || import_data.witnessscript || pubkey_map.size() || privkey_map.size();
+ if (have_solving_data) {
+ // Match up data in import_data with the scriptPubKey in script.
+ auto error = RecurseImportData(script, import_data, ScriptContext::TOP);
+
+ // Verify whether the watchonly option corresponds to the availability of private keys.
+ bool spendable = std::all_of(import_data.used_keys.begin(), import_data.used_keys.end(), [&](const std::pair<CKeyID, bool>& used_key){ return privkey_map.count(used_key.first) > 0; });
+ if (!watchOnly && !spendable) {
+ warnings.push_back("Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.");
+ }
+ if (watchOnly && spendable) {
+ warnings.push_back("All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag.");
+ }
+
+ // Check that all required keys for solvability are provided.
+ if (error.empty()) {
+ for (const auto& require_key : import_data.used_keys) {
+ if (!require_key.second) continue; // Not a required key
+ if (pubkey_map.count(require_key.first) == 0 && privkey_map.count(require_key.first) == 0) {
+ error = "some required keys are missing";
+ }
}
- script = GetScriptForDestination(dest);
+ }
+
+ if (!error.empty()) {
+ warnings.push_back("Importing as non-solvable: " + error + ". If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.");
+ import_data = ImportData();
+ pubkey_map.clear();
+ privkey_map.clear();
+ have_solving_data = false;
} else {
- if (!IsHex(output)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid scriptPubKey \"" + output + "\"");
+ // RecurseImportData() removes any relevant redeemscript/witnessscript from import_data, so we can use that to discover if a superfluous one was provided.
+ if (import_data.redeemscript) warnings.push_back("Ignoring redeemscript as this is not a P2SH script.");
+ if (import_data.witnessscript) warnings.push_back("Ignoring witnessscript as this is not a (P2SH-)P2WSH script.");
+ for (auto it = privkey_map.begin(); it != privkey_map.end(); ) {
+ auto oldit = it++;
+ if (import_data.used_keys.count(oldit->first) == 0) {
+ warnings.push_back("Ignoring irrelevant private key.");
+ privkey_map.erase(oldit);
+ }
}
- std::vector<unsigned char> vData(ParseHex(output));
- script = CScript(vData.begin(), vData.end());
- if (!ExtractDestination(script, dest) && !internal) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal must be set to true for nonstandard scriptPubKey imports.");
+ for (auto it = pubkey_map.begin(); it != pubkey_map.end(); ) {
+ auto oldit = it++;
+ auto key_data_it = import_data.used_keys.find(oldit->first);
+ if (key_data_it == import_data.used_keys.end() || !key_data_it->second) {
+ warnings.push_back("Ignoring public key \"" + HexStr(oldit->first) + "\" as it doesn't appear inside P2PKH or P2WPKH.");
+ pubkey_map.erase(oldit);
+ }
}
}
+ }
- // Parse all arguments
- ImportData import_data;
- if (strRedeemScript.size()) {
- if (!IsHex(strRedeemScript)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid redeem script \"" + strRedeemScript + "\": must be hex string");
- }
- auto parsed_redeemscript = ParseHex(strRedeemScript);
- import_data.redeemscript = MakeUnique<CScript>(parsed_redeemscript.begin(), parsed_redeemscript.end());
+ return warnings;
+}
+
+static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID, CPubKey>& pubkey_map, std::map<CKeyID, CKey>& privkey_map, std::set<CScript>& script_pub_keys, bool& have_solving_data, const UniValue& data)
+{
+ UniValue warnings(UniValue::VARR);
+
+ const std::string& descriptor = data["desc"].get_str();
+ FlatSigningProvider keys;
+ auto parsed_desc = Parse(descriptor, keys);
+ if (!parsed_desc) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Descriptor is invalid");
+ }
+
+ have_solving_data = parsed_desc->IsSolvable();
+ const bool watch_only = data.exists("watchonly") ? data["watchonly"].get_bool() : false;
+
+ int64_t range_start = 0, range_end = 0;
+ if (!parsed_desc->IsRange() && data.exists("range")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should not be specified for an un-ranged descriptor");
+ } else if (parsed_desc->IsRange()) {
+ if (!data.exists("range")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor is ranged, please specify the range");
}
- if (witness_script_hex.size()) {
- if (!IsHex(witness_script_hex)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid witness script \"" + witness_script_hex + "\": must be hex string");
- }
- auto parsed_witnessscript = ParseHex(witness_script_hex);
- import_data.witnessscript = MakeUnique<CScript>(parsed_witnessscript.begin(), parsed_witnessscript.end());
+ const UniValue& range = data["range"];
+ range_start = range.exists("start") ? range["start"].get_int64() : 0;
+ if (!range.exists("end")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "End of range for descriptor must be specified");
}
- std::map<CKeyID, CPubKey> pubkey_map;
- for (size_t i = 0; i < pubKeys.size(); ++i) {
- const auto& str = pubKeys[i].get_str();
- if (!IsHex(str)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey \"" + str + "\" must be a hex string");
- }
- auto parsed_pubkey = ParseHex(str);
- CPubKey pubkey(parsed_pubkey.begin(), parsed_pubkey.end());
- if (!pubkey.IsFullyValid()) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey \"" + str + "\" is not a valid public key");
- }
- pubkey_map.emplace(pubkey.GetID(), pubkey);
+ range_end = range["end"].get_int64();
+ if (range_end < range_start || range_start < 0) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid descriptor range specified");
}
- std::map<CKeyID, CKey> privkey_map;
- for (size_t i = 0; i < keys.size(); ++i) {
- const auto& str = keys[i].get_str();
- CKey key = DecodeSecret(str);
- if (!key.IsValid()) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
- }
- CPubKey pubkey = key.GetPubKey();
- CKeyID id = pubkey.GetID();
- if (pubkey_map.count(id)) {
- pubkey_map.erase(id);
- }
+ }
+
+ const UniValue& priv_keys = data.exists("keys") ? data["keys"].get_array() : UniValue();
+
+ FlatSigningProvider out_keys;
+
+ // Expand all descriptors to get public keys and scripts.
+ // TODO: get private keys from descriptors too
+ for (int i = range_start; i <= range_end; ++i) {
+ std::vector<CScript> scripts_temp;
+ parsed_desc->Expand(i, keys, scripts_temp, out_keys);
+ std::copy(scripts_temp.begin(), scripts_temp.end(), std::inserter(script_pub_keys, script_pub_keys.end()));
+ }
+
+ for (const auto& x : out_keys.scripts) {
+ import_data.import_scripts.emplace(x.second);
+ }
+
+ std::copy(out_keys.pubkeys.begin(), out_keys.pubkeys.end(), std::inserter(pubkey_map, pubkey_map.end()));
+
+ for (size_t i = 0; i < priv_keys.size(); ++i) {
+ const auto& str = priv_keys[i].get_str();
+ CKey key = DecodeSecret(str);
+ if (!key.IsValid()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
+ }
+ CPubKey pubkey = key.GetPubKey();
+ CKeyID id = pubkey.GetID();
+
+ // Check if this private key corresponds to a public key from the descriptor
+ if (!pubkey_map.count(id)) {
+ warnings.push_back("Ignoring irrelevant private key.");
+ } else {
privkey_map.emplace(id, key);
}
+ }
+ // Check if all the public keys have corresponding private keys in the import for spendability.
+ // This does not take into account threshold multisigs which could be spendable without all keys.
+ // Thus, threshold multisigs without all keys will be considered not spendable here, even if they are,
+ // perhaps triggering a false warning message. This is consistent with the current wallet IsMine check.
+ bool spendable = std::all_of(pubkey_map.begin(), pubkey_map.end(),
+ [&](const std::pair<CKeyID, CPubKey>& used_key) {
+ return privkey_map.count(used_key.first) > 0;
+ });
+ if (!watch_only && !spendable) {
+ warnings.push_back("Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.");
+ }
+ if (watch_only && spendable) {
+ warnings.push_back("All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag.");
+ }
+
+ return warnings;
+}
+
+static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
+{
+ UniValue warnings(UniValue::VARR);
+ UniValue result(UniValue::VOBJ);
+
+ try {
+ const bool internal = data.exists("internal") ? data["internal"].get_bool() : false;
// Internal addresses should not have a label
if (internal && data.exists("label")) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal addresses should not have a label");
}
+ const std::string& label = data.exists("label") ? data["label"].get_str() : "";
- // Verify and process input data
- bool have_solving_data = import_data.redeemscript || import_data.witnessscript || pubkey_map.size() || privkey_map.size();
- if (have_solving_data) {
- // Match up data in import_data with the scriptPubKey in script.
- auto error = RecurseImportData(script, import_data, ScriptContext::TOP);
-
- // Verify whether the watchonly option corresponds to the availability of private keys.
- bool spendable = std::all_of(import_data.used_keys.begin(), import_data.used_keys.end(), [&](const std::pair<CKeyID, bool>& used_key){ return privkey_map.count(used_key.first) > 0; });
- if (!watchOnly && !spendable) {
- warnings.push_back("Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.");
- }
- if (watchOnly && spendable) {
- warnings.push_back("All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag.");
- }
-
- // Check that all required keys for solvability are provided.
- if (error.empty()) {
- for (const auto& require_key : import_data.used_keys) {
- if (!require_key.second) continue; // Not a required key
- if (pubkey_map.count(require_key.first) == 0 && privkey_map.count(require_key.first) == 0) {
- error = "some required keys are missing";
- }
- }
- }
+ ImportData import_data;
+ std::map<CKeyID, CPubKey> pubkey_map;
+ std::map<CKeyID, CKey> privkey_map;
+ std::set<CScript> script_pub_keys;
+ bool have_solving_data;
+
+ if (data.exists("scriptPubKey") && data.exists("desc")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Both a descriptor and a scriptPubKey should not be provided.");
+ } else if (data.exists("scriptPubKey")) {
+ warnings = ProcessImportLegacy(import_data, pubkey_map, privkey_map, script_pub_keys, have_solving_data, data);
+ } else if (data.exists("desc")) {
+ warnings = ProcessImportDescriptor(import_data, pubkey_map, privkey_map, script_pub_keys, have_solving_data, data);
+ } else {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Either a descriptor or scriptPubKey must be provided.");
+ }
- if (!error.empty()) {
- warnings.push_back("Importing as non-solvable: " + error + ". If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.");
- import_data = ImportData();
- pubkey_map.clear();
- privkey_map.clear();
- have_solving_data = false;
- } else {
- // RecurseImportData() removes any relevant redeemscript/witnessscript from import_data, so we can use that to discover if a superfluous one was provided.
- if (import_data.redeemscript) warnings.push_back("Ignoring redeemscript as this is not a P2SH script.");
- if (import_data.witnessscript) warnings.push_back("Ignoring witnessscript as this is not a (P2SH-)P2WSH script.");
- for (auto it = privkey_map.begin(); it != privkey_map.end(); ) {
- auto oldit = it++;
- if (import_data.used_keys.count(oldit->first) == 0) {
- warnings.push_back("Ignoring irrelevant private key.");
- privkey_map.erase(oldit);
- }
- }
- for (auto it = pubkey_map.begin(); it != pubkey_map.end(); ) {
- auto oldit = it++;
- auto key_data_it = import_data.used_keys.find(oldit->first);
- if (key_data_it == import_data.used_keys.end() || !key_data_it->second) {
- warnings.push_back("Ignoring public key \"" + HexStr(oldit->first) + "\" as it doesn't appear inside P2PKH or P2WPKH.");
- pubkey_map.erase(oldit);
- }
- }
- }
+ // If private keys are disabled, abort if private keys are being imported
+ if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !privkey_map.empty()) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled");
}
// Check whether we have any work to do
- if (::IsMine(*pwallet, script) & ISMINE_SPENDABLE) {
- throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
+ for (const CScript& script : script_pub_keys) {
+ if (::IsMine(*pwallet, script) & ISMINE_SPENDABLE) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script (\"" + HexStr(script.begin(), script.end()) + "\")");
+ }
}
// All good, time to import
@@ -1100,14 +1261,18 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
}
}
- if (!have_solving_data || !::IsMine(*pwallet, script)) { // Always call AddWatchOnly for non-solvable watch-only, so that watch timestamp gets updated
- if (!pwallet->AddWatchOnly(script, timestamp)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
+
+ for (const CScript& script : script_pub_keys) {
+ if (!have_solving_data || !::IsMine(*pwallet, script)) { // Always call AddWatchOnly for non-solvable watch-only, so that watch timestamp gets updated
+ if (!pwallet->AddWatchOnly(script, timestamp)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
+ }
+ }
+ CTxDestination dest;
+ ExtractDestination(script, dest);
+ if (!internal && IsValidDestination(dest)) {
+ pwallet->SetAddressBook(dest, label, "receive");
}
- }
- if (!internal) {
- assert(IsValidDestination(dest));
- pwallet->SetAddressBook(dest, label, "receive");
}
result.pushKV("success", UniValue(true));
@@ -1150,13 +1315,16 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
RPCHelpMan{"importmulti",
"\nImport addresses/scripts (with private or public keys, redeem script (P2SH)), optionally rescanning the blockchain from the earliest creation time of the imported scripts. Requires a new wallet backup.\n"
"If an address/script is imported without all of the private keys required to spend from that address, it will be watchonly. The 'watchonly' option must be set to true in this case or a warning will be returned.\n"
- "Conversely, if all the private keys are provided and the address/script is spendable, the watchonly option must be set to false, or a warning will be returned.\n",
+ "Conversely, if all the private keys are provided and the address/script is spendable, the watchonly option must be set to false, or a warning will be returned.\n"
+ "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
+ "may report that the imported keys, addresses or scripts exists but related transactions are still missing.\n",
{
{"requests", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "Data to be imported",
{
{"", RPCArg::Type::OBJ, /* opt */ false, /* default_val */ "", "",
{
- {"scriptPubKey", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "Type of scriptPubKey (string for script, json for address)",
+ {"desc", RPCArg::Type::STR, /* opt */ true, /* default_val */ "", "Descriptor to import. If using descriptor, do not also provide address/scriptPubKey, scripts, or pubkeys"},
+ {"scriptPubKey", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "Type of scriptPubKey (string for script, json for address). Should not be provided if using a descriptor",
/* oneline_description */ "", {"\"<script>\" | { \"address\":\"<address>\" }", "string / json"}
},
{"timestamp", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "Creation time of the key in seconds since epoch (Jan 1 1970 GMT),\n"
@@ -1179,6 +1347,12 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
{"key", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", ""},
}
},
+ {"range", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "", "If a ranged descriptor is used, this specifies the start and end of the range to import",
+ {
+ {"start", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Start of the range to import"},
+ {"end", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "End of the range to import (inclusive)"},
+ }
+ },
{"internal", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Stating whether matching outputs should be treated as not incoming payments (also known as change)"},
{"watchonly", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Stating whether matching outputs should be considered watchonly."},
{"label", RPCArg::Type::STR, /* opt */ true, /* default_val */ "''", "Label to assign to the address, only allowed with internal=false"},
@@ -1191,17 +1365,18 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
{"rescan", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "Stating if should rescan the blockchain after all imports"},
},
"\"options\""},
- }}
- .ToString() +
- "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
- "may report that the imported keys, addresses or scripts exists but related transactions are still missing.\n"
- "\nExamples:\n" +
- HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }, "
- "{ \"scriptPubKey\": { \"address\": \"<my 2nd address>\" }, \"label\": \"example 2\", \"timestamp\": 1455191480 }]'") +
- HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }]' '{ \"rescan\": false}'") +
-
+ },
+ RPCResult{
"\nResponse is an array with the same size as the input that has the execution result :\n"
- " [{\"success\": true}, {\"success\": true, \"warnings\": [\"Ignoring irrelevant private key\"]}, {\"success\": false, \"error\": {\"code\": -1, \"message\": \"Internal Server Error\"}}, ...]\n");
+ " [{\"success\": true}, {\"success\": true, \"warnings\": [\"Ignoring irrelevant private key\"]}, {\"success\": false, \"error\": {\"code\": -1, \"message\": \"Internal Server Error\"}}, ...]\n"
+ },
+ RPCExamples{
+ HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }, "
+ "{ \"scriptPubKey\": { \"address\": \"<my 2nd address>\" }, \"label\": \"example 2\", \"timestamp\": 1455191480 }]'") +
+ HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }]' '{ \"rescan\": false}'")
+ },
+ }.ToString()
+ );
RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ});
@@ -1234,15 +1409,16 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
EnsureWalletIsUnlocked(pwallet);
// Verify all timestamps are present before importing any keys.
- now = chainActive.Tip() ? chainActive.Tip()->GetMedianTimePast() : 0;
+ const Optional<int> tip_height = locked_chain->getHeight();
+ now = tip_height ? locked_chain->getBlockMedianTimePast(*tip_height) : 0;
for (const UniValue& data : requests.getValues()) {
GetImportTimestamp(data, now);
}
const int64_t minimumTimestamp = 1;
- if (fRescan && chainActive.Tip()) {
- nLowestTimestamp = chainActive.Tip()->GetBlockTime();
+ if (fRescan && tip_height) {
+ nLowestTimestamp = locked_chain->getBlockTime(*tip_height);
} else {
fRescan = false;
}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 13fe5c3ab0..a9fbed5423 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -102,7 +102,10 @@ static void WalletTxToJSON(interfaces::Chain& chain, interfaces::Chain::Lock& lo
{
entry.pushKV("blockhash", wtx.hashBlock.GetHex());
entry.pushKV("blockindex", wtx.nIndex);
- entry.pushKV("blocktime", LookupBlockIndex(wtx.hashBlock)->GetBlockTime());
+ int64_t block_time;
+ bool found_block = chain.findBlock(wtx.hashBlock, nullptr /* block */, &block_time);
+ assert(found_block);
+ entry.pushKV("blocktime", block_time);
} else {
entry.pushKV("trusted", wtx.IsTrusted(locked_chain));
}
@@ -157,21 +160,28 @@ static UniValue getnewaddress(const JSONRPCRequest& request)
{
{"label", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "The label name for the address to be linked to. If not provided, the default label \"\" is used. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created if there is no label by the given name."},
{"address_type", RPCArg::Type::STR, /* opt */ true, /* default_val */ "set by -addresstype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"\"address\" (string) The new bitcoin address\n"
- "\nExamples:\n"
- + HelpExampleCli("getnewaddress", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getnewaddress", "")
+ HelpExampleRpc("getnewaddress", "")
- );
+ },
+ }.ToString());
+ // Belt and suspenders check for disabled private keys
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
}
LOCK(pwallet->cs_wallet);
+ if (!pwallet->CanGetAddresses()) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error: This wallet has no available keys");
+ }
+
+
// Parse the label first so we don't generate a key if there's an error
std::string label;
if (!request.params[0].isNull())
@@ -217,21 +227,27 @@ static UniValue getrawchangeaddress(const JSONRPCRequest& request)
"This is for use with raw transactions, NOT normal use.\n",
{
{"address_type", RPCArg::Type::STR, /* opt */ true, /* default_val */ "set by -changetype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"\"address\" (string) The address\n"
- "\nExamples:\n"
- + HelpExampleCli("getrawchangeaddress", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getrawchangeaddress", "")
+ HelpExampleRpc("getrawchangeaddress", "")
- );
+ },
+ }.ToString());
+ // Belt and suspenders check for disabled private keys
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
}
LOCK(pwallet->cs_wallet);
+ if (!pwallet->CanGetAddresses(true)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error: This wallet has no available keys");
+ }
+
if (!pwallet->IsLocked()) {
pwallet->TopUpKeyPool();
}
@@ -273,12 +289,13 @@ static UniValue setlabel(const JSONRPCRequest& request)
{
{"address", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The bitcoin address to be associated with a label."},
{"label", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The label to assign to the address."},
- }}
- .ToString() +
- "\nExamples:\n"
- + HelpExampleCli("setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"tabby\"")
+ },
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"tabby\"")
+ HelpExampleRpc("setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"tabby\"")
- );
+ },
+ }.ToString());
LOCK(pwallet->cs_wallet);
@@ -369,16 +386,17 @@ static UniValue sendtoaddress(const JSONRPCRequest& request)
" \"UNSET\"\n"
" \"ECONOMICAL\"\n"
" \"CONSERVATIVE\""},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"\"txid\" (string) The transaction id.\n"
- "\nExamples:\n"
- + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
+ },
+ RPCExamples{
+ HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
+ HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"donation\" \"seans outpost\"")
+ HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"\" \"\" true")
+ HelpExampleRpc("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
- );
+ },
+ }.ToString());
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -446,9 +464,8 @@ static UniValue listaddressgroupings(const JSONRPCRequest& request)
"\nLists groups of addresses which have had their common ownership\n"
"made public by common use as inputs or as the resulting change\n"
"in past transactions\n",
- {}}
- .ToString() +
- "\nResult:\n"
+ {},
+ RPCResult{
"[\n"
" [\n"
" [\n"
@@ -460,10 +477,12 @@ static UniValue listaddressgroupings(const JSONRPCRequest& request)
" ]\n"
" ,...\n"
"]\n"
- "\nExamples:\n"
- + HelpExampleCli("listaddressgroupings", "")
+ },
+ RPCExamples{
+ HelpExampleCli("listaddressgroupings", "")
+ HelpExampleRpc("listaddressgroupings", "")
- );
+ },
+ }.ToString());
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -510,11 +529,11 @@ static UniValue signmessage(const JSONRPCRequest& request)
{
{"address", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The bitcoin address to use for the private key."},
{"message", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The message to create a signature of."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"\"signature\" (string) The signature of the message encoded in base 64\n"
- "\nExamples:\n"
+ },
+ RPCExamples{
"\nUnlock the wallet for 30 seconds\n"
+ HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
"\nCreate the signature\n"
@@ -523,7 +542,8 @@ static UniValue signmessage(const JSONRPCRequest& request)
+ HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"my message\"")
- );
+ },
+ }.ToString());
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
@@ -575,11 +595,11 @@ static UniValue getreceivedbyaddress(const JSONRPCRequest& request)
{
{"address", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The bitcoin address for transactions."},
{"minconf", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1", "Only include transactions confirmed at least this many times."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"amount (numeric) The total amount in " + CURRENCY_UNIT + " received at this address.\n"
- "\nExamples:\n"
+ },
+ RPCExamples{
"\nThe amount from transactions with at least 1 confirmation\n"
+ HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\"") +
"\nThe amount including unconfirmed transactions, zero confirmations\n"
@@ -588,7 +608,8 @@ static UniValue getreceivedbyaddress(const JSONRPCRequest& request)
+ HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" 6") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", 6")
- );
+ },
+ }.ToString());
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -646,11 +667,11 @@ static UniValue getreceivedbylabel(const JSONRPCRequest& request)
{
{"label", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The selected label, may be the default label using \"\"."},
{"minconf", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1", "Only include transactions confirmed at least this many times."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this label.\n"
- "\nExamples:\n"
+ },
+ RPCExamples{
"\nAmount received by the default label with at least 1 confirmation\n"
+ HelpExampleCli("getreceivedbylabel", "\"\"") +
"\nAmount received at the tabby label including unconfirmed amounts with zero confirmations\n"
@@ -659,7 +680,8 @@ static UniValue getreceivedbylabel(const JSONRPCRequest& request)
+ HelpExampleCli("getreceivedbylabel", "\"tabby\" 6") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("getreceivedbylabel", "\"tabby\", 6")
- );
+ },
+ }.ToString());
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -718,18 +740,19 @@ static UniValue getbalance(const JSONRPCRequest& request)
{"dummy", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "Remains for backward compatibility. Must be excluded or set to \"*\"."},
{"minconf", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Only include transactions confirmed at least this many times."},
{"include_watchonly", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Also include balance in watch-only addresses (see 'importaddress')"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this wallet.\n"
- "\nExamples:\n"
+ },
+ RPCExamples{
"\nThe total amount in the wallet with 1 or more confirmations\n"
+ HelpExampleCli("getbalance", "") +
"\nThe total amount in the wallet at least 6 blocks confirmed\n"
+ HelpExampleCli("getbalance", "\"*\" 6") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("getbalance", "\"*\", 6")
- );
+ },
+ }.ToString());
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -768,8 +791,11 @@ static UniValue getunconfirmedbalance(const JSONRPCRequest &request)
if (request.fHelp || request.params.size() > 0)
throw std::runtime_error(
RPCHelpMan{"getunconfirmedbalance",
- "Returns the server's total unconfirmed balance\n", {}}
- .ToString());
+ "Returns the server's total unconfirmed balance\n",
+ {},
+ RPCResults{},
+ RPCExamples{""},
+ }.ToString());
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -819,12 +845,12 @@ static UniValue sendmany(const JSONRPCRequest& request)
" \"UNSET\"\n"
" \"ECONOMICAL\"\n"
" \"CONSERVATIVE\""},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"\"txid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
" the number of addresses.\n"
- "\nExamples:\n"
+ },
+ RPCExamples{
"\nSend two amounts to two different addresses:\n"
+ HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") +
"\nSend two amounts to two different addresses setting the confirmation and comment:\n"
@@ -833,7 +859,8 @@ static UniValue sendmany(const JSONRPCRequest& request)
+ HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 1 \"\" \"[\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\",\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("sendmany", "\"\", {\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\":0.01,\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\":0.02}, 6, \"testing\"")
- );
+ },
+ }.ToString());
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -964,19 +991,20 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request)
},
{"label", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "A label to assign the addresses to."},
{"address_type", RPCArg::Type::STR, /* opt */ true, /* default_val */ "set by -addresstype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{\n"
" \"address\":\"multisigaddress\", (string) The value of the new multisig address.\n"
" \"redeemScript\":\"script\" (string) The string value of the hex-encoded redemption script.\n"
"}\n"
- "\nExamples:\n"
+ },
+ RPCExamples{
"\nAdd a multisig address from 2 addresses\n"
+ HelpExampleCli("addmultisigaddress", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("addmultisigaddress", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
- ;
+ },
+ }.ToString();
throw std::runtime_error(msg);
}
@@ -1193,9 +1221,8 @@ static UniValue listreceivedbyaddress(const JSONRPCRequest& request)
{"include_empty", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Whether to include addresses that haven't received any payments."},
{"include_watchonly", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Whether to include watch-only addresses (see 'importaddress')."},
{"address_filter", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "If present, only return information on this address."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"[\n"
" {\n"
" \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
@@ -1210,13 +1237,14 @@ static UniValue listreceivedbyaddress(const JSONRPCRequest& request)
" }\n"
" ,...\n"
"]\n"
-
- "\nExamples:\n"
- + HelpExampleCli("listreceivedbyaddress", "")
+ },
+ RPCExamples{
+ HelpExampleCli("listreceivedbyaddress", "")
+ HelpExampleCli("listreceivedbyaddress", "6 true")
+ HelpExampleRpc("listreceivedbyaddress", "6, true, true")
+ HelpExampleRpc("listreceivedbyaddress", "6, true, true, \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\"")
- );
+ },
+ }.ToString());
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -1245,9 +1273,8 @@ static UniValue listreceivedbylabel(const JSONRPCRequest& request)
{"minconf", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1", "The minimum number of confirmations before payments are included."},
{"include_empty", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Whether to include labels that haven't received any payments."},
{"include_watchonly", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Whether to include watch-only addresses (see 'importaddress')."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"[\n"
" {\n"
" \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
@@ -1257,12 +1284,13 @@ static UniValue listreceivedbylabel(const JSONRPCRequest& request)
" }\n"
" ,...\n"
"]\n"
-
- "\nExamples:\n"
- + HelpExampleCli("listreceivedbylabel", "")
+ },
+ RPCExamples{
+ HelpExampleCli("listreceivedbylabel", "")
+ HelpExampleCli("listreceivedbylabel", "6 true")
+ HelpExampleRpc("listreceivedbylabel", "6, true, true")
- );
+ },
+ }.ToString());
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -1292,7 +1320,7 @@ static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
* @param filter_ismine The "is mine" filter flags.
* @param filter_label Optional label string to filter incoming transactions.
*/
-static void ListTransactions(interfaces::Chain::Lock& locked_chain, CWallet* const pwallet, const CWalletTx& wtx, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter_ismine, const std::string* filter_label)
+static void ListTransactions(interfaces::Chain::Lock& locked_chain, CWallet* const pwallet, const CWalletTx& wtx, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter_ismine, const std::string* filter_label) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
{
CAmount nFee;
std::list<COutputEntry> listReceived;
@@ -1388,9 +1416,8 @@ UniValue listtransactions(const JSONRPCRequest& request)
{"count", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "10", "The number of transactions to return"},
{"skip", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "The number of transactions to skip"},
{"include_watchonly", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Include transactions to watch-only addresses (see 'importaddress')"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"[\n"
" {\n"
" \"address\":\"address\", (string) The bitcoin address of the transaction.\n"
@@ -1422,15 +1449,16 @@ UniValue listtransactions(const JSONRPCRequest& request)
" 'send' category of transactions.\n"
" }\n"
"]\n"
-
- "\nExamples:\n"
+ },
+ RPCExamples{
"\nList the most recent 10 transactions in the systems\n"
+ HelpExampleCli("listtransactions", "") +
"\nList transactions 100 to 120\n"
+ HelpExampleCli("listtransactions", "\"*\" 20 100") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("listtransactions", "\"*\", 20, 100")
- );
+ },
+ }.ToString());
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -1523,9 +1551,8 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
{"include_watchonly", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Include transactions to watch-only addresses (see 'importaddress')"},
{"include_removed", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "true", "Show transactions that were removed due to a reorg in the \"removed\" array\n"
" (not guaranteed to work on pruned nodes)"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{\n"
" \"transactions\": [\n"
" \"address\":\"address\", (string) The bitcoin address of the transaction.\n"
@@ -1560,11 +1587,13 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
" ],\n"
" \"lastblock\": \"lastblockhash\" (string) The hash of the block (target_confirmations-1) from the best block on the main chain. This is typically used to feed back into listsinceblock the next time you call it. So you would generally use a target_confirmations of say 6, so you will be continually re-notified of transactions until they've reached 6 confirmations plus any new ones\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("listsinceblock", "")
+ },
+ RPCExamples{
+ HelpExampleCli("listsinceblock", "")
+ HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
+ HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
- );
+ },
+ }.ToString());
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -1573,24 +1602,19 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
- const CBlockIndex* pindex = nullptr; // Block index of the specified block or the common ancestor, if the block provided was in a deactivated chain.
- const CBlockIndex* paltindex = nullptr; // Block index of the specified block, even if it's in a deactivated chain.
+ // The way the 'height' is initialized is just a workaround for the gcc bug #47679 since version 4.6.0.
+ Optional<int> height = MakeOptional(false, int()); // Height of the specified block or the common ancestor, if the block provided was in a deactivated chain.
+ Optional<int> altheight; // Height of the specified block, even if it's in a deactivated chain.
int target_confirms = 1;
isminefilter filter = ISMINE_SPENDABLE;
+ uint256 blockId;
if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
- uint256 blockId(ParseHashV(request.params[0], "blockhash"));
-
- paltindex = pindex = LookupBlockIndex(blockId);
- if (!pindex) {
+ blockId = ParseHashV(request.params[0], "blockhash");
+ height = locked_chain->findFork(blockId, &altheight);
+ if (!height) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
- if (chainActive[pindex->nHeight] != pindex) {
- // the block being asked for is a part of a deactivated chain;
- // we don't want to depend on its perceived height in the block
- // chain, we want to instead use the last common ancestor
- pindex = chainActive.FindFork(pindex);
- }
}
if (!request.params[1].isNull()) {
@@ -1607,7 +1631,8 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
bool include_removed = (request.params[3].isNull() || request.params[3].get_bool());
- int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
+ const Optional<int> tip_height = locked_chain->getHeight();
+ int depth = tip_height && height ? (1 + *tip_height - *height) : -1;
UniValue transactions(UniValue::VARR);
@@ -1622,9 +1647,9 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
// when a reorg'd block is requested, we also list any relevant transactions
// in the blocks of the chain that was detached
UniValue removed(UniValue::VARR);
- while (include_removed && paltindex && paltindex != pindex) {
+ while (include_removed && altheight && *altheight > *height) {
CBlock block;
- if (!ReadBlockFromDisk(block, paltindex, Params().GetConsensus())) {
+ if (!pwallet->chain().findBlock(blockId, &block) || block.IsNull()) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
}
for (const CTransactionRef& tx : block.vtx) {
@@ -1635,11 +1660,12 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
ListTransactions(*locked_chain, pwallet, it->second, -100000000, true, removed, filter, nullptr /* filter_label */);
}
}
- paltindex = paltindex->pprev;
+ blockId = block.hashPrevBlock;
+ --*altheight;
}
- CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
- uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256();
+ int last_height = tip_height ? *tip_height + 1 - target_confirms : -1;
+ uint256 lastblock = last_height >= 0 ? locked_chain->getBlockHash(last_height) : uint256();
UniValue ret(UniValue::VOBJ);
ret.pushKV("transactions", transactions);
@@ -1665,9 +1691,8 @@ static UniValue gettransaction(const JSONRPCRequest& request)
{
{"txid", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The transaction id"},
{"include_watchonly", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Whether to include watch-only addresses in balance calculation and details[]"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{\n"
" \"amount\" : x.xxx, (numeric) The transaction amount in " + CURRENCY_UNIT + "\n"
" \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
@@ -1702,12 +1727,13 @@ static UniValue gettransaction(const JSONRPCRequest& request)
" ],\n"
" \"hex\" : \"data\" (string) Raw data for transaction\n"
"}\n"
-
- "\nExamples:\n"
- + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
+ },
+ RPCExamples{
+ HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
+ HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
+ HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
- );
+ },
+ }.ToString());
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -1770,13 +1796,13 @@ static UniValue abandontransaction(const JSONRPCRequest& request)
"It has no effect on transactions which are already abandoned.\n",
{
{"txid", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The transaction id"},
- }}
- .ToString() +
- "\nResult:\n"
- "\nExamples:\n"
- + HelpExampleCli("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
+ },
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
+ HelpExampleRpc("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
- );
+ },
+ }.ToString());
}
// Make sure the results are valid at least up to the most recent block
@@ -1814,12 +1840,13 @@ static UniValue backupwallet(const JSONRPCRequest& request)
"\nSafely copies current wallet file to destination, which can be a directory or a path with filename.\n",
{
{"destination", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The destination directory or file"},
- }}
- .ToString() +
- "\nExamples:\n"
- + HelpExampleCli("backupwallet", "\"backup.dat\"")
+ },
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("backupwallet", "\"backup.dat\"")
+ HelpExampleRpc("backupwallet", "\"backup.dat\"")
- );
+ },
+ }.ToString());
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -1853,12 +1880,13 @@ static UniValue keypoolrefill(const JSONRPCRequest& request)
HelpRequiringPassphrase(pwallet) + "\n",
{
{"newsize", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "100", "The new keypool size"},
- }}
- .ToString() +
- "\nExamples:\n"
- + HelpExampleCli("keypoolrefill", "")
+ },
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("keypoolrefill", "")
+ HelpExampleRpc("keypoolrefill", "")
- );
+ },
+ }.ToString());
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
@@ -1899,23 +1927,24 @@ static UniValue walletpassphrase(const JSONRPCRequest& request)
throw std::runtime_error(
RPCHelpMan{"walletpassphrase",
"\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
- "This is needed prior to performing transactions related to private keys such as sending bitcoins\n",
+ "This is needed prior to performing transactions related to private keys such as sending bitcoins\n"
+ "\nNote:\n"
+ "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
+ "time that overrides the old one.\n",
{
{"passphrase", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The wallet passphrase"},
{"timeout", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The time to keep the decryption key in seconds; capped at 100000000 (~3 years)."},
- }}
- .ToString() +
- "\nNote:\n"
- "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
- "time that overrides the old one.\n"
- "\nExamples:\n"
+ },
+ RPCResults{},
+ RPCExamples{
"\nUnlock the wallet for 60 seconds\n"
+ HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
"\nLock the wallet again (before 60 seconds)\n"
+ HelpExampleCli("walletlock", "") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
- );
+ },
+ }.ToString());
}
auto locked_chain = pwallet->chain().lock();
@@ -1988,12 +2017,13 @@ static UniValue walletpassphrasechange(const JSONRPCRequest& request)
{
{"oldpassphrase", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The current passphrase"},
{"newpassphrase", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The new passphrase"},
- }}
- .ToString() +
- "\nExamples:\n"
- + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
+ },
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
+ HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
- );
+ },
+ }.ToString());
}
auto locked_chain = pwallet->chain().lock();
@@ -2040,9 +2070,9 @@ static UniValue walletlock(const JSONRPCRequest& request)
"\nRemoves the wallet encryption key from memory, locking the wallet.\n"
"After calling this method, you will need to call walletpassphrase again\n"
"before being able to call any methods which require the wallet to be unlocked.\n",
- {}}
- .ToString() +
- "\nExamples:\n"
+ {},
+ RPCResults{},
+ RPCExamples{
"\nSet the passphrase for 2 minutes to perform a transaction\n"
+ HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
"\nPerform a send (requires passphrase set)\n"
@@ -2051,7 +2081,8 @@ static UniValue walletlock(const JSONRPCRequest& request)
+ HelpExampleCli("walletlock", "") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("walletlock", "")
- );
+ },
+ }.ToString());
}
auto locked_chain = pwallet->chain().lock();
@@ -2087,9 +2118,9 @@ static UniValue encryptwallet(const JSONRPCRequest& request)
"If the wallet is already encrypted, use the walletpassphrasechange call.\n",
{
{"passphrase", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long."},
- }}
- .ToString() +
- "\nExamples:\n"
+ },
+ RPCResults{},
+ RPCExamples{
"\nEncrypt your wallet\n"
+ HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
"\nNow set the passphrase to use the wallet, such as for signing or sending bitcoin\n"
@@ -2100,7 +2131,8 @@ static UniValue encryptwallet(const JSONRPCRequest& request)
+ HelpExampleCli("walletlock", "") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
- );
+ },
+ }.ToString());
}
auto locked_chain = pwallet->chain().lock();
@@ -2158,12 +2190,11 @@ static UniValue lockunspent(const JSONRPCRequest& request)
},
},
},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"true|false (boolean) Whether the command was successful or not\n"
-
- "\nExamples:\n"
+ },
+ RPCExamples{
"\nList the unspent transactions\n"
+ HelpExampleCli("listunspent", "") +
"\nLock an unspent transaction\n"
@@ -2174,7 +2205,8 @@ static UniValue lockunspent(const JSONRPCRequest& request)
+ HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
- );
+ },
+ }.ToString());
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -2270,9 +2302,8 @@ static UniValue listlockunspent(const JSONRPCRequest& request)
RPCHelpMan{"listlockunspent",
"\nReturns list of temporarily unspendable outputs.\n"
"See the lockunspent call to lock and unlock transactions for spending.\n",
- {}}
- .ToString() +
- "\nResult:\n"
+ {},
+ RPCResult{
"[\n"
" {\n"
" \"txid\" : \"transactionid\", (string) The transaction id locked\n"
@@ -2280,7 +2311,8 @@ static UniValue listlockunspent(const JSONRPCRequest& request)
" }\n"
" ,...\n"
"]\n"
- "\nExamples:\n"
+ },
+ RPCExamples{
"\nList the unspent transactions\n"
+ HelpExampleCli("listunspent", "") +
"\nLock an unspent transaction\n"
@@ -2291,7 +2323,8 @@ static UniValue listlockunspent(const JSONRPCRequest& request)
+ HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("listlockunspent", "")
- );
+ },
+ }.ToString());
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
@@ -2327,14 +2360,15 @@ static UniValue settxfee(const JSONRPCRequest& request)
"\nSet the transaction fee per kB for this wallet. Overrides the global -paytxfee command line parameter.\n",
{
{"amount", RPCArg::Type::AMOUNT, /* opt */ false, /* default_val */ "", "The transaction fee in " + CURRENCY_UNIT + "/kB"},
- }}
- .ToString() +
- "\nResult\n"
+ },
+ RPCResult{
"true|false (boolean) Returns true if successful\n"
- "\nExamples:\n"
- + HelpExampleCli("settxfee", "0.00001")
+ },
+ RPCExamples{
+ HelpExampleCli("settxfee", "0.00001")
+ HelpExampleRpc("settxfee", "0.00001")
- );
+ },
+ }.ToString());
}
auto locked_chain = pwallet->chain().lock();
@@ -2366,9 +2400,9 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
RPCHelpMan{"getwalletinfo",
- "Returns an object containing various wallet state info.\n", {}}
- .ToString() +
- "\nResult:\n"
+ "Returns an object containing various wallet state info.\n",
+ {},
+ RPCResult{
"{\n"
" \"walletname\": xxxxx, (string) the wallet name\n"
" \"walletversion\": xxxxx, (numeric) the wallet version\n"
@@ -2385,10 +2419,12 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
" \"hdmasterkeyid\": \"<hash160>\" (string, optional) alias for hdseedid retained for backwards-compatibility. Will be removed in V0.18.\n"
" \"private_keys_enabled\": true|false (boolean) false if privatekeys are disabled for this wallet (enforced watch-only wallet)\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getwalletinfo", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getwalletinfo", "")
+ HelpExampleRpc("getwalletinfo", "")
- );
+ },
+ }.ToString());
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -2429,8 +2465,9 @@ static UniValue listwalletdir(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 0) {
throw std::runtime_error(
RPCHelpMan{"listwalletdir",
- "Returns a list of wallets in the wallet directory.\n", {}}
- .ToString() +
+ "Returns a list of wallets in the wallet directory.\n",
+ {},
+ RPCResult{
"{\n"
" \"wallets\" : [ (json array of objects)\n"
" {\n"
@@ -2439,10 +2476,12 @@ static UniValue listwalletdir(const JSONRPCRequest& request)
" ,...\n"
" ]\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("listwalletdir", "")
+ },
+ RPCExamples{
+ HelpExampleCli("listwalletdir", "")
+ HelpExampleRpc("listwalletdir", "")
- );
+ },
+ }.ToString());
}
UniValue wallets(UniValue::VARR);
@@ -2464,17 +2503,18 @@ static UniValue listwallets(const JSONRPCRequest& request)
RPCHelpMan{"listwallets",
"Returns a list of currently loaded wallets.\n"
"For full information on the wallet, use \"getwalletinfo\"\n",
- {}}
- .ToString() +
- "\nResult:\n"
+ {},
+ RPCResult{
"[ (json array of strings)\n"
" \"walletname\" (string) the wallet name\n"
" ...\n"
"]\n"
- "\nExamples:\n"
- + HelpExampleCli("listwallets", "")
+ },
+ RPCExamples{
+ HelpExampleCli("listwallets", "")
+ HelpExampleRpc("listwallets", "")
- );
+ },
+ }.ToString());
UniValue obj(UniValue::VARR);
@@ -2501,20 +2541,20 @@ static UniValue loadwallet(const JSONRPCRequest& request)
"\napplied to the new wallet (eg -zapwallettxes, upgradewallet, rescan, etc).\n",
{
{"filename", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The wallet directory or .dat file."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{\n"
" \"name\" : <wallet_name>, (string) The wallet name if loaded successfully.\n"
" \"warning\" : <warning>, (string) Warning message if wallet was not loaded cleanly.\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("loadwallet", "\"test.dat\"")
+ },
+ RPCExamples{
+ HelpExampleCli("loadwallet", "\"test.dat\"")
+ HelpExampleRpc("loadwallet", "\"test.dat\"")
- );
+ },
+ }.ToString());
WalletLocation location(request.params[0].get_str());
- std::string error;
if (!location.Exists()) {
throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Wallet " + location.GetName() + " not found.");
@@ -2526,18 +2566,9 @@ static UniValue loadwallet(const JSONRPCRequest& request)
}
}
- std::string warning;
- if (!CWallet::Verify(*g_rpc_interfaces->chain, location, false, error, warning)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Wallet file verification failed: " + error);
- }
-
- std::shared_ptr<CWallet> const wallet = CWallet::CreateWalletFromFile(*g_rpc_interfaces->chain, location);
- if (!wallet) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Wallet loading failed.");
- }
- AddWallet(wallet);
-
- wallet->postInitProcess();
+ std::string error, warning;
+ std::shared_ptr<CWallet> const wallet = LoadWallet(*g_rpc_interfaces->chain, location, error, warning);
+ if (!wallet) throw JSONRPCError(RPC_WALLET_ERROR, error);
UniValue obj(UniValue::VOBJ);
obj.pushKV("name", wallet->GetName());
@@ -2548,31 +2579,37 @@ static UniValue loadwallet(const JSONRPCRequest& request)
static UniValue createwallet(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) {
throw std::runtime_error(
RPCHelpMan{"createwallet",
"\nCreates and loads a new wallet.\n",
{
{"wallet_name", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The name for the new wallet. If this is a path, the wallet will be created at the path location."},
{"disable_private_keys", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Disable the possibility of private keys (only watchonlys are possible in this mode)."},
- }}
- .ToString() +
- "\nResult:\n"
+ {"blank", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."},
+ },
+ RPCResult{
"{\n"
" \"name\" : <wallet_name>, (string) The wallet name if created successfully. If the wallet was created using a full path, the wallet_name will be the full path.\n"
" \"warning\" : <warning>, (string) Warning message if wallet was not loaded cleanly.\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("createwallet", "\"testwallet\"")
+ },
+ RPCExamples{
+ HelpExampleCli("createwallet", "\"testwallet\"")
+ HelpExampleRpc("createwallet", "\"testwallet\"")
- );
+ },
+ }.ToString());
}
std::string error;
std::string warning;
- bool disable_privatekeys = false;
- if (!request.params[1].isNull()) {
- disable_privatekeys = request.params[1].get_bool();
+ uint64_t flags = 0;
+ if (!request.params[1].isNull() && request.params[1].get_bool()) {
+ flags |= WALLET_FLAG_DISABLE_PRIVATE_KEYS;
+ }
+
+ if (!request.params[2].isNull() && request.params[2].get_bool()) {
+ flags |= WALLET_FLAG_BLANK_WALLET;
}
WalletLocation location(request.params[0].get_str());
@@ -2585,7 +2622,7 @@ static UniValue createwallet(const JSONRPCRequest& request)
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet file verification failed: " + error);
}
- std::shared_ptr<CWallet> const wallet = CWallet::CreateWalletFromFile(*g_rpc_interfaces->chain, location, (disable_privatekeys ? (uint64_t)WALLET_FLAG_DISABLE_PRIVATE_KEYS : 0));
+ std::shared_ptr<CWallet> const wallet = CWallet::CreateWalletFromFile(*g_rpc_interfaces->chain, location, flags);
if (!wallet) {
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet creation failed.");
}
@@ -2609,12 +2646,13 @@ static UniValue unloadwallet(const JSONRPCRequest& request)
"Specifying the wallet name on a wallet endpoint is invalid.",
{
{"wallet_name", RPCArg::Type::STR, /* opt */ true, /* default_val */ "the wallet name from the RPC request", "The name of the wallet to unload."},
- }}
- .ToString() +
- "\nExamples:\n"
- + HelpExampleCli("unloadwallet", "wallet_name")
+ },
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("unloadwallet", "wallet_name")
+ HelpExampleRpc("unloadwallet", "wallet_name")
- );
+ },
+ }.ToString());
}
std::string wallet_name;
@@ -2656,12 +2694,15 @@ static UniValue resendwallettransactions(const JSONRPCRequest& request)
throw std::runtime_error(
RPCHelpMan{"resendwallettransactions",
"Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
- "Intended only for testing; the wallet code periodically re-broadcasts\n",
- {}}
- .ToString() +
- "automatically.\n"
+ "Intended only for testing; the wallet code periodically re-broadcasts\n"
+ "automatically.\n",
+ {},
+ RPCResult{
"Returns an RPC error if -walletbroadcast is set to false.\n"
"Returns array of transaction ids that were re-broadcast.\n"
+ },
+ RPCExamples{""},
+ }.ToString()
);
if (!g_connman)
@@ -2716,9 +2757,8 @@ static UniValue listunspent(const JSONRPCRequest& request)
{"minimumSumAmount", RPCArg::Type::AMOUNT, /* opt */ true, /* default_val */ "unlimited", "Minimum sum value of all UTXOs in " + CURRENCY_UNIT + ""},
},
"query_options"},
- }}
- .ToString() +
- "\nResult\n"
+ },
+ RPCResult{
"[ (array of json object)\n"
" {\n"
" \"txid\" : \"txid\", (string) the transaction id \n"
@@ -2738,14 +2778,15 @@ static UniValue listunspent(const JSONRPCRequest& request)
" }\n"
" ,...\n"
"]\n"
-
- "\nExamples\n"
- + HelpExampleCli("listunspent", "")
+ },
+ RPCExamples{
+ HelpExampleCli("listunspent", "")
+ HelpExampleCli("listunspent", "6 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
+ HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
+ HelpExampleCli("listunspent", "6 9999999 '[]' true '{ \"minimumAmount\": 0.005 }'")
+ HelpExampleRpc("listunspent", "6, 9999999, [] , true, { \"minimumAmount\": 0.005 } ")
- );
+ },
+ }.ToString());
int nMinDepth = 1;
if (!request.params[0].isNull()) {
@@ -2993,7 +3034,8 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request)
"This will not modify existing inputs, and will add at most one change output to the outputs.\n"
"No existing outputs will be modified unless \"subtractFeeFromOutputs\" is specified.\n"
"Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
- "The inputs added will not be signed, use signrawtransaction for that.\n"
+ "The inputs added will not be signed, use signrawtransactionwithkey\n"
+ " or signrawtransactionwithwallet for that.\n"
"Note that all existing inputs must have their previous output transaction be in the wallet.\n"
"Note that all inputs selected must be of standard form and P2SH scripts must be\n"
"in the wallet using importaddress or addmultisigaddress (to calculate fees).\n"
@@ -3028,24 +3070,25 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request)
"options"},
{"iswitness", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction \n"
" If iswitness is not present, heuristic tests will be used in decoding"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{\n"
" \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n"
" \"fee\": n, (numeric) Fee in " + CURRENCY_UNIT + " the resulting transaction pays\n"
" \"changepos\": n (numeric) The position of the added change output, or -1\n"
"}\n"
- "\nExamples:\n"
+ },
+ RPCExamples{
"\nCreate a transaction with no inputs\n"
+ HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
"\nAdd sufficient unsigned inputs to meet the output value\n"
+ HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
"\nSign the transaction\n"
- + HelpExampleCli("signrawtransaction", "\"fundedtransactionhex\"") +
+ + HelpExampleCli("signrawtransactionwithwallet", "\"fundedtransactionhex\"") +
"\nSend the transaction\n"
+ HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
- );
+ },
+ }.ToString());
RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType(), UniValue::VBOOL});
@@ -3062,7 +3105,7 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request)
FundTransaction(pwallet, tx, fee, change_position, request.params[1]);
UniValue result(UniValue::VOBJ);
- result.pushKV("hex", EncodeHexTx(tx));
+ result.pushKV("hex", EncodeHexTx(CTransaction(tx)));
result.pushKV("fee", ValueFromAmount(fee));
result.pushKV("changepos", change_position);
@@ -3107,9 +3150,8 @@ UniValue signrawtransactionwithwallet(const JSONRPCRequest& request)
" \"ALL|ANYONECANPAY\"\n"
" \"NONE|ANYONECANPAY\"\n"
" \"SINGLE|ANYONECANPAY\""},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{\n"
" \"hex\" : \"value\", (string) The hex-encoded raw transaction with signature(s)\n"
" \"complete\" : true|false, (boolean) If the transaction has a complete set of signatures\n"
@@ -3124,11 +3166,12 @@ UniValue signrawtransactionwithwallet(const JSONRPCRequest& request)
" ,...\n"
" ]\n"
"}\n"
-
- "\nExamples:\n"
- + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"")
+ },
+ RPCExamples{
+ HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"")
+ HelpExampleRpc("signrawtransactionwithwallet", "\"myhex\"")
- );
+ },
+ }.ToString());
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VSTR}, true);
@@ -3190,18 +3233,20 @@ static UniValue bumpfee(const JSONRPCRequest& request)
" \"CONSERVATIVE\""},
},
"options"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{\n"
" \"txid\": \"value\", (string) The id of the new transaction\n"
" \"origfee\": n, (numeric) Fee of the replaced transaction\n"
" \"fee\": n, (numeric) Fee of the new transaction\n"
" \"errors\": [ str... ] (json array of strings) Errors encountered during processing (may be empty)\n"
"}\n"
- "\nExamples:\n"
+ },
+ RPCExamples{
"\nBump the fee, get the new transaction\'s txid\n" +
- HelpExampleCli("bumpfee", "<txid>"));
+ HelpExampleCli("bumpfee", "<txid>")
+ },
+ }.ToString());
}
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ});
@@ -3316,14 +3361,15 @@ UniValue generate(const JSONRPCRequest& request)
{
{"nblocks", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "How many blocks are generated immediately."},
{"maxtries", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "1000000", "How many iterations to try."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"[ blockhashes ] (array) hashes of blocks generated\n"
- "\nExamples:\n"
+ },
+ RPCExamples{
"\nGenerate 11 blocks\n"
+ HelpExampleCli("generate", "11")
- );
+ },
+ }.ToString());
}
if (!IsDeprecatedRPCEnabled("generate")) {
@@ -3369,18 +3415,19 @@ UniValue rescanblockchain(const JSONRPCRequest& request)
"\nRescan the local blockchain for wallet related transactions.\n",
{
{"start_height", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "block height where the rescan should start"},
- {"stop_height", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "tip height", "the last block height that should be scanned"},
- }}
- .ToString() +
- "\nResult:\n"
+ {"stop_height", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "", "the last block height that should be scanned. If none is provided it will rescan up to the tip at return time of this call."},
+ },
+ RPCResult{
"{\n"
- " \"start_height\" (numeric) The block height where the rescan has started. If omitted, rescan started from the genesis block.\n"
- " \"stop_height\" (numeric) The height of the last rescanned block. If omitted, rescan stopped at the chain tip.\n"
+ " \"start_height\" (numeric) The block height where the rescan started (the requested height or 0)\n"
+ " \"stop_height\" (numeric) The height of the last rescanned block. May be null in rare cases if there was a reorg and the call didn't scan any blocks because they were already scanned in the background.\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("rescanblockchain", "100000 120000")
+ },
+ RPCExamples{
+ HelpExampleCli("rescanblockchain", "100000 120000")
+ HelpExampleRpc("rescanblockchain", "100000, 120000")
- );
+ },
+ }.ToString());
}
WalletRescanReserver reserver(pwallet);
@@ -3388,50 +3435,53 @@ UniValue rescanblockchain(const JSONRPCRequest& request)
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
}
- CBlockIndex *pindexStart = nullptr;
- CBlockIndex *pindexStop = nullptr;
- CBlockIndex *pChainTip = nullptr;
+ int start_height = 0;
+ uint256 start_block, stop_block;
{
auto locked_chain = pwallet->chain().lock();
- pindexStart = chainActive.Genesis();
- pChainTip = chainActive.Tip();
+ Optional<int> tip_height = locked_chain->getHeight();
if (!request.params[0].isNull()) {
- pindexStart = chainActive[request.params[0].get_int()];
- if (!pindexStart) {
+ start_height = request.params[0].get_int();
+ if (start_height < 0 || !tip_height || start_height > *tip_height) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid start_height");
}
}
+ Optional<int> stop_height;
if (!request.params[1].isNull()) {
- pindexStop = chainActive[request.params[1].get_int()];
- if (!pindexStop) {
+ stop_height = request.params[1].get_int();
+ if (*stop_height < 0 || !tip_height || *stop_height > *tip_height) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid stop_height");
}
- else if (pindexStop->nHeight < pindexStart->nHeight) {
+ else if (*stop_height < start_height) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "stop_height must be greater than start_height");
}
}
- }
- // We can't rescan beyond non-pruned blocks, stop and throw an error
- if (fPruneMode) {
- auto locked_chain = pwallet->chain().lock();
- CBlockIndex *block = pindexStop ? pindexStop : pChainTip;
- while (block && block->nHeight >= pindexStart->nHeight) {
- if (!(block->nStatus & BLOCK_HAVE_DATA)) {
- throw JSONRPCError(RPC_MISC_ERROR, "Can't rescan beyond pruned data. Use RPC call getblockchaininfo to determine your pruned height.");
+ // We can't rescan beyond non-pruned blocks, stop and throw an error
+ if (locked_chain->findPruned(start_height, stop_height)) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Can't rescan beyond pruned data. Use RPC call getblockchaininfo to determine your pruned height.");
+ }
+
+ if (tip_height) {
+ start_block = locked_chain->getBlockHash(start_height);
+ // If called with a stop_height, set the stop_height here to
+ // trigger a rescan to that height.
+ // If called without a stop height, leave stop_height as null here
+ // so rescan continues to the tip (even if the tip advances during
+ // rescan).
+ if (stop_height) {
+ stop_block = locked_chain->getBlockHash(*stop_height);
}
- block = block->pprev;
}
}
- const CBlockIndex *failed_block, *stopBlock;
CWallet::ScanResult result =
- pwallet->ScanForWalletTransactions(pindexStart, pindexStop, reserver, failed_block, stopBlock, true);
- switch (result) {
+ pwallet->ScanForWalletTransactions(start_block, stop_block, reserver, true /* fUpdate */);
+ switch (result.status) {
case CWallet::ScanResult::SUCCESS:
- break; // stopBlock set by ScanForWalletTransactions
+ break;
case CWallet::ScanResult::FAILURE:
throw JSONRPCError(RPC_MISC_ERROR, "Rescan failed. Potentially corrupted data files.");
case CWallet::ScanResult::USER_ABORT:
@@ -3439,8 +3489,8 @@ UniValue rescanblockchain(const JSONRPCRequest& request)
// no default case, so the compiler can warn about missing cases
}
UniValue response(UniValue::VOBJ);
- response.pushKV("start_height", pindexStart->nHeight);
- response.pushKV("stop_height", stopBlock->nHeight);
+ response.pushKV("start_height", start_height);
+ response.pushKV("stop_height", result.last_scanned_height ? *result.last_scanned_height : UniValue());
return response;
}
@@ -3579,9 +3629,8 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
"to be in the wallet.\n",
{
{"address", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The bitcoin address to get the information of."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{\n"
" \"address\" : \"address\", (string) The bitcoin address validated\n"
" \"scriptPubKey\" : \"hex\", (string) The hex-encoded scriptPubKey generated by the address\n"
@@ -3618,10 +3667,12 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
" },...\n"
" ]\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getaddressinfo", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
+ },
+ RPCExamples{
+ HelpExampleCli("getaddressinfo", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
+ HelpExampleRpc("getaddressinfo", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
- );
+ },
+ }.ToString());
}
LOCK(pwallet->cs_wallet);
@@ -3705,18 +3756,19 @@ static UniValue getaddressesbylabel(const JSONRPCRequest& request)
"\nReturns the list of addresses assigned the specified label.\n",
{
{"label", RPCArg::Type::STR, /* opt */ false, /* default_val */ "", "The label."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{ (json object with addresses as keys)\n"
" \"address\": { (json object with information about address)\n"
" \"purpose\": \"string\" (string) Purpose of address (\"send\" for sending address, \"receive\" for receiving address)\n"
" },...\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getaddressesbylabel", "\"tabby\"")
+ },
+ RPCExamples{
+ HelpExampleCli("getaddressesbylabel", "\"tabby\"")
+ HelpExampleRpc("getaddressesbylabel", "\"tabby\"")
- );
+ },
+ }.ToString());
LOCK(pwallet->cs_wallet);
@@ -3752,14 +3804,14 @@ static UniValue listlabels(const JSONRPCRequest& request)
"\nReturns the list of all labels, or labels that are assigned to addresses with a specific purpose.\n",
{
{"purpose", RPCArg::Type::STR, /* opt */ true, /* default_val */ "null", "Address purpose to list labels for ('send','receive'). An empty string is the same as not providing this argument."},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"[ (json array of string)\n"
" \"label\", (string) Label name\n"
" ...\n"
"]\n"
- "\nExamples:\n"
+ },
+ RPCExamples{
"\nList all labels\n"
+ HelpExampleCli("listlabels", "") +
"\nList labels that have receiving addresses\n"
@@ -3768,7 +3820,8 @@ static UniValue listlabels(const JSONRPCRequest& request)
+ HelpExampleCli("listlabels", "send") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("listlabels", "receive")
- );
+ },
+ }.ToString());
LOCK(pwallet->cs_wallet);
@@ -3816,25 +3869,30 @@ UniValue sethdseed(const JSONRPCRequest& request)
" keypool will be used until it has been depleted."},
{"seed", RPCArg::Type::STR, /* opt */ true, /* default_val */ "random seed", "The WIF private key to use as the new HD seed.\n"
" The seed value can be retrieved using the dumpwallet command. It is the private key marked hdseed=1"},
- }}
- .ToString() +
- "\nExamples:\n"
- + HelpExampleCli("sethdseed", "")
+ },
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("sethdseed", "")
+ HelpExampleCli("sethdseed", "false")
+ HelpExampleCli("sethdseed", "true \"wifkey\"")
+ HelpExampleRpc("sethdseed", "true, \"wifkey\"")
- );
+ },
+ }.ToString());
}
if (IsInitialBlockDownload()) {
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Cannot set a new HD seed while still in Initial Block Download");
}
+ if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set a HD seed to a wallet with private keys disabled");
+ }
+
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
// Do not do anything to non-HD wallets
- if (!pwallet->IsHDEnabled()) {
+ if (!pwallet->CanSupportFeature(FEATURE_HD)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set a HD seed on a non-HD wallet. Start with -upgradewallet in order to upgrade a non-HD wallet to HD");
}
@@ -3960,18 +4018,18 @@ UniValue walletprocesspsbt(const JSONRPCRequest& request)
" \"NONE|ANYONECANPAY\"\n"
" \"SINGLE|ANYONECANPAY\""},
{"bip32derivs", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "If true, includes the BIP 32 derivation paths for public keys if we know them"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{\n"
" \"psbt\" : \"value\", (string) The base64-encoded partially signed transaction\n"
" \"complete\" : true|false, (boolean) If the transaction has a complete set of signatures\n"
" ]\n"
"}\n"
-
- "\nExamples:\n"
- + HelpExampleCli("walletprocesspsbt", "\"psbt\"")
- );
+ },
+ RPCExamples{
+ HelpExampleCli("walletprocesspsbt", "\"psbt\"")
+ },
+ }.ToString());
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VSTR});
@@ -4042,8 +4100,7 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
},
},
},
- {"locktime", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Raw locktime. Non-0 value also locktime-activates inputs\n"
- " Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."},
+ {"locktime", RPCArg::Type::NUM, /* opt */ true, /* default_val */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"},
{"options", RPCArg::Type::OBJ, /* opt */ true, /* default_val */ "null", "",
{
{"changeAddress", RPCArg::Type::STR_HEX, /* opt */ true, /* default_val */ "pool address", "The bitcoin address to receive the change"},
@@ -4070,18 +4127,19 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
},
"options"},
{"bip32derivs", RPCArg::Type::BOOL, /* opt */ true, /* default_val */ "false", "If true, includes the BIP 32 derivation paths for public keys if we know them"},
- }}
- .ToString() +
- "\nResult:\n"
+ },
+ RPCResult{
"{\n"
" \"psbt\": \"value\", (string) The resulting raw transaction (base64-encoded string)\n"
" \"fee\": n, (numeric) Fee in " + CURRENCY_UNIT + " the resulting transaction pays\n"
" \"changepos\": n (numeric) The position of the added change output, or -1\n"
"}\n"
- "\nExamples:\n"
+ },
+ RPCExamples{
"\nCreate a transaction with no inputs\n"
+ HelpExampleCli("walletcreatefundedpsbt", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
- );
+ },
+ }.ToString());
RPCTypeCheck(request.params, {
UniValue::VARR,
@@ -4138,7 +4196,7 @@ static const CRPCCommand commands[] =
{ "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","label","address_type"} },
{ "wallet", "backupwallet", &backupwallet, {"destination"} },
{ "wallet", "bumpfee", &bumpfee, {"txid", "options"} },
- { "wallet", "createwallet", &createwallet, {"wallet_name", "disable_private_keys"} },
+ { "wallet", "createwallet", &createwallet, {"wallet_name", "disable_private_keys", "blank"} },
{ "wallet", "dumpprivkey", &dumpprivkey, {"address"} },
{ "wallet", "dumpwallet", &dumpwallet, {"filename"} },
{ "wallet", "encryptwallet", &encryptwallet, {"passphrase"} },
diff --git a/src/wallet/test/db_tests.cpp b/src/wallet/test/db_tests.cpp
new file mode 100644
index 0000000000..2a64749379
--- /dev/null
+++ b/src/wallet/test/db_tests.cpp
@@ -0,0 +1,72 @@
+// Copyright (c) 2018 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <memory>
+
+#include <boost/test/unit_test.hpp>
+
+#include <fs.h>
+#include <test/test_bitcoin.h>
+#include <wallet/db.h>
+
+
+BOOST_FIXTURE_TEST_SUITE(db_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(getwalletenv_file)
+{
+ std::string test_name = "test_name.dat";
+ fs::path datadir = SetDataDir("tempdir");
+ fs::path file_path = datadir / test_name;
+ std::ofstream f(file_path.BOOST_FILESYSTEM_C_STR);
+ f.close();
+
+ std::string filename;
+ std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(file_path, filename);
+ BOOST_CHECK(filename == test_name);
+ BOOST_CHECK(env->Directory() == datadir);
+}
+
+BOOST_AUTO_TEST_CASE(getwalletenv_directory)
+{
+ std::string expected_name = "wallet.dat";
+ fs::path datadir = SetDataDir("tempdir");
+
+ std::string filename;
+ std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(datadir, filename);
+ BOOST_CHECK(filename == expected_name);
+ BOOST_CHECK(env->Directory() == datadir);
+}
+
+BOOST_AUTO_TEST_CASE(getwalletenv_g_dbenvs_multiple)
+{
+ fs::path datadir = SetDataDir("tempdir");
+ fs::path datadir_2 = SetDataDir("tempdir_2");
+ std::string filename;
+
+ std::shared_ptr<BerkeleyEnvironment> env_1 = GetWalletEnv(datadir, filename);
+ std::shared_ptr<BerkeleyEnvironment> env_2 = GetWalletEnv(datadir, filename);
+ std::shared_ptr<BerkeleyEnvironment> env_3 = GetWalletEnv(datadir_2, filename);
+
+ BOOST_CHECK(env_1 == env_2);
+ BOOST_CHECK(env_2 != env_3);
+}
+
+BOOST_AUTO_TEST_CASE(getwalletenv_g_dbenvs_free_instance)
+{
+ fs::path datadir = SetDataDir("tempdir");
+ fs::path datadir_2 = SetDataDir("tempdir_2");
+ std::string filename;
+
+ std::shared_ptr <BerkeleyEnvironment> env_1_a = GetWalletEnv(datadir, filename);
+ std::shared_ptr <BerkeleyEnvironment> env_2_a = GetWalletEnv(datadir_2, filename);
+ env_1_a.reset();
+
+ std::shared_ptr<BerkeleyEnvironment> env_1_b = GetWalletEnv(datadir, filename);
+ std::shared_ptr<BerkeleyEnvironment> env_2_b = GetWalletEnv(datadir_2, filename);
+
+ BOOST_CHECK(env_1_a != env_1_b);
+ BOOST_CHECK(env_2_a == env_2_b);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 0db22cf6fe..e674b2faea 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -39,12 +39,12 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
auto chain = interfaces::MakeChain();
// Cap last block file size, and mine new block in a new block file.
- const CBlockIndex* const null_block = nullptr;
CBlockIndex* oldTip = chainActive.Tip();
GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE;
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
CBlockIndex* newTip = chainActive.Tip();
+ LockAnnotation lock(::cs_main);
auto locked_chain = chain->lock();
// Verify ScanForWalletTransactions accommodates a null start block.
@@ -53,10 +53,11 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
AddKey(wallet, coinbaseKey);
WalletRescanReserver reserver(&wallet);
reserver.reserve();
- const CBlockIndex *stop_block = null_block + 1, *failed_block = null_block + 1;
- BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(nullptr, nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::SUCCESS);
- BOOST_CHECK_EQUAL(failed_block, null_block);
- BOOST_CHECK_EQUAL(stop_block, null_block);
+ CWallet::ScanResult result = wallet.ScanForWalletTransactions({} /* start_block */, {} /* stop_block */, reserver, false /* update */);
+ BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS);
+ BOOST_CHECK(result.last_failed_block.IsNull());
+ BOOST_CHECK(result.last_scanned_block.IsNull());
+ BOOST_CHECK(!result.last_scanned_height);
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 0);
}
@@ -67,10 +68,11 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
AddKey(wallet, coinbaseKey);
WalletRescanReserver reserver(&wallet);
reserver.reserve();
- const CBlockIndex *stop_block = null_block + 1, *failed_block = null_block + 1;
- BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(oldTip, nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::SUCCESS);
- BOOST_CHECK_EQUAL(failed_block, null_block);
- BOOST_CHECK_EQUAL(stop_block, newTip);
+ CWallet::ScanResult result = wallet.ScanForWalletTransactions(oldTip->GetBlockHash(), {} /* stop_block */, reserver, false /* update */);
+ BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS);
+ BOOST_CHECK(result.last_failed_block.IsNull());
+ BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash());
+ BOOST_CHECK_EQUAL(*result.last_scanned_height, newTip->nHeight);
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN);
}
@@ -85,10 +87,11 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
AddKey(wallet, coinbaseKey);
WalletRescanReserver reserver(&wallet);
reserver.reserve();
- const CBlockIndex *stop_block = null_block + 1, *failed_block = null_block + 1;
- BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(oldTip, nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::FAILURE);
- BOOST_CHECK_EQUAL(failed_block, oldTip);
- BOOST_CHECK_EQUAL(stop_block, newTip);
+ CWallet::ScanResult result = wallet.ScanForWalletTransactions(oldTip->GetBlockHash(), {} /* stop_block */, reserver, false /* update */);
+ BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::FAILURE);
+ BOOST_CHECK_EQUAL(result.last_failed_block, oldTip->GetBlockHash());
+ BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash());
+ BOOST_CHECK_EQUAL(*result.last_scanned_height, newTip->nHeight);
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN);
}
@@ -102,10 +105,11 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
AddKey(wallet, coinbaseKey);
WalletRescanReserver reserver(&wallet);
reserver.reserve();
- const CBlockIndex *stop_block = null_block + 1, *failed_block = null_block + 1;
- BOOST_CHECK_EQUAL(wallet.ScanForWalletTransactions(oldTip, nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::FAILURE);
- BOOST_CHECK_EQUAL(failed_block, newTip);
- BOOST_CHECK_EQUAL(stop_block, null_block);
+ CWallet::ScanResult result = wallet.ScanForWalletTransactions(oldTip->GetBlockHash(), {} /* stop_block */, reserver, false /* update */);
+ BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::FAILURE);
+ BOOST_CHECK_EQUAL(result.last_failed_block, newTip->GetBlockHash());
+ BOOST_CHECK(result.last_scanned_block.IsNull());
+ BOOST_CHECK(!result.last_scanned_height);
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 0);
}
}
@@ -120,6 +124,7 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup)
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
CBlockIndex* newTip = chainActive.Tip();
+ LockAnnotation lock(::cs_main);
auto locked_chain = chain->lock();
// Prune the older block file.
@@ -265,6 +270,7 @@ static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64
SetMockTime(mockTime);
CBlockIndex* block = nullptr;
if (blockTime > 0) {
+ LockAnnotation lock(::cs_main);
auto locked_chain = wallet.chain().lock();
auto inserted = mapBlockIndex.emplace(GetRandHash(), new CBlockIndex);
assert(inserted.second);
@@ -276,7 +282,7 @@ static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64
CWalletTx wtx(&wallet, MakeTransactionRef(tx));
if (block) {
- wtx.SetMerkleBranch(block, 0);
+ wtx.SetMerkleBranch(block->GetBlockHash(), 0);
}
{
LOCK(cs_main);
@@ -340,11 +346,11 @@ public:
AddKey(*wallet, coinbaseKey);
WalletRescanReserver reserver(wallet.get());
reserver.reserve();
- const CBlockIndex* const null_block = nullptr;
- const CBlockIndex *stop_block = null_block + 1, *failed_block = null_block + 1;
- BOOST_CHECK_EQUAL(wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, failed_block, stop_block), CWallet::ScanResult::SUCCESS);
- BOOST_CHECK_EQUAL(stop_block, chainActive.Tip());
- BOOST_CHECK_EQUAL(failed_block, null_block);
+ CWallet::ScanResult result = wallet->ScanForWalletTransactions(chainActive.Genesis()->GetBlockHash(), {} /* stop_block */, reserver, false /* update */);
+ BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS);
+ BOOST_CHECK_EQUAL(result.last_scanned_block, chainActive.Tip()->GetBlockHash());
+ BOOST_CHECK_EQUAL(*result.last_scanned_height, chainActive.Height());
+ BOOST_CHECK(result.last_failed_block.IsNull());
}
~ListCoinsTestingSetup()
@@ -372,7 +378,7 @@ public:
LOCK(wallet->cs_wallet);
auto it = wallet->mapWallet.find(tx->GetHash());
BOOST_CHECK(it != wallet->mapWallet.end());
- it->second.SetMerkleBranch(chainActive.Tip(), 1);
+ it->second.SetMerkleBranch(chainActive.Tip()->GetBlockHash(), 1);
return it->second;
}
@@ -446,6 +452,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup)
{
auto chain = interfaces::MakeChain();
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(*chain, WalletLocation(), WalletDatabase::CreateDummy());
+ wallet->SetMinVersion(FEATURE_LATEST);
wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
BOOST_CHECK(!wallet->TopUpKeyPool(1000));
CPubKey pubkey;
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 098055673b..063015d1d8 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -130,6 +130,28 @@ void UnloadWallet(std::shared_ptr<CWallet>&& wallet)
}
}
+std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, std::string& error, std::string& warning)
+{
+ if (!CWallet::Verify(chain, location, false, error, warning)) {
+ error = "Wallet file verification failed: " + error;
+ return nullptr;
+ }
+
+ std::shared_ptr<CWallet> wallet = CWallet::CreateWalletFromFile(chain, location);
+ if (!wallet) {
+ error = "Wallet loading failed.";
+ return nullptr;
+ }
+ AddWallet(wallet);
+ wallet->postInitProcess();
+ return wallet;
+}
+
+std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::string& warning)
+{
+ return LoadWallet(chain, WalletLocation(name), error, warning);
+}
+
const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000;
const uint256 CMerkleTx::ABANDON_HASH(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
@@ -168,6 +190,7 @@ const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
CPubKey CWallet::GenerateNewKey(WalletBatch &batch, bool internal)
{
assert(!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
+ assert(!IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET));
AssertLockHeld(cs_wallet); // mapKeyMetadata
bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
@@ -177,7 +200,7 @@ CPubKey CWallet::GenerateNewKey(WalletBatch &batch, bool internal)
int64_t nCreationTime = GetTime();
CKeyMetadata metadata(nCreationTime);
- // use HD key derivation if HD was enabled during wallet creation
+ // use HD key derivation if HD was enabled during wallet creation and a seed is present
if (IsHDEnabled()) {
DeriveNewChildKey(batch, metadata, secret, (CanSupportFeature(FEATURE_HD_SPLIT) ? internal : false));
} else {
@@ -251,6 +274,9 @@ bool CWallet::AddKeyPubKeyWithDB(WalletBatch &batch, const CKey& secret, const C
{
AssertLockHeld(cs_wallet); // mapKeyMetadata
+ // Make sure we aren't adding private keys to private key disabled wallets
+ assert(!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
+
// CCryptoKeyStore has no concept of wallet databases, but calls AddCryptedKey
// which is overridden below. To avoid flushes, the database handle is
// tunneled through to it.
@@ -280,6 +306,7 @@ bool CWallet::AddKeyPubKeyWithDB(WalletBatch &batch, const CKey& secret, const C
secret.GetPrivKey(),
mapKeyMetadata[pubkey.GetID()]);
}
+ UnsetWalletFlag(WALLET_FLAG_BLANK_WALLET);
return true;
}
@@ -346,7 +373,11 @@ bool CWallet::AddCScript(const CScript& redeemScript)
{
if (!CCryptoKeyStore::AddCScript(redeemScript))
return false;
- return WalletBatch(*database).WriteCScript(Hash160(redeemScript), redeemScript);
+ if (WalletBatch(*database).WriteCScript(Hash160(redeemScript), redeemScript)) {
+ UnsetWalletFlag(WALLET_FLAG_BLANK_WALLET);
+ return true;
+ }
+ return false;
}
bool CWallet::LoadCScript(const CScript& redeemScript)
@@ -371,7 +402,11 @@ bool CWallet::AddWatchOnly(const CScript& dest)
const CKeyMetadata& meta = m_script_metadata[CScriptID(dest)];
UpdateTimeFirstKey(meta.nCreateTime);
NotifyWatchonlyChanged(true);
- return WalletBatch(*database).WriteWatchOnly(dest, meta);
+ if (WalletBatch(*database).WriteWatchOnly(dest, meta)) {
+ UnsetWalletFlag(WALLET_FLAG_BLANK_WALLET);
+ return true;
+ }
+ return false;
}
bool CWallet::AddWatchOnly(const CScript& dest, int64_t nCreateTime)
@@ -398,7 +433,7 @@ bool CWallet::LoadWatchOnly(const CScript &dest)
return CCryptoKeyStore::AddWatchOnly(dest);
}
-bool CWallet::Unlock(const SecureString& strWalletPassphrase)
+bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool accept_no_keys)
{
CCrypter crypter;
CKeyingMaterial _vMasterKey;
@@ -411,7 +446,7 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase)
return false;
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
continue; // try another master key
- if (CCryptoKeyStore::Unlock(_vMasterKey))
+ if (CCryptoKeyStore::Unlock(_vMasterKey, accept_no_keys))
return true;
}
}
@@ -935,19 +970,19 @@ void CWallet::LoadToWallet(const CWalletTx& wtxIn)
}
}
-bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate)
+bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const uint256& block_hash, int posInBlock, bool fUpdate)
{
const CTransaction& tx = *ptx;
{
AssertLockHeld(cs_wallet);
- if (pIndex != nullptr) {
+ if (!block_hash.IsNull()) {
for (const CTxIn& txin : tx.vin) {
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.prevout);
while (range.first != range.second) {
if (range.first->second != tx.GetHash()) {
- WalletLogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), pIndex->GetBlockHash().ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n);
- MarkConflicted(pIndex->GetBlockHash(), range.first->second);
+ WalletLogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), block_hash.ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n);
+ MarkConflicted(block_hash, range.first->second);
}
range.first++;
}
@@ -983,8 +1018,8 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const CBlockI
CWalletTx wtx(this, ptx);
// Get merkle branch if transaction was found in a block
- if (pIndex != nullptr)
- wtx.SetMerkleBranch(pIndex, posInBlock);
+ if (!block_hash.IsNull())
+ wtx.SetMerkleBranch(block_hash, posInBlock);
return AddToWallet(wtx, false);
}
@@ -1071,11 +1106,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
auto locked_chain = chain().lock();
LOCK(cs_wallet);
- int conflictconfirms = 0;
- CBlockIndex* pindex = LookupBlockIndex(hashBlock);
- if (pindex && chainActive.Contains(pindex)) {
- conflictconfirms = -(chainActive.Height() - pindex->nHeight + 1);
- }
+ int conflictconfirms = -locked_chain->getBlockDepth(hashBlock);
// If number of conflict confirms cannot be determined, this means
// that the block is still unknown or not yet part of the main chain,
// for example when loading the wallet during a reindex. Do nothing in that
@@ -1121,8 +1152,8 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
}
}
-void CWallet::SyncTransaction(const CTransactionRef& ptx, const CBlockIndex *pindex, int posInBlock, bool update_tx) {
- if (!AddToWalletIfInvolvingMe(ptx, pindex, posInBlock, update_tx))
+void CWallet::SyncTransaction(const CTransactionRef& ptx, const uint256& block_hash, int posInBlock, bool update_tx) {
+ if (!AddToWalletIfInvolvingMe(ptx, block_hash, posInBlock, update_tx))
return; // Not one of ours
// If a transaction changes 'conflicted' state, that changes the balance
@@ -1134,7 +1165,7 @@ void CWallet::SyncTransaction(const CTransactionRef& ptx, const CBlockIndex *pin
void CWallet::TransactionAddedToMempool(const CTransactionRef& ptx) {
auto locked_chain = chain().lock();
LOCK(cs_wallet);
- SyncTransaction(ptx);
+ SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */);
auto it = mapWallet.find(ptx->GetHash());
if (it != mapWallet.end()) {
@@ -1162,15 +1193,15 @@ void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const
// the notification that the conflicted transaction was evicted.
for (const CTransactionRef& ptx : vtxConflicted) {
- SyncTransaction(ptx);
+ SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */);
TransactionRemovedFromMempool(ptx);
}
for (size_t i = 0; i < pblock->vtx.size(); i++) {
- SyncTransaction(pblock->vtx[i], pindex, i);
+ SyncTransaction(pblock->vtx[i], pindex->GetBlockHash(), i);
TransactionRemovedFromMempool(pblock->vtx[i]);
}
- m_last_block_processed = pindex;
+ m_last_block_processed = pindex->GetBlockHash();
}
void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) {
@@ -1178,7 +1209,7 @@ void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) {
LOCK(cs_wallet);
for (const CTransactionRef& ptx : pblock->vtx) {
- SyncTransaction(ptx);
+ SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */);
}
}
@@ -1195,9 +1226,8 @@ void CWallet::BlockUntilSyncedToCurrentChain() {
// protected by cs_wallet instead of cs_main, but as long as we need
// cs_main here anyway, it's easier to just call it cs_main-protected.
auto locked_chain = chain().lock();
- const CBlockIndex* initialChainTip = chainActive.Tip();
- if (m_last_block_processed && m_last_block_processed->GetAncestor(initialChainTip->nHeight) == initialChainTip) {
+ if (!m_last_block_processed.IsNull() && locked_chain->isPotentialTip(m_last_block_processed)) {
return;
}
}
@@ -1403,6 +1433,8 @@ void CWallet::SetHDSeed(const CPubKey& seed)
newHdChain.nVersion = CanSupportFeature(FEATURE_HD_SPLIT) ? CHDChain::VERSION_HD_CHAIN_SPLIT : CHDChain::VERSION_HD_BASE;
newHdChain.seed_id = seed.GetID();
SetHDChain(newHdChain, false);
+ NotifyCanGetAddressesChanged();
+ UnsetWalletFlag(WALLET_FLAG_BLANK_WALLET);
}
void CWallet::SetHDChain(const CHDChain& chain, bool memonly)
@@ -1419,6 +1451,30 @@ bool CWallet::IsHDEnabled() const
return !hdChain.seed_id.IsNull();
}
+bool CWallet::CanGenerateKeys()
+{
+ // A wallet can generate keys if it has an HD seed (IsHDEnabled) or it is a non-HD wallet (pre FEATURE_HD)
+ LOCK(cs_wallet);
+ return IsHDEnabled() || !CanSupportFeature(FEATURE_HD);
+}
+
+bool CWallet::CanGetAddresses(bool internal)
+{
+ LOCK(cs_wallet);
+ // Check if the keypool has keys
+ bool keypool_has_keys;
+ if (internal && CanSupportFeature(FEATURE_HD_SPLIT)) {
+ keypool_has_keys = setInternalKeyPool.size() > 0;
+ } else {
+ keypool_has_keys = KeypoolCountExternalKeys() > 0;
+ }
+ // If the keypool doesn't have keys, check if we can generate them
+ if (!keypool_has_keys) {
+ return CanGenerateKeys();
+ }
+ return keypool_has_keys;
+}
+
void CWallet::SetWalletFlag(uint64_t flags)
{
LOCK(cs_wallet);
@@ -1427,6 +1483,14 @@ void CWallet::SetWalletFlag(uint64_t flags)
throw std::runtime_error(std::string(__func__) + ": writing wallet flags failed");
}
+void CWallet::UnsetWalletFlag(uint64_t flag)
+{
+ LOCK(cs_wallet);
+ m_wallet_flags &= ~flag;
+ if (!WalletBatch(*database).WriteWalletFlags(m_wallet_flags))
+ throw std::runtime_error(std::string(__func__) + ": writing wallet flags failed");
+}
+
bool CWallet::IsWalletFlagSet(uint64_t flag)
{
return (m_wallet_flags & flag);
@@ -1510,7 +1574,7 @@ int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wall
// implies that we can sign for every input.
return -1;
}
- return GetVirtualTransactionSize(txNew);
+ return GetVirtualTransactionSize(CTransaction(txNew));
}
int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* wallet, bool use_max_sig)
@@ -1591,132 +1655,146 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r
// Find starting block. May be null if nCreateTime is greater than the
// highest blockchain timestamp, in which case there is nothing that needs
// to be scanned.
- CBlockIndex* startBlock = nullptr;
+ uint256 start_block;
{
auto locked_chain = chain().lock();
- startBlock = chainActive.FindEarliestAtLeast(startTime - TIMESTAMP_WINDOW);
- WalletLogPrintf("%s: Rescanning last %i blocks\n", __func__, startBlock ? chainActive.Height() - startBlock->nHeight + 1 : 0);
+ const Optional<int> start_height = locked_chain->findFirstBlockWithTime(startTime - TIMESTAMP_WINDOW, &start_block);
+ const Optional<int> tip_height = locked_chain->getHeight();
+ WalletLogPrintf("%s: Rescanning last %i blocks\n", __func__, tip_height && start_height ? *tip_height - *start_height + 1 : 0);
}
- if (startBlock) {
- const CBlockIndex *failedBlock, *stop_block;
+ if (!start_block.IsNull()) {
// TODO: this should take into account failure by ScanResult::USER_ABORT
- if (ScanResult::FAILURE == ScanForWalletTransactions(startBlock, nullptr, reserver, failedBlock, stop_block, update)) {
- return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1;
+ ScanResult result = ScanForWalletTransactions(start_block, {} /* stop_block */, reserver, update);
+ if (result.status == ScanResult::FAILURE) {
+ int64_t time_max;
+ if (!chain().findBlock(result.last_failed_block, nullptr /* block */, nullptr /* time */, &time_max)) {
+ throw std::logic_error("ScanForWalletTransactions returned invalid block hash");
+ }
+ return time_max + TIMESTAMP_WINDOW + 1;
}
}
return startTime;
}
/**
- * Scan the block chain (starting in pindexStart) for transactions
+ * Scan the block chain (starting in start_block) for transactions
* from or to us. If fUpdate is true, found transactions that already
* exist in the wallet will be updated.
*
- * @param[in] pindexStop if not a nullptr, the scan will stop at this block-index
- * @param[out] failed_block if FAILURE is returned, the most recent block
- * that could not be scanned, otherwise nullptr
- * @param[out] stop_block the most recent block that could be scanned,
- * otherwise nullptr if no block could be scanned
+ * @param[in] start_block Scan starting block. If block is not on the active
+ * chain, the scan will return SUCCESS immediately.
+ * @param[in] stop_block Scan ending block. If block is not on the active
+ * chain, the scan will continue until it reaches the
+ * chain tip.
*
- * @return ScanResult indicating success or failure of the scan. SUCCESS if
- * scan was successful. FAILURE if a complete rescan was not possible (due to
- * pruning or corruption). USER_ABORT if the rescan was aborted before it
- * could complete.
+ * @return ScanResult returning scan information and indicating success or
+ * failure. Return status will be set to SUCCESS if scan was
+ * successful. FAILURE if a complete rescan was not possible (due to
+ * pruning or corruption). USER_ABORT if the rescan was aborted before
+ * it could complete.
*
- * @pre Caller needs to make sure pindexStop (and the optional pindexStart) are on
+ * @pre Caller needs to make sure start_block (and the optional stop_block) are on
* the main chain after to the addition of any new keys you want to detect
* transactions for.
*/
-CWallet::ScanResult CWallet::ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, const CBlockIndex*& failed_block, const CBlockIndex*& stop_block, bool fUpdate)
+CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_block, const uint256& stop_block, const WalletRescanReserver& reserver, bool fUpdate)
{
int64_t nNow = GetTime();
- const CChainParams& chainParams = Params();
assert(reserver.isReserved());
- if (pindexStop) {
- assert(pindexStop->nHeight >= pindexStart->nHeight);
- }
- const CBlockIndex* pindex = pindexStart;
- failed_block = nullptr;
- stop_block = nullptr;
+ uint256 block_hash = start_block;
+ ScanResult result;
- if (pindex) WalletLogPrintf("Rescan started from block %d...\n", pindex->nHeight);
+ WalletLogPrintf("Rescan started from block %s...\n", start_block.ToString());
{
fAbortRescan = false;
ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
- CBlockIndex* tip = nullptr;
+ uint256 tip_hash;
+ // The way the 'block_height' is initialized is just a workaround for the gcc bug #47679 since version 4.6.0.
+ Optional<int> block_height = MakeOptional(false, int());
double progress_begin;
double progress_end;
{
auto locked_chain = chain().lock();
- progress_begin = GuessVerificationProgress(chainParams.TxData(), pindex);
- if (pindexStop == nullptr) {
- tip = chainActive.Tip();
- progress_end = GuessVerificationProgress(chainParams.TxData(), tip);
- } else {
- progress_end = GuessVerificationProgress(chainParams.TxData(), pindexStop);
+ if (Optional<int> tip_height = locked_chain->getHeight()) {
+ tip_hash = locked_chain->getBlockHash(*tip_height);
}
+ block_height = locked_chain->getBlockHeight(block_hash);
+ progress_begin = chain().guessVerificationProgress(block_hash);
+ progress_end = chain().guessVerificationProgress(stop_block.IsNull() ? tip_hash : stop_block);
}
double progress_current = progress_begin;
- while (pindex && !fAbortRescan && !ShutdownRequested()) {
- if (pindex->nHeight % 100 == 0 && progress_end - progress_begin > 0.0) {
+ while (block_height && !fAbortRescan && !ShutdownRequested()) {
+ if (*block_height % 100 == 0 && progress_end - progress_begin > 0.0) {
ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), std::max(1, std::min(99, (int)((progress_current - progress_begin) / (progress_end - progress_begin) * 100))));
}
if (GetTime() >= nNow + 60) {
nNow = GetTime();
- WalletLogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, progress_current);
+ WalletLogPrintf("Still rescanning. At block %d. Progress=%f\n", *block_height, progress_current);
}
CBlock block;
- if (ReadBlockFromDisk(block, pindex, Params().GetConsensus())) {
+ if (chain().findBlock(block_hash, &block) && !block.IsNull()) {
auto locked_chain = chain().lock();
LOCK(cs_wallet);
- if (pindex && !chainActive.Contains(pindex)) {
+ if (!locked_chain->getBlockHeight(block_hash)) {
// Abort scan if current block is no longer active, to prevent
// marking transactions as coming from the wrong block.
- failed_block = pindex;
+ // TODO: This should return success instead of failure, see
+ // https://github.com/bitcoin/bitcoin/pull/14711#issuecomment-458342518
+ result.last_failed_block = block_hash;
+ result.status = ScanResult::FAILURE;
break;
}
for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) {
- SyncTransaction(block.vtx[posInBlock], pindex, posInBlock, fUpdate);
+ SyncTransaction(block.vtx[posInBlock], block_hash, posInBlock, fUpdate);
}
// scan succeeded, record block as most recent successfully scanned
- stop_block = pindex;
+ result.last_scanned_block = block_hash;
+ result.last_scanned_height = *block_height;
} else {
// could not scan block, keep scanning but record this block as the most recent failure
- failed_block = pindex;
+ result.last_failed_block = block_hash;
+ result.status = ScanResult::FAILURE;
}
- if (pindex == pindexStop) {
+ if (block_hash == stop_block) {
break;
}
{
auto locked_chain = chain().lock();
- pindex = chainActive.Next(pindex);
- progress_current = GuessVerificationProgress(chainParams.TxData(), pindex);
- if (pindexStop == nullptr && tip != chainActive.Tip()) {
- tip = chainActive.Tip();
+ Optional<int> tip_height = locked_chain->getHeight();
+ if (!tip_height || *tip_height <= block_height || !locked_chain->getBlockHeight(block_hash)) {
+ // break successfully when rescan has reached the tip, or
+ // previous block is no longer on the chain due to a reorg
+ break;
+ }
+
+ // increment block and verification progress
+ block_hash = locked_chain->getBlockHash(++*block_height);
+ progress_current = chain().guessVerificationProgress(block_hash);
+
+ // handle updated tip hash
+ const uint256 prev_tip_hash = tip_hash;
+ tip_hash = locked_chain->getBlockHash(*tip_height);
+ if (stop_block.IsNull() && prev_tip_hash != tip_hash) {
// in case the tip has changed, update progress max
- progress_end = GuessVerificationProgress(chainParams.TxData(), tip);
+ progress_end = chain().guessVerificationProgress(tip_hash);
}
}
}
ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), 100); // hide progress dialog in GUI
- if (pindex && fAbortRescan) {
- WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", pindex->nHeight, progress_current);
- return ScanResult::USER_ABORT;
- } else if (pindex && ShutdownRequested()) {
- WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", pindex->nHeight, progress_current);
- return ScanResult::USER_ABORT;
+ if (block_height && fAbortRescan) {
+ WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", *block_height, progress_current);
+ result.status = ScanResult::USER_ABORT;
+ } else if (block_height && ShutdownRequested()) {
+ WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", *block_height, progress_current);
+ result.status = ScanResult::USER_ABORT;
}
}
- if (failed_block) {
- return ScanResult::FAILURE;
- } else {
- return ScanResult::SUCCESS;
- }
+ return result;
}
void CWallet::ReacceptWalletTransactions()
@@ -2573,6 +2651,7 @@ static bool IsCurrentForAntiFeeSniping(interfaces::Chain::Lock& locked_chain)
*/
static uint32_t GetLocktimeForNewTransaction(interfaces::Chain::Lock& locked_chain)
{
+ uint32_t const height = locked_chain.getHeight().get_value_or(-1);
uint32_t locktime;
// Discourage fee sniping.
//
@@ -2595,7 +2674,7 @@ static uint32_t GetLocktimeForNewTransaction(interfaces::Chain::Lock& locked_cha
// now we ensure code won't be written that makes assumptions about
// nLockTime that preclude a fix later.
if (IsCurrentForAntiFeeSniping(locked_chain)) {
- locktime = chainActive.Height();
+ locktime = height;
// Secondly occasionally randomly pick a nLockTime even further back, so
// that transactions that are delayed after signing for whatever reason,
@@ -2609,7 +2688,7 @@ static uint32_t GetLocktimeForNewTransaction(interfaces::Chain::Lock& locked_cha
// unique "nLockTime fingerprint", set nLockTime to a constant.
locktime = 0;
}
- assert(locktime <= (unsigned int)chainActive.Height());
+ assert(locktime <= height);
assert(locktime < LOCKTIME_THRESHOLD);
return locktime;
}
@@ -2850,7 +2929,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
txNew.vin.push_back(CTxIn(coin.outpoint,CScript()));
}
- nBytes = CalculateMaximumSignedTxSize(txNew, this, coin_control.fAllowWatchOnly);
+ nBytes = CalculateMaximumSignedTxSize(CTransaction(txNew), this, coin_control.fAllowWatchOnly);
if (nBytes < 0) {
strFailReason = _("Signing transaction failed");
return false;
@@ -3089,7 +3168,8 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
{
LOCK(cs_KeyStore);
// This wallet is in its first run if all of these are empty
- fFirstRunRet = mapKeys.empty() && mapCryptedKeys.empty() && mapWatchKeys.empty() && setWatchOnly.empty() && mapScripts.empty() && !IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
+ fFirstRunRet = mapKeys.empty() && mapCryptedKeys.empty() && mapWatchKeys.empty() && setWatchOnly.empty() && mapScripts.empty()
+ && !IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET);
}
if (nLoadWalletRet != DBErrors::LOAD_OK)
@@ -3158,7 +3238,7 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& s
{
bool fUpdated = false;
{
- LOCK(cs_wallet); // mapAddressBook
+ LOCK(cs_wallet);
std::map<CTxDestination, CAddressBookData>::iterator mi = mapAddressBook.find(address);
fUpdated = mi != mapAddressBook.end();
mapAddressBook[address].name = strName;
@@ -3175,7 +3255,7 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& s
bool CWallet::DelAddressBook(const CTxDestination& address)
{
{
- LOCK(cs_wallet); // mapAddressBook
+ LOCK(cs_wallet);
// Delete destdata tuples associated with address
std::string strAddress = EncodeDestination(address);
@@ -3274,7 +3354,7 @@ void CWallet::LoadKeyPool(int64_t nIndex, const CKeyPool &keypool)
bool CWallet::TopUpKeyPool(unsigned int kpSize)
{
- if (IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
+ if (!CanGenerateKeys()) {
return false;
}
{
@@ -3327,6 +3407,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
WalletLogPrintf("keypool added %d keys (%d internal), size=%u (%u internal)\n", missingInternal + missingExternal, missingInternal, setInternalKeyPool.size() + setExternalKeyPool.size() + set_pre_split_keypool.size(), setInternalKeyPool.size());
}
}
+ NotifyCanGetAddressesChanged();
return true;
}
@@ -3371,6 +3452,7 @@ bool CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRe
m_pool_key_to_index.erase(keypool.vchPubKey.GetID());
WalletLogPrintf("keypool reserve %d\n", nIndex);
}
+ NotifyCanGetAddressesChanged();
return true;
}
@@ -3395,13 +3477,14 @@ void CWallet::ReturnKey(int64_t nIndex, bool fInternal, const CPubKey& pubkey)
setExternalKeyPool.insert(nIndex);
}
m_pool_key_to_index[pubkey.GetID()] = nIndex;
+ NotifyCanGetAddressesChanged();
}
WalletLogPrintf("keypool return %d\n", nIndex);
}
bool CWallet::GetKeyFromPool(CPubKey& result, bool internal)
{
- if (IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
+ if (!CanGetAddresses(internal)) {
return false;
}
@@ -3602,6 +3685,10 @@ std::set<CTxDestination> CWallet::GetLabelAddresses(const std::string& label) co
bool CReserveKey::GetReservedKey(CPubKey& pubkey, bool internal)
{
+ if (!pwallet->CanGetAddresses(internal)) {
+ return false;
+ }
+
if (nIndex == -1)
{
CKeyPool keypool;
@@ -3718,11 +3805,12 @@ void CWallet::GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<C
}
// map in which we'll infer heights of other keys
- CBlockIndex *pindexMax = chainActive[std::max(0, chainActive.Height() - 144)]; // the tip can be reorganized; use a 144-block safety margin
- std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock;
+ const Optional<int> tip_height = locked_chain.getHeight();
+ const int max_height = tip_height && *tip_height > 144 ? *tip_height - 144 : 0; // the tip can be reorganized; use a 144-block safety margin
+ std::map<CKeyID, int> mapKeyFirstBlock;
for (const CKeyID &keyid : GetKeys()) {
if (mapKeyBirth.count(keyid) == 0)
- mapKeyFirstBlock[keyid] = pindexMax;
+ mapKeyFirstBlock[keyid] = max_height;
}
// if there are no such keys, we're done
@@ -3733,17 +3821,15 @@ void CWallet::GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<C
for (const auto& entry : mapWallet) {
// iterate over all wallet transactions...
const CWalletTx &wtx = entry.second;
- CBlockIndex* pindex = LookupBlockIndex(wtx.hashBlock);
- if (pindex && chainActive.Contains(pindex)) {
+ if (Optional<int> height = locked_chain.getBlockHeight(wtx.hashBlock)) {
// ... which are already in a block
- int nHeight = pindex->nHeight;
for (const CTxOut &txout : wtx.tx->vout) {
// iterate over all their outputs
for (const auto &keyid : GetAffectedKeys(txout.scriptPubKey, *this)) {
// ... and all their affected keys
- std::map<CKeyID, CBlockIndex*>::iterator rit = mapKeyFirstBlock.find(keyid);
- if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->nHeight)
- rit->second = pindex;
+ std::map<CKeyID, int>::iterator rit = mapKeyFirstBlock.find(keyid);
+ if (rit != mapKeyFirstBlock.end() && *height < rit->second)
+ rit->second = *height;
}
}
}
@@ -3751,7 +3837,7 @@ void CWallet::GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<C
// Extract block timestamps for those keys
for (const auto& entry : mapKeyFirstBlock)
- mapKeyBirth[entry.first] = entry.second->GetBlockTime() - TIMESTAMP_WINDOW; // block times can be 2h off
+ mapKeyBirth[entry.first] = locked_chain.getBlockTime(entry.second) - TIMESTAMP_WINDOW; // block times can be 2h off
}
/**
@@ -3779,7 +3865,8 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const
{
unsigned int nTimeSmart = wtx.nTimeReceived;
if (!wtx.hashUnset()) {
- if (const CBlockIndex* pindex = LookupBlockIndex(wtx.hashBlock)) {
+ int64_t blocktime;
+ if (chain().findBlock(wtx.hashBlock, nullptr /* block */, &blocktime)) {
int64_t latestNow = wtx.nTimeReceived;
int64_t latestEntry = 0;
@@ -3805,7 +3892,6 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const
}
}
- int64_t blocktime = pindex->GetBlockTime();
nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
} else {
WalletLogPrintf("%s: found %s in block %s not in index\n", __func__, wtx.GetHash().ToString(), wtx.hashBlock.ToString());
@@ -3853,7 +3939,6 @@ bool CWallet::GetDestData(const CTxDestination &dest, const std::string &key, st
std::vector<std::string> CWallet::GetDestValues(const std::string& prefix) const
{
- LOCK(cs_wallet);
std::vector<std::string> values;
for (const auto& address : mapAddressBook) {
for (const auto& data : address.second.destdata) {
@@ -3911,6 +3996,9 @@ bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, b
return false;
}
+ // Keep same database environment instance across Verify/Recover calls below.
+ std::unique_ptr<WalletDatabase> database = WalletDatabase::Create(wallet_path);
+
try {
if (!WalletBatch::VerifyEnvironment(wallet_path, error_string)) {
return false;
@@ -4054,20 +4142,22 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
if ((wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
//selective allow to set flags
walletInstance->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
+ } else if (wallet_creation_flags & WALLET_FLAG_BLANK_WALLET) {
+ walletInstance->SetWalletFlag(WALLET_FLAG_BLANK_WALLET);
} else {
// generate a new seed
CPubKey seed = walletInstance->GenerateNewSeed();
walletInstance->SetHDSeed(seed);
- }
+ } // Otherwise, do not generate a new seed
// Top up the keypool
- if (!walletInstance->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !walletInstance->TopUpKeyPool()) {
+ if (walletInstance->CanGenerateKeys() && !walletInstance->TopUpKeyPool()) {
InitError(_("Unable to generate initial keys"));
return nullptr;
}
auto locked_chain = chain.assumeLocked(); // Temporary. Removed in upcoming lock cleanup
- walletInstance->ChainStateFlushed(chainActive.GetLocator());
+ walletInstance->ChainStateFlushed(locked_chain->getTipLocator());
} else if (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS) {
// Make it impossible to disable private keys after creation
InitError(strprintf(_("Error loading %s: Private keys can only be disabled during creation"), walletFile));
@@ -4154,58 +4244,67 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
// Try to top up keypool. No-op if the wallet is locked.
walletInstance->TopUpKeyPool();
- LockAnnotation lock(::cs_main); // Temporary, for FindForkInGlobalIndex below. Removed in upcoming commit.
auto locked_chain = chain.lock();
LOCK(walletInstance->cs_wallet);
- CBlockIndex *pindexRescan = chainActive.Genesis();
+ int rescan_height = 0;
if (!gArgs.GetBoolArg("-rescan", false))
{
WalletBatch batch(*walletInstance->database);
CBlockLocator locator;
- if (batch.ReadBestBlock(locator))
- pindexRescan = FindForkInGlobalIndex(chainActive, locator);
+ if (batch.ReadBestBlock(locator)) {
+ if (const Optional<int> fork_height = locked_chain->findLocatorFork(locator)) {
+ rescan_height = *fork_height;
+ }
+ }
}
- walletInstance->m_last_block_processed = chainActive.Tip();
+ const Optional<int> tip_height = locked_chain->getHeight();
+ if (tip_height) {
+ walletInstance->m_last_block_processed = locked_chain->getBlockHash(*tip_height);
+ } else {
+ walletInstance->m_last_block_processed.SetNull();
+ }
- if (chainActive.Tip() && chainActive.Tip() != pindexRescan)
+ if (tip_height && *tip_height != rescan_height)
{
//We can't rescan beyond non-pruned blocks, stop and throw an error
//this might happen if a user uses an old wallet within a pruned node
// or if he ran -disablewallet for a longer time, then decided to re-enable
if (fPruneMode)
{
- CBlockIndex *block = chainActive.Tip();
- while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA) && block->pprev->nTx > 0 && pindexRescan != block)
- block = block->pprev;
+ int block_height = *tip_height;
+ while (block_height > 0 && locked_chain->haveBlockOnDisk(block_height - 1) && rescan_height != block_height) {
+ --block_height;
+ }
- if (pindexRescan != block) {
+ if (rescan_height != block_height) {
InitError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)"));
return nullptr;
}
}
uiInterface.InitMessage(_("Rescanning..."));
- walletInstance->WalletLogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight);
+ walletInstance->WalletLogPrintf("Rescanning last %i blocks (from block %i)...\n", *tip_height - rescan_height, rescan_height);
// No need to read and scan block if block was created before
// our wallet birthday (as adjusted for block time variability)
- while (pindexRescan && walletInstance->nTimeFirstKey && (pindexRescan->GetBlockTime() < (walletInstance->nTimeFirstKey - TIMESTAMP_WINDOW))) {
- pindexRescan = chainActive.Next(pindexRescan);
+ if (walletInstance->nTimeFirstKey) {
+ if (Optional<int> first_block = locked_chain->findFirstBlockWithTimeAndHeight(walletInstance->nTimeFirstKey - TIMESTAMP_WINDOW, rescan_height)) {
+ rescan_height = *first_block;
+ }
}
nStart = GetTimeMillis();
{
WalletRescanReserver reserver(walletInstance.get());
- const CBlockIndex *stop_block, *failed_block;
- if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, reserver, failed_block, stop_block, true))) {
+ if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(locked_chain->getBlockHash(rescan_height), {} /* stop block */, reserver, true /* update */).status)) {
InitError(_("Failed to rescan the wallet during initialization"));
return nullptr;
}
}
walletInstance->WalletLogPrintf("Rescan completed in %15dms\n", GetTimeMillis() - nStart);
- walletInstance->ChainStateFlushed(chainActive.GetLocator());
+ walletInstance->ChainStateFlushed(locked_chain->getTipLocator());
walletInstance->database->IncrementUpdateCounter();
// Restore wallet transaction metadata after -zapwallettxes=1
@@ -4282,10 +4381,10 @@ CWalletKey::CWalletKey(int64_t nExpires)
nTimeExpires = nExpires;
}
-void CMerkleTx::SetMerkleBranch(const CBlockIndex* pindex, int posInBlock)
+void CMerkleTx::SetMerkleBranch(const uint256& block_hash, int posInBlock)
{
// Update the tx's hashBlock
- hashBlock = pindex->GetBlockHash();
+ hashBlock = block_hash;
// set the position of the transaction in the block
nIndex = posInBlock;
@@ -4298,12 +4397,7 @@ int CMerkleTx::GetDepthInMainChain(interfaces::Chain::Lock& locked_chain) const
AssertLockHeld(cs_main);
- // Find the block it claims to be in
- CBlockIndex* pindex = LookupBlockIndex(hashBlock);
- if (!pindex || !chainActive.Contains(pindex))
- return 0;
-
- return ((nIndex == -1) ? (-1) : 1) * (chainActive.Height() - pindex->nHeight + 1);
+ return locked_chain.getBlockDepth(hashBlock) * (nIndex == -1 ? -1 : 1);
}
int CMerkleTx::GetBlocksToMaturity(interfaces::Chain::Lock& locked_chain) const
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 6872fbad2d..5846ac0f3e 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -35,8 +35,8 @@
#include <vector>
//! Responsible for reading and validating the -wallet arguments and verifying the wallet database.
-// This function will perform salvage on the wallet if requested, as long as only one wallet is
-// being loaded (WalletParameterInteraction forbids -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet).
+//! This function will perform salvage on the wallet if requested, as long as only one wallet is
+//! being loaded (WalletParameterInteraction forbids -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet).
bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files);
//! Load wallet databases.
@@ -55,10 +55,10 @@ void StopWallets();
void UnloadWallets();
//! Explicitly unload and delete the wallet.
-// Blocks the current thread after signaling the unload intent so that all
-// wallet clients release the wallet.
-// Note that, when blocking is not required, the wallet is implicitly unloaded
-// by the shared pointer deleter.
+//! Blocks the current thread after signaling the unload intent so that all
+//! wallet clients release the wallet.
+//! Note that, when blocking is not required, the wallet is implicitly unloaded
+//! by the shared pointer deleter.
void UnloadWallet(std::shared_ptr<CWallet>&& wallet);
bool AddWallet(const std::shared_ptr<CWallet>& wallet);
@@ -66,6 +66,7 @@ bool RemoveWallet(const std::shared_ptr<CWallet>& wallet);
bool HasWallets();
std::vector<std::shared_ptr<CWallet>> GetWallets();
std::shared_ptr<CWallet> GetWallet(const std::string& name);
+std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, std::string& error, std::string& warning);
//! Default for -keypool
static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000;
@@ -95,7 +96,6 @@ static const bool DEFAULT_DISABLE_WALLET = false;
//! Pre-calculated constants for input size estimation in *virtual size*
static constexpr size_t DUMMY_NESTED_P2WPKH_INPUT_SIZE = 91;
-class CBlockIndex;
class CCoinControl;
class COutput;
class CReserveKey;
@@ -137,9 +137,21 @@ enum WalletFlags : uint64_t {
// will enforce the rule that the wallet can't contain any private keys (only watch-only/pubkeys)
WALLET_FLAG_DISABLE_PRIVATE_KEYS = (1ULL << 32),
+
+ //! Flag set when a wallet contains no HD seed and no private keys, scripts,
+ //! addresses, and other watch only things, and is therefore "blank."
+ //!
+ //! The only function this flag serves is to distinguish a blank wallet from
+ //! a newly created wallet when the wallet database is loaded, to avoid
+ //! initialization that should only happen on first run.
+ //!
+ //! This flag is also a mandatory flag to prevent previous versions of
+ //! bitcoin from opening the wallet, thinking it was newly created, and
+ //! then improperly reinitializing it.
+ WALLET_FLAG_BLANK_WALLET = (1ULL << 33),
};
-static constexpr uint64_t g_known_wallet_flags = WALLET_FLAG_DISABLE_PRIVATE_KEYS;
+static constexpr uint64_t g_known_wallet_flags = WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET;
/** A key pool entry */
class CKeyPool
@@ -287,7 +299,7 @@ public:
READWRITE(nIndex);
}
- void SetMerkleBranch(const CBlockIndex* pIndex, int posInBlock);
+ void SetMerkleBranch(const uint256& block_hash, int posInBlock);
/**
* Return depth of transaction in blockchain:
@@ -588,8 +600,8 @@ public:
int64_t nTimeCreated;
int64_t nTimeExpires;
std::string strComment;
- //! todo: add something to note what created it (user, getnewaddress, change)
- //! maybe should have a map<string, string> property map
+ // todo: add something to note what created it (user, getnewaddress, change)
+ // maybe should have a map<string, string> property map
explicit CWalletKey(int64_t nExpires=0);
@@ -667,7 +679,7 @@ private:
* Abandoned state should probably be more carefully tracked via different
* posInBlock signals or by checking mempool presence when necessary.
*/
- bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const uint256& block_hash, int posInBlock, bool fUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/* Mark a transaction (and its in-wallet descendants) as conflicting with a particular block. */
void MarkConflicted(const uint256& hashBlock, const uint256& hashTx);
@@ -678,8 +690,8 @@ private:
void SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator>) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/* Used by TransactionAddedToMemorypool/BlockConnected/Disconnected/ScanForWalletTransactions.
- * Should be called with pindexBlock and posInBlock if this is for a transaction that is included in a block. */
- void SyncTransaction(const CTransactionRef& tx, const CBlockIndex *pindex = nullptr, int posInBlock = 0, bool update_tx = true) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ * Should be called with non-zero block_hash and posInBlock if this is for a transaction that is included in a block. */
+ void SyncTransaction(const CTransactionRef& tx, const uint256& block_hash, int posInBlock = 0, bool update_tx = true) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/* the HD chain data model (external chain counters) */
CHDChain hdChain;
@@ -723,10 +735,8 @@ private:
* Note that this is *not* how far we've processed, we may need some rescan
* to have seen all transactions in the chain, but is only used to track
* live BlockConnected callbacks.
- *
- * Protected by cs_main (see BlockUntilSyncedToCurrentChain)
*/
- const CBlockIndex* m_last_block_processed = nullptr;
+ uint256 m_last_block_processed;
public:
/*
@@ -791,7 +801,7 @@ public:
int64_t nOrderPosNext GUARDED_BY(cs_wallet) = 0;
uint64_t nAccountingEntryNumber = 0;
- std::map<CTxDestination, CAddressBookData> mapAddressBook;
+ std::map<CTxDestination, CAddressBookData> mapAddressBook GUARDED_BY(cs_wallet);
std::set<COutPoint> setLockedCoins GUARDED_BY(cs_wallet);
@@ -868,15 +878,15 @@ public:
bool LoadCScript(const CScript& redeemScript);
//! Adds a destination data tuple to the store, and saves it to disk
- bool AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value);
+ bool AddDestData(const CTxDestination& dest, const std::string& key, const std::string& value) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Erases a destination data tuple in the store and on disk
- bool EraseDestData(const CTxDestination &dest, const std::string &key);
+ bool EraseDestData(const CTxDestination& dest, const std::string& key) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Adds a destination data tuple to the store, without saving it to disk
- void LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value);
+ void LoadDestData(const CTxDestination& dest, const std::string& key, const std::string& value) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Look up a destination data tuple in the store, return true if found false otherwise
- bool GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) const;
+ bool GetDestData(const CTxDestination& dest, const std::string& key, std::string* value) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Get all destination values matching a prefix.
- std::vector<std::string> GetDestValues(const std::string& prefix) const;
+ std::vector<std::string> GetDestValues(const std::string& prefix) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Adds a watch-only address to the store, and saves it to disk.
bool AddWatchOnly(const CScript& dest, int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
@@ -887,7 +897,7 @@ public:
//! Holds a timestamp at which point the wallet is scheduled (externally) to be relocked. Caller must arrange for actual relocking to occur via Lock().
int64_t nRelockTime = 0;
- bool Unlock(const SecureString& strWalletPassphrase);
+ bool Unlock(const SecureString& strWalletPassphrase, bool accept_no_keys = false);
bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
bool EncryptWallet(const SecureString& strWalletPassphrase);
@@ -909,12 +919,22 @@ public:
void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override;
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update);
- enum class ScanResult {
- SUCCESS,
- FAILURE,
- USER_ABORT
+ struct ScanResult {
+ enum { SUCCESS, FAILURE, USER_ABORT } status = SUCCESS;
+
+ //! Hash and height of most recent block that was successfully scanned.
+ //! Unset if no blocks were scanned due to read errors or the chain
+ //! being empty.
+ uint256 last_scanned_block;
+ Optional<int> last_scanned_height;
+
+ //! Height of the most recent block that could not be scanned due to
+ //! read errors or pruning. Will be set if status is FAILURE, unset if
+ //! status is SUCCESS, and may or may not be set if status is
+ //! USER_ABORT.
+ uint256 last_failed_block;
};
- ScanResult ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, const CBlockIndex*& failed_block, const CBlockIndex*& stop_block, bool fUpdate = false);
+ ScanResult ScanForWalletTransactions(const uint256& first_block, const uint256& last_block, const WalletRescanReserver& reserver, bool fUpdate);
void TransactionRemovedFromMempool(const CTransactionRef &ptx) override;
void ReacceptWalletTransactions();
void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -1034,7 +1054,7 @@ public:
bool DelAddressBook(const CTxDestination& address);
- const std::string& GetLabelName(const CScript& scriptPubKey) const;
+ const std::string& GetLabelName(const CScript& scriptPubKey) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void GetScriptForMining(std::shared_ptr<CReserveScript> &script);
@@ -1087,6 +1107,9 @@ public:
/** Watch-only address added */
boost::signals2::signal<void (bool fHaveWatchOnly)> NotifyWatchonlyChanged;
+ /** Keypool has new keys */
+ boost::signals2::signal<void ()> NotifyCanGetAddressesChanged;
+
/** Inquire whether this wallet broadcasts transactions. */
bool GetBroadcastTransactions() const { return fBroadcastTransactions; }
/** Set whether this wallet broadcasts transactions. */
@@ -1122,6 +1145,12 @@ public:
/* Returns true if HD is enabled */
bool IsHDEnabled() const;
+ /* Returns true if the wallet can generate new keys */
+ bool CanGenerateKeys();
+
+ /* Returns true if the wallet can give out new addresses. This means it has keys in the keypool or can generate new keys */
+ bool CanGetAddresses(bool internal = false);
+
/* Generates a new HD seed (will not be activated) */
CPubKey GenerateNewSeed();
@@ -1159,6 +1188,9 @@ public:
/** set a single wallet flag */
void SetWalletFlag(uint64_t flags);
+ /** Unsets a single wallet flag */
+ void UnsetWalletFlag(uint64_t flag);
+
/** check if a certain wallet flag is set */
bool IsWalletFlagSet(uint64_t flag);
diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp
new file mode 100644
index 0000000000..628f3fe803
--- /dev/null
+++ b/src/wallet/wallettool.cpp
@@ -0,0 +1,138 @@
+// Copyright (c) 2016-2018 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <base58.h>
+#include <fs.h>
+#include <interfaces/chain.h>
+#include <util/system.h>
+#include <wallet/wallet.h>
+#include <wallet/walletutil.h>
+
+namespace WalletTool {
+
+// The standard wallet deleter function blocks on the validation interface
+// queue, which doesn't exist for the bitcoin-wallet. Define our own
+// deleter here.
+static void WalletToolReleaseWallet(CWallet* wallet)
+{
+ wallet->WalletLogPrintf("Releasing wallet\n");
+ wallet->Flush();
+ delete wallet;
+}
+
+static std::shared_ptr<CWallet> CreateWallet(const std::string& name, const fs::path& path)
+{
+ if (fs::exists(path)) {
+ fprintf(stderr, "Error: File exists already\n");
+ return nullptr;
+ }
+ // dummy chain interface
+ auto chain = interfaces::MakeChain();
+ std::shared_ptr<CWallet> wallet_instance(new CWallet(*chain, WalletLocation(name), WalletDatabase::Create(path)), WalletToolReleaseWallet);
+ bool first_run = true;
+ DBErrors load_wallet_ret = wallet_instance->LoadWallet(first_run);
+ if (load_wallet_ret != DBErrors::LOAD_OK) {
+ fprintf(stderr, "Error creating %s", name.c_str());
+ return nullptr;
+ }
+
+ wallet_instance->SetMinVersion(FEATURE_HD_SPLIT);
+
+ // generate a new HD seed
+ CPubKey seed = wallet_instance->GenerateNewSeed();
+ wallet_instance->SetHDSeed(seed);
+
+ fprintf(stdout, "Topping up keypool...\n");
+ wallet_instance->TopUpKeyPool();
+ return wallet_instance;
+}
+
+static std::shared_ptr<CWallet> LoadWallet(const std::string& name, const fs::path& path)
+{
+ if (!fs::exists(path)) {
+ fprintf(stderr, "Error: Wallet files does not exist\n");
+ return nullptr;
+ }
+
+ // dummy chain interface
+ auto chain = interfaces::MakeChain();
+ std::shared_ptr<CWallet> wallet_instance(new CWallet(*chain, WalletLocation(name), WalletDatabase::Create(path)), WalletToolReleaseWallet);
+ DBErrors load_wallet_ret;
+ try {
+ bool first_run;
+ load_wallet_ret = wallet_instance->LoadWallet(first_run);
+ } catch (const std::runtime_error) {
+ fprintf(stderr, "Error loading %s. Is wallet being used by another process?\n", name.c_str());
+ return nullptr;
+ }
+
+ if (load_wallet_ret != DBErrors::LOAD_OK) {
+ wallet_instance = nullptr;
+ if (load_wallet_ret == DBErrors::CORRUPT) {
+ fprintf(stderr, "Error loading %s: Wallet corrupted", name.c_str());
+ return nullptr;
+ } else if (load_wallet_ret == DBErrors::NONCRITICAL_ERROR) {
+ fprintf(stderr, "Error reading %s! All keys read correctly, but transaction data"
+ " or address book entries might be missing or incorrect.",
+ name.c_str());
+ } else if (load_wallet_ret == DBErrors::TOO_NEW) {
+ fprintf(stderr, "Error loading %s: Wallet requires newer version of %s",
+ name.c_str(), PACKAGE_NAME);
+ return nullptr;
+ } else if (load_wallet_ret == DBErrors::NEED_REWRITE) {
+ fprintf(stderr, "Wallet needed to be rewritten: restart %s to complete", PACKAGE_NAME);
+ return nullptr;
+ } else {
+ fprintf(stderr, "Error loading %s", name.c_str());
+ return nullptr;
+ }
+ }
+
+ return wallet_instance;
+}
+
+static void WalletShowInfo(CWallet* wallet_instance)
+{
+ LOCK(wallet_instance->cs_wallet);
+
+ fprintf(stdout, "Wallet info\n===========\n");
+ fprintf(stdout, "Encrypted: %s\n", wallet_instance->IsCrypted() ? "yes" : "no");
+ fprintf(stdout, "HD (hd seed available): %s\n", wallet_instance->GetHDChain().seed_id.IsNull() ? "no" : "yes");
+ fprintf(stdout, "Keypool Size: %u\n", wallet_instance->GetKeyPoolSize());
+ fprintf(stdout, "Transactions: %zu\n", wallet_instance->mapWallet.size());
+ fprintf(stdout, "Address Book: %zu\n", wallet_instance->mapAddressBook.size());
+}
+
+bool ExecuteWalletToolFunc(const std::string& command, const std::string& name)
+{
+ fs::path path = fs::absolute(name, GetWalletDir());
+
+ if (command == "create") {
+ std::shared_ptr<CWallet> wallet_instance = CreateWallet(name, path);
+ if (wallet_instance) {
+ WalletShowInfo(wallet_instance.get());
+ wallet_instance->Flush();
+ }
+ } else if (command == "info") {
+ if (!fs::exists(path)) {
+ fprintf(stderr, "Error: no wallet file at %s\n", name.c_str());
+ return false;
+ }
+ std::string error;
+ if (!WalletBatch::VerifyEnvironment(path, error)) {
+ fprintf(stderr, "Error loading %s. Is wallet being used by other process?\n", name.c_str());
+ return false;
+ }
+ std::shared_ptr<CWallet> wallet_instance = LoadWallet(name, path);
+ if (!wallet_instance) return false;
+ WalletShowInfo(wallet_instance.get());
+ wallet_instance->Flush();
+ } else {
+ fprintf(stderr, "Invalid command: %s\n", command.c_str());
+ return false;
+ }
+
+ return true;
+}
+} // namespace WalletTool
diff --git a/src/wallet/wallettool.h b/src/wallet/wallettool.h
new file mode 100644
index 0000000000..5b06fd1792
--- /dev/null
+++ b/src/wallet/wallettool.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2016-2018 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_WALLET_WALLETTOOL_H
+#define BITCOIN_WALLET_WALLETTOOL_H
+
+#include <script/ismine.h>
+#include <wallet/wallet.h>
+
+namespace WalletTool {
+
+std::shared_ptr<CWallet> CreateWallet(const std::string& name, const fs::path& path);
+std::shared_ptr<CWallet> LoadWallet(const std::string& name, const fs::path& path);
+void WalletShowInfo(CWallet* wallet_instance);
+bool ExecuteWalletToolFunc(const std::string& command, const std::string& file);
+
+} // namespace WalletTool
+
+#endif // BITCOIN_WALLET_WALLETTOOL_H
diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp
index 15d4ac1b89..ba89d1401d 100644
--- a/src/zmq/zmqpublishnotifier.cpp
+++ b/src/zmq/zmqpublishnotifier.cpp
@@ -101,6 +101,7 @@ bool CZMQAbstractPublishNotifier::Initialize(void *pcontext)
else
{
LogPrint(BCLog::ZMQ, "zmq: Reusing socket for address %s\n", address);
+ LogPrint(BCLog::ZMQ, "zmq: Outbound message high water mark for %s at %s is %d\n", type, address, outbound_message_high_water_mark);
psocket = i->second->psocket;
mapPublishNotifiers.insert(std::make_pair(address, this));
diff --git a/src/zmq/zmqrpc.cpp b/src/zmq/zmqrpc.cpp
index d3eab46e5f..a34968ef7d 100644
--- a/src/zmq/zmqrpc.cpp
+++ b/src/zmq/zmqrpc.cpp
@@ -18,9 +18,9 @@ UniValue getzmqnotifications(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 0) {
throw std::runtime_error(
RPCHelpMan{"getzmqnotifications",
- "\nReturns information about the active ZeroMQ notifications.\n", {}}
- .ToString() +
- "\nResult:\n"
+ "\nReturns information about the active ZeroMQ notifications.\n",
+ {},
+ RPCResult{
"[\n"
" { (json object)\n"
" \"type\": \"pubhashtx\", (string) Type of notification\n"
@@ -29,10 +29,12 @@ UniValue getzmqnotifications(const JSONRPCRequest& request)
" },\n"
" ...\n"
"]\n"
- "\nExamples:\n"
- + HelpExampleCli("getzmqnotifications", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getzmqnotifications", "")
+ HelpExampleRpc("getzmqnotifications", "")
- );
+ },
+ }.ToString());
}
UniValue result(UniValue::VARR);
diff --git a/test/README.md b/test/README.md
index b5cbe1aff3..9d4351b1de 100644
--- a/test/README.md
+++ b/test/README.md
@@ -175,7 +175,28 @@ cat /tmp/user/1000/testo9vsdjo3/node1/regtest/bitcoind.pid
gdb /home/example/bitcoind <pid>
```
-Note: gdb attach step may require `sudo`
+Note: gdb attach step may require ptrace_scope to be modified, or `sudo` preceding the `gdb`.
+See this link for considerations: https://www.kernel.org/doc/Documentation/security/Yama.txt
+
+##### Profiling
+
+An easy way to profile node performance during functional tests is provided
+for Linux platforms using `perf`.
+
+Perf will sample the running node and will generate profile data in the node's
+datadir. The profile data can then be presented using `perf report` or a graphical
+tool like [hotspot](https://github.com/KDAB/hotspot).
+
+To generate a profile during test suite runs, use the `--perf` flag.
+
+To see render the output to text, run
+
+```sh
+perf report -i /path/to/datadir/send-big-msgs.perf.data.xxxx --stdio | c++filt | less
+```
+
+For ways to generate more granular profiles, see the README in
+[test/functional](/test/functional).
### Util tests
diff --git a/test/functional/README.md b/test/functional/README.md
index bce0d5db2e..5e3009e6af 100644
--- a/test/functional/README.md
+++ b/test/functional/README.md
@@ -26,7 +26,7 @@ don't have test cases for.
The Travis linter also checks this, but [possibly not in all cases](https://github.com/bitcoin/bitcoin/pull/14884#discussion_r239585126).
- See [the python lint script](/test/lint/lint-python.sh) that checks for violations that
could lead to bugs and issues in the test code.
-- Avoid wildcard imports where possible
+- Avoid wildcard imports
- Use a module-level docstring to describe what the test is testing, and how it
is testing it.
- When subclassing the BitcoinTestFramwork, place overrides for the
@@ -43,6 +43,7 @@ don't have test cases for.
- `mining` for tests for mining features, eg `mining_prioritisetransaction.py`
- `p2p` for tests that explicitly test the p2p interface, eg `p2p_disconnect_ban.py`
- `rpc` for tests for individual RPC methods or features, eg `rpc_listtransactions.py`
+ - `tool` for tests for tools, eg `tool_wallet.py`
- `wallet` for tests for wallet features, eg `wallet_keypool.py`
- use an underscore to separate words
- exception: for tests for specific RPCs or command line options which don't include underscores, name the test after the exact RPC or argument name, eg `rpc_decodescript.py`, not `rpc_decode_script.py`
@@ -122,3 +123,36 @@ Helpers for script.py
#### [test_framework/blocktools.py](test_framework/blocktools.py)
Helper functions for creating blocks and transactions.
+
+### Benchmarking with perf
+
+An easy way to profile node performance during functional tests is provided
+for Linux platforms using `perf`.
+
+Perf will sample the running node and will generate profile data in the node's
+datadir. The profile data can then be presented using `perf report` or a graphical
+tool like [hotspot](https://github.com/KDAB/hotspot).
+
+There are two ways of invoking perf: one is to use the `--perf` flag when
+running tests, which will profile each node during the entire test run: perf
+begins to profile when the node starts and ends when it shuts down. The other
+way is the use the `profile_with_perf` context manager, e.g.
+
+```python
+with node.profile_with_perf("send-big-msgs"):
+ # Perform activity on the node you're interested in profiling, e.g.:
+ for _ in range(10000):
+ node.p2p.send_message(some_large_message)
+```
+
+To see useful textual output, run
+
+```sh
+perf report -i /path/to/datadir/send-big-msgs.perf.data.xxxx --stdio | c++filt | less
+```
+
+#### See also:
+
+- [Installing perf](https://askubuntu.com/q/50145)
+- [Perf examples](http://www.brendangregg.com/perf.html)
+- [Hotspot](https://github.com/KDAB/hotspot): a GUI for perf output analysis
diff --git a/test/functional/example_test.py b/test/functional/example_test.py
index be3544ee74..f367e4fca8 100755
--- a/test/functional/example_test.py
+++ b/test/functional/example_test.py
@@ -13,7 +13,7 @@ is testing and *how* it's being tested
# libraries then local imports).
from collections import defaultdict
-# Avoid wildcard * imports if possible
+# Avoid wildcard * imports
from test_framework.blocktools import (create_block, create_coinbase)
from test_framework.messages import CInv
from test_framework.mininode import (
diff --git a/test/functional/feature_pruning.py b/test/functional/feature_pruning.py
index 9a3f4fae45..3e1ba88f0a 100755
--- a/test/functional/feature_pruning.py
+++ b/test/functional/feature_pruning.py
@@ -320,7 +320,7 @@ class PruneTest(BitcoinTestFramework):
if has_block(3):
raise AssertionError("blk00003.dat is still there, should be pruned by now")
- # stop node, start back up with auto-prune at 550MB, make sure still runs
+ # stop node, start back up with auto-prune at 550 MiB, make sure still runs
self.stop_node(node_number)
self.start_node(node_number, extra_args=["-prune=550"])
diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py
index 4bcdf9af55..1efc50e71f 100755
--- a/test/functional/feature_segwit.py
+++ b/test/functional/feature_segwit.py
@@ -43,22 +43,26 @@ class SegWitTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 3
# This test tests SegWit both pre and post-activation, so use the normal BIP9 activation.
+ # TODO: remove -txindex. Currently required for getrawtransaction call.
self.extra_args = [
[
"-rpcserialversion=0",
"-vbparams=segwit:0:999999999999",
"-addresstype=legacy",
+ "-txindex"
],
[
"-blockversion=4",
"-rpcserialversion=1",
"-vbparams=segwit:0:999999999999",
"-addresstype=legacy",
+ "-txindex"
],
[
"-blockversion=536870915",
"-vbparams=segwit:0:999999999999",
"-addresstype=legacy",
+ "-txindex"
],
]
diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py
index afa9de580f..f850a54462 100755
--- a/test/functional/interface_rest.py
+++ b/test/functional/interface_rest.py
@@ -41,7 +41,8 @@ class RESTTest (BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
- self.extra_args = [["-rest"], []]
+ # TODO: remove -txindex. Currently required for getrawtransaction call.
+ self.extra_args = [["-rest", "-txindex"], []]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
@@ -198,9 +199,19 @@ class RESTTest (BitcoinTestFramework):
self.nodes[0].generate(1) # generate block to not affect upcoming tests
self.sync_all()
- self.log.info("Test the /block and /headers URIs")
+ self.log.info("Test the /block, /blockhashbyheight and /headers URIs")
bb_hash = self.nodes[0].getbestblockhash()
+ # Check result if block does not exists
+ assert_equal(self.test_rest_request('/headers/1/0000000000000000000000000000000000000000000000000000000000000000'), [])
+ self.test_rest_request('/block/0000000000000000000000000000000000000000000000000000000000000000', status=404, ret_type=RetType.OBJ)
+
+ # Check result if block is not in the active chain
+ self.nodes[0].invalidateblock(bb_hash)
+ assert_equal(self.test_rest_request('/headers/1/{}'.format(bb_hash)), [])
+ self.test_rest_request('/block/{}'.format(bb_hash))
+ self.nodes[0].reconsiderblock(bb_hash)
+
# Check binary format
response = self.test_rest_request("/block/{}".format(bb_hash), req_type=ReqType.BIN, ret_type=RetType.OBJ)
assert_greater_than(int(response.getheader('content-length')), 80)
@@ -227,6 +238,23 @@ class RESTTest (BitcoinTestFramework):
# Check json format
block_json_obj = self.test_rest_request("/block/{}".format(bb_hash))
assert_equal(block_json_obj['hash'], bb_hash)
+ assert_equal(self.test_rest_request("/blockhashbyheight/{}".format(block_json_obj['height']))['blockhash'], bb_hash)
+
+ # Check hex/bin format
+ resp_hex = self.test_rest_request("/blockhashbyheight/{}".format(block_json_obj['height']), req_type=ReqType.HEX, ret_type=RetType.OBJ)
+ assert_equal(resp_hex.read().decode('utf-8').rstrip(), bb_hash)
+ resp_bytes = self.test_rest_request("/blockhashbyheight/{}".format(block_json_obj['height']), req_type=ReqType.BIN, ret_type=RetType.BYTES)
+ blockhash = binascii.hexlify(resp_bytes[::-1]).decode('utf-8')
+ assert_equal(blockhash, bb_hash)
+
+ # Check invalid blockhashbyheight requests
+ resp = self.test_rest_request("/blockhashbyheight/abc", ret_type=RetType.OBJ, status=400)
+ assert_equal(resp.read().decode('utf-8').rstrip(), "Invalid height: abc")
+ resp = self.test_rest_request("/blockhashbyheight/1000000", ret_type=RetType.OBJ, status=404)
+ assert_equal(resp.read().decode('utf-8').rstrip(), "Block height out of range")
+ resp = self.test_rest_request("/blockhashbyheight/-1", ret_type=RetType.OBJ, status=400)
+ assert_equal(resp.read().decode('utf-8').rstrip(), "Invalid height: -1")
+ self.test_rest_request("/blockhashbyheight/", ret_type=RetType.OBJ, status=400)
# Compare with json block header
json_obj = self.test_rest_request("/headers/1/{}".format(bb_hash))
diff --git a/test/functional/p2p_invalid_messages.py b/test/functional/p2p_invalid_messages.py
index dbc5c5fff6..700fdf6e04 100755
--- a/test/functional/p2p_invalid_messages.py
+++ b/test/functional/p2p_invalid_messages.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2018 The Bitcoin Core developers
+# 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 node responses to invalid network messages."""
@@ -16,7 +16,7 @@ class msg_unrecognized:
command = b'badmsg'
- def __init__(self, str_data):
+ def __init__(self, *, str_data):
self.str_data = str_data.encode() if not isinstance(str_data, bytes) else str_data
def serialize(self):
@@ -26,19 +26,14 @@ class msg_unrecognized:
return "{}(data={})".format(self.command, self.str_data)
-class msg_nametoolong(msg_unrecognized):
-
- command = b'thisnameiswayyyyyyyyytoolong'
-
-
class InvalidMessagesTest(BitcoinTestFramework):
-
def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
def run_test(self):
"""
+ . Test msg header
0. Send a bunch of large (4MB) messages of an unrecognized type. Check to see
that it isn't an effective DoS against the node.
@@ -46,10 +41,12 @@ class InvalidMessagesTest(BitcoinTestFramework):
2. Send a few messages with an incorrect data size in the header, ensure the
messages are ignored.
-
- 3. Send an unrecognized message with a command name longer than 12 characters.
-
"""
+ self.test_magic_bytes()
+ self.test_checksum()
+ self.test_size()
+ self.test_command()
+
node = self.nodes[0]
self.node = node
node.add_p2p_connection(P2PDataStore())
@@ -64,7 +61,7 @@ class InvalidMessagesTest(BitcoinTestFramework):
# Send as large a message as is valid, ensure we aren't disconnected but
# also can't exhaust resources.
#
- msg_at_size = msg_unrecognized("b" * valid_data_limit)
+ msg_at_size = msg_unrecognized(str_data="b" * valid_data_limit)
assert len(msg_at_size.serialize()) == msg_limit
increase_allowed = 0.5
@@ -94,10 +91,10 @@ class InvalidMessagesTest(BitcoinTestFramework):
#
# Send an oversized message, ensure we're disconnected.
#
- msg_over_size = msg_unrecognized("b" * (valid_data_limit + 1))
+ msg_over_size = msg_unrecognized(str_data="b" * (valid_data_limit + 1))
assert len(msg_over_size.serialize()) == (msg_limit + 1)
- with node.assert_debug_log(["Oversized message from peer=0, disconnecting"]):
+ with node.assert_debug_log(["Oversized message from peer=4, disconnecting"]):
# An unknown message type (or *any* message type) over
# MAX_PROTOCOL_MESSAGE_LENGTH should result in a disconnect.
node.p2p.send_message(msg_over_size)
@@ -113,7 +110,7 @@ class InvalidMessagesTest(BitcoinTestFramework):
# Send messages with an incorrect data size in the header.
#
actual_size = 100
- msg = msg_unrecognized("b" * actual_size)
+ msg = msg_unrecognized(str_data="b" * actual_size)
# TODO: handle larger-than cases. I haven't been able to pin down what behavior to expect.
for wrong_size in (2, 77, 78, 79):
@@ -140,18 +137,59 @@ class InvalidMessagesTest(BitcoinTestFramework):
node.disconnect_p2ps()
node.add_p2p_connection(P2PDataStore())
- #
- # 3.
- #
- # Send a message with a too-long command name.
- #
- node.p2p.send_message(msg_nametoolong("foobar"))
- node.p2p.wait_for_disconnect(timeout=4)
-
# Node is still up.
conn = node.add_p2p_connection(P2PDataStore())
conn.sync_with_ping()
+ def test_magic_bytes(self):
+ conn = self.nodes[0].add_p2p_connection(P2PDataStore())
+ conn._on_data = lambda: None # Need to ignore all incoming messages from now, since they come with "invalid" magic bytes
+ conn.magic_bytes = b'\x00\x11\x22\x32'
+ with self.nodes[0].assert_debug_log(['PROCESSMESSAGE: INVALID MESSAGESTART ping']):
+ conn.send_message(messages.msg_ping(nonce=0xff))
+ conn.wait_for_disconnect(timeout=1)
+ self.nodes[0].disconnect_p2ps()
+
+ def test_checksum(self):
+ conn = self.nodes[0].add_p2p_connection(P2PDataStore())
+ with self.nodes[0].assert_debug_log(['ProcessMessages(badmsg, 2 bytes): CHECKSUM ERROR expected 78df0a04 was ffffffff']):
+ msg = conn.build_message(msg_unrecognized(str_data="d"))
+ cut_len = (
+ 4 + # magic
+ 12 + # command
+ 4 #len
+ )
+ # modify checksum
+ msg = msg[:cut_len] + b'\xff' * 4 + msg[cut_len + 4:]
+ self.nodes[0].p2p.send_raw_message(msg)
+ conn.sync_with_ping(timeout=1)
+ self.nodes[0].disconnect_p2ps()
+
+ def test_size(self):
+ conn = self.nodes[0].add_p2p_connection(P2PDataStore())
+ with self.nodes[0].assert_debug_log(['']):
+ msg = conn.build_message(msg_unrecognized(str_data="d"))
+ cut_len = (
+ 4 + # magic
+ 12 # command
+ )
+ # modify len to MAX_SIZE + 1
+ msg = msg[:cut_len] + struct.pack("<I", 0x02000000 + 1) + msg[cut_len + 4:]
+ self.nodes[0].p2p.send_raw_message(msg)
+ conn.wait_for_disconnect(timeout=1)
+ self.nodes[0].disconnect_p2ps()
+
+ def test_command(self):
+ conn = self.nodes[0].add_p2p_connection(P2PDataStore())
+ with self.nodes[0].assert_debug_log(['PROCESSMESSAGE: ERRORS IN HEADER']):
+ msg = msg_unrecognized(str_data="d")
+ msg.command = b'\xff' * 12
+ msg = conn.build_message(msg)
+ # Modify command
+ msg = msg[:7] + b'\x00' + msg[7 + 1:]
+ self.nodes[0].p2p.send_raw_message(msg)
+ conn.sync_with_ping(timeout=1)
+ self.nodes[0].disconnect_p2ps()
def _tweak_msg_data_size(self, message, wrong_size):
"""
@@ -174,6 +212,5 @@ class InvalidMessagesTest(BitcoinTestFramework):
return raw_msg_with_wrong_size
-
if __name__ == '__main__':
InvalidMessagesTest().main()
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index d95da227e5..8f8e89cf15 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -755,7 +755,7 @@ class SegWitTest(BitcoinTestFramework):
spend_tx.vin[0].scriptSig = CScript([p2wsh_pubkey, b'a'])
spend_tx.rehash()
with self.nodes[0].assert_debug_log(
- expected_msgs=('Not relaying invalid transaction {}'.format(spend_tx.hash), 'was not accepted: mandatory-script-verify-flag-failed (Script evaluated without error but finished with a false/empty top stack element)')):
+ expected_msgs=(spend_tx.hash, 'was not accepted: mandatory-script-verify-flag-failed (Script evaluated without error but finished with a false/empty top stack element)')):
test_transaction_acceptance(self.nodes[0], self.test_node, spend_tx, with_witness=False, accepted=False)
# Now put the witness script in the witness, should succeed after
diff --git a/test/functional/p2p_sendheaders.py b/test/functional/p2p_sendheaders.py
index c7ae57de86..7d7d251765 100755
--- a/test/functional/p2p_sendheaders.py
+++ b/test/functional/p2p_sendheaders.py
@@ -490,7 +490,7 @@ class SendHeadersTest(BitcoinTestFramework):
# Now announce a header that forks the last two blocks
tip = blocks[0].sha256
- height -= 1
+ height -= 2
blocks = []
# Create extra blocks for later
diff --git a/test/functional/rpc_deriveaddresses.py b/test/functional/rpc_deriveaddresses.py
new file mode 100755
index 0000000000..2cc5bc974b
--- /dev/null
+++ b/test/functional/rpc_deriveaddresses.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3
+# 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.
+"""Test the deriveaddresses rpc call."""
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal, assert_raises_rpc_error
+
+class DeriveaddressesTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+ self.supports_cli = 1
+
+ def run_test(self):
+ assert_raises_rpc_error(-5, "Invalid descriptor", self.nodes[0].deriveaddresses, "a")
+
+ descriptor = "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)"
+ address = "bcrt1qjqmxmkpmxt80xz4y3746zgt0q3u3ferr34acd5"
+
+ assert_equal(self.nodes[0].deriveaddresses(descriptor), [address])
+
+ descriptor_pubkey = "wpkh(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/0)"
+ address = "bcrt1qjqmxmkpmxt80xz4y3746zgt0q3u3ferr34acd5"
+
+ assert_equal(self.nodes[0].deriveaddresses(descriptor_pubkey), [address])
+
+ ranged_descriptor = "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)"
+ assert_equal(self.nodes[0].deriveaddresses(ranged_descriptor, 0, 2), [address, "bcrt1qhku5rq7jz8ulufe2y6fkcpnlvpsta7rq4442dy", "bcrt1qpgptk2gvshyl0s9lqshsmx932l9ccsv265tvaq"])
+
+ assert_raises_rpc_error(-8, "Range should not be specified for an un-ranged descriptor", self.nodes[0].deriveaddresses, "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)", 0, 2)
+
+ assert_raises_rpc_error(-8, "Range must be specified for a ranged descriptor", self.nodes[0].deriveaddresses, "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)")
+
+ assert_raises_rpc_error(-8, "Missing range end parameter", self.nodes[0].deriveaddresses, "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)", 0)
+
+ assert_raises_rpc_error(-8, "Range end should be equal to or greater than begin", self.nodes[0].deriveaddresses, "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)", 2, 0)
+
+ assert_raises_rpc_error(-8, "Range should be greater or equal than 0", self.nodes[0].deriveaddresses, "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)", -1, 0)
+
+ combo_descriptor = "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)"
+ assert_equal(self.nodes[0].deriveaddresses(combo_descriptor), ["mtfUoUax9L4tzXARpw1oTGxWyoogp52KhJ", "mtfUoUax9L4tzXARpw1oTGxWyoogp52KhJ", address, "2NDvEwGfpEqJWfybzpKPHF2XH3jwoQV3D7x"])
+
+ hardened_without_privkey_descriptor = "wpkh(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1'/1/0)"
+ assert_raises_rpc_error(-5, "Cannot derive script without private keys", self.nodes[0].deriveaddresses, hardened_without_privkey_descriptor)
+
+ bare_multisig_descriptor = "multi(1, tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/0, tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/1)"
+ assert_raises_rpc_error(-5, "Descriptor does not have a corresponding address", self.nodes[0].deriveaddresses, bare_multisig_descriptor)
+
+if __name__ == '__main__':
+ DeriveaddressesTest().main()
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
index 272ebe65cb..a82a5d0208 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -19,6 +19,8 @@ class PSBTTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = False
self.num_nodes = 3
+ # TODO: remove -txindex. Currently required for getrawtransaction call.
+ self.extra_args = [[], ["-txindex"], ["-txindex"]]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
@@ -267,6 +269,9 @@ class PSBTTest(BitcoinTestFramework):
combined = self.nodes[2].combinepsbt(combiner['combine'])
assert_equal(combined, combiner['result'])
+ # Empty combiner test
+ assert_raises_rpc_error(-8, "Parameter 'txs' cannot be empty", self.nodes[0].combinepsbt, [])
+
# Finalizer test
for finalizer in finalizers:
finalized = self.nodes[2].finalizepsbt(finalizer['finalize'], False)['psbt']
diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py
index 5b9dbef68d..a97d753626 100755
--- a/test/functional/rpc_rawtransaction.py
+++ b/test/functional/rpc_rawtransaction.py
@@ -42,7 +42,8 @@ class RawTransactionsTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 3
- self.extra_args = [["-addresstype=legacy"], ["-addresstype=legacy"], ["-addresstype=legacy"]]
+ # TODO: remove -txindex. Currently required for getrawtransaction call.
+ self.extra_args = [["-addresstype=legacy", "-txindex"], ["-addresstype=legacy", "-txindex"], ["-addresstype=legacy", "-txindex"]]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py
index ca5734d67d..ac7cc068bd 100755
--- a/test/functional/test_framework/mininode.py
+++ b/test/functional/test_framework/mininode.py
@@ -118,7 +118,7 @@ class P2PConnection(asyncio.Protocol):
# The initial message to send after the connection was made:
self.on_connection_send_msg = None
self.recvbuf = b""
- self.network = net
+ self.magic_bytes = MAGIC_BYTES[net]
logger.debug('Connecting to Bitcoin Node: %s:%d' % (self.dstaddr, self.dstport))
loop = NetworkThread.network_event_loop
@@ -170,7 +170,7 @@ class P2PConnection(asyncio.Protocol):
while True:
if len(self.recvbuf) < 4:
return
- if self.recvbuf[:4] != MAGIC_BYTES[self.network]:
+ if self.recvbuf[:4] != self.magic_bytes:
raise ValueError("got garbage %s" % repr(self.recvbuf))
if len(self.recvbuf) < 4 + 12 + 4 + 4:
return
@@ -232,7 +232,7 @@ class P2PConnection(asyncio.Protocol):
"""Build a serialized P2P message"""
command = message.command
data = message.serialize()
- tmsg = MAGIC_BYTES[self.network]
+ tmsg = self.magic_bytes
tmsg += command
tmsg += b"\x00" * (12 - len(command))
tmsg += struct.pack("<I", len(data))
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index 352fa32b5b..8c4c0d7226 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -128,6 +128,8 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
help="Attach a python debugger if test fails")
parser.add_argument("--usecli", dest="usecli", default=False, action="store_true",
help="use bitcoin-cli instead of RPC for all commands")
+ parser.add_argument("--perf", dest="perf", default=False, action="store_true",
+ help="profile running nodes with perf for the duration of the test")
self.add_options(parser)
self.options = parser.parse_args()
@@ -139,6 +141,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
config = configparser.ConfigParser()
config.read_file(open(self.options.configfile))
+ self.config = config
self.options.bitcoind = os.getenv("BITCOIND", default=config["environment"]["BUILDDIR"] + '/src/bitcoind' + config["environment"]["EXEEXT"])
self.options.bitcoincli = os.getenv("BITCOINCLI", default=config["environment"]["BUILDDIR"] + '/src/bitcoin-cli' + config["environment"]["EXEEXT"])
@@ -201,11 +204,20 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
node.cleanup_on_exit = False
self.log.info("Note: bitcoinds were not stopped and may still be running")
- if not self.options.nocleanup and not self.options.noshutdown and success != TestStatus.FAILED:
+ should_clean_up = (
+ not self.options.nocleanup and
+ not self.options.noshutdown and
+ success != TestStatus.FAILED and
+ not self.options.perf
+ )
+ if should_clean_up:
self.log.info("Cleaning up {} on exit".format(self.options.tmpdir))
cleanup_tree_on_exit = True
+ elif self.options.perf:
+ self.log.warning("Not cleaning up dir {} due to perf data".format(self.options.tmpdir))
+ cleanup_tree_on_exit = False
else:
- self.log.warning("Not cleaning up dir %s" % self.options.tmpdir)
+ self.log.warning("Not cleaning up dir {}".format(self.options.tmpdir))
cleanup_tree_on_exit = False
if success == TestStatus.PASSED:
@@ -309,6 +321,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
extra_conf=extra_confs[i],
extra_args=extra_args[i],
use_cli=self.options.usecli,
+ start_perf=self.options.perf,
))
def start_node(self, i, *args, **kwargs):
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index 031a8824b1..999ea68254 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -18,6 +18,8 @@ import tempfile
import time
import urllib.parse
import collections
+import shlex
+import sys
from .authproxy import JSONRPCException
from .util import (
@@ -59,7 +61,13 @@ class TestNode():
To make things easier for the test writer, any unrecognised messages will
be dispatched to the RPC connection."""
- def __init__(self, i, datadir, *, rpchost, timewait, bitcoind, bitcoin_cli, mocktime, coverage_dir, extra_conf=None, extra_args=None, use_cli=False):
+ def __init__(self, i, datadir, *, rpchost, timewait, bitcoind, bitcoin_cli, mocktime, coverage_dir, extra_conf=None, extra_args=None, use_cli=False, start_perf=False):
+ """
+ Kwargs:
+ start_perf (bool): If True, begin profiling the node with `perf` as soon as
+ the node starts.
+ """
+
self.index = i
self.datadir = datadir
self.stdout_dir = os.path.join(self.datadir, "stdout")
@@ -87,6 +95,7 @@ class TestNode():
self.cli = TestNodeCLI(bitcoin_cli, self.datadir)
self.use_cli = use_cli
+ self.start_perf = start_perf
self.running = False
self.process = None
@@ -95,6 +104,8 @@ class TestNode():
self.url = None
self.log = logging.getLogger('TestFramework.node%d' % i)
self.cleanup_on_exit = True # Whether to kill the node when this object goes away
+ # Cache perf subprocesses here by their data output filename.
+ self.perf_subprocesses = {}
self.p2ps = []
@@ -186,6 +197,9 @@ class TestNode():
self.running = True
self.log.debug("bitcoind started, waiting for RPC to come up")
+ if self.start_perf:
+ self._start_perf()
+
def wait_for_rpc_connection(self):
"""Sets up an RPC connection to the bitcoind process. Returns False if unable to connect."""
# Poll at a rate of four times per second
@@ -195,12 +209,15 @@ class TestNode():
raise FailedToStartError(self._node_msg(
'bitcoind exited with status {} during initialization'.format(self.process.returncode)))
try:
- self.rpc = get_rpc_proxy(rpc_url(self.datadir, self.index, self.rpchost), self.index, timeout=self.rpc_timeout, coveragedir=self.coverage_dir)
- self.rpc.getblockcount()
+ rpc = get_rpc_proxy(rpc_url(self.datadir, self.index, self.rpchost), self.index, timeout=self.rpc_timeout, coveragedir=self.coverage_dir)
+ rpc.getblockcount()
# If the call to getblockcount() succeeds then the RPC connection is up
+ self.log.debug("RPC successfully started")
+ if self.use_cli:
+ return
+ self.rpc = rpc
self.rpc_connected = True
self.url = self.rpc.url
- self.log.debug("RPC successfully started")
return
except IOError as e:
if e.errno != errno.ECONNREFUSED: # Port not yet open?
@@ -238,6 +255,10 @@ class TestNode():
except http.client.CannotSendRequest:
self.log.exception("Unable to stop node.")
+ # If there are any running perf processes, stop them.
+ for profile_name in tuple(self.perf_subprocesses.keys()):
+ self._stop_perf(profile_name)
+
# Check that stderr is as expected
self.stderr.seek(0)
stderr = self.stderr.read().decode('utf-8').strip()
@@ -317,6 +338,84 @@ class TestNode():
increase_allowed * 100, before_memory_usage, after_memory_usage,
perc_increase_memory_usage * 100))
+ @contextlib.contextmanager
+ def profile_with_perf(self, profile_name):
+ """
+ Context manager that allows easy profiling of node activity using `perf`.
+
+ See `test/functional/README.md` for details on perf usage.
+
+ Args:
+ profile_name (str): This string will be appended to the
+ profile data filename generated by perf.
+ """
+ subp = self._start_perf(profile_name)
+
+ yield
+
+ if subp:
+ self._stop_perf(profile_name)
+
+ def _start_perf(self, profile_name=None):
+ """Start a perf process to profile this node.
+
+ Returns the subprocess running perf."""
+ subp = None
+
+ def test_success(cmd):
+ return subprocess.call(
+ # shell=True required for pipe use below
+ cmd, shell=True,
+ stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL) == 0
+
+ if not sys.platform.startswith('linux'):
+ self.log.warning("Can't profile with perf; only availabe on Linux platforms")
+ return None
+
+ if not test_success('which perf'):
+ self.log.warning("Can't profile with perf; must install perf-tools")
+ return None
+
+ if not test_success('readelf -S {} | grep .debug_str'.format(shlex.quote(self.binary))):
+ self.log.warning(
+ "perf output won't be very useful without debug symbols compiled into bitcoind")
+
+ output_path = tempfile.NamedTemporaryFile(
+ dir=self.datadir,
+ prefix="{}.perf.data.".format(profile_name or 'test'),
+ delete=False,
+ ).name
+
+ cmd = [
+ 'perf', 'record',
+ '-g', # Record the callgraph.
+ '--call-graph', 'dwarf', # Compatibility for gcc's --fomit-frame-pointer.
+ '-F', '101', # Sampling frequency in Hz.
+ '-p', str(self.process.pid),
+ '-o', output_path,
+ ]
+ subp = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ self.perf_subprocesses[profile_name] = subp
+
+ return subp
+
+ def _stop_perf(self, profile_name):
+ """Stop (and pop) a perf subprocess."""
+ subp = self.perf_subprocesses.pop(profile_name)
+ output_path = subp.args[subp.args.index('-o') + 1]
+
+ subp.terminate()
+ subp.wait(timeout=10)
+
+ stderr = subp.stderr.read().decode()
+ if 'Consider tweaking /proc/sys/kernel/perf_event_paranoid' in stderr:
+ self.log.warning(
+ "perf couldn't collect data! Try "
+ "'sudo sysctl -w kernel.perf_event_paranoid=-1'")
+ else:
+ report_cmd = "perf report -i {}".format(output_path)
+ self.log.info("See perf output by running '{}'".format(report_cmd))
+
def assert_start_raises_init_error(self, extra_args=None, expected_msg=None, match=ErrorMatch.FULL_TEXT, *args, **kwargs):
"""Attempt to start the node and expect it to raise an error.
@@ -402,6 +501,14 @@ class TestNodeCLIAttr:
def get_request(self, *args, **kwargs):
return lambda: self(*args, **kwargs)
+def arg_to_cli(arg):
+ if isinstance(arg, bool):
+ return str(arg).lower()
+ elif isinstance(arg, dict) or isinstance(arg, list):
+ return json.dumps(arg)
+ else:
+ return str(arg)
+
class TestNodeCLI():
"""Interface to bitcoin-cli for an individual node"""
@@ -433,8 +540,8 @@ class TestNodeCLI():
def send_cli(self, command=None, *args, **kwargs):
"""Run bitcoin-cli command. Deserializes returned string as python object."""
- pos_args = [str(arg).lower() if type(arg) is bool else str(arg) for arg in args]
- named_args = [str(key) + "=" + str(value) for (key, value) in kwargs.items()]
+ pos_args = [arg_to_cli(arg) for arg in args]
+ named_args = [str(key) + "=" + arg_to_cli(value) for (key, value) in kwargs.items()]
assert not (pos_args and named_args), "Cannot use positional arguments and named arguments in the same bitcoin-cli call"
p_args = [self.binary, "-datadir=" + self.datadir] + self.options
if named_args:
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 8c6f6706e7..999cd72108 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -7,8 +7,6 @@
This module calls down into individual test cases via subprocess. It will
forward all unrecognized arguments onto the individual test scripts.
-Functional tests are disabled on Windows by default. Use --force to run them anyway.
-
For a description of arguments recognized by test scripts, see
`test/functional/test_framework/test_framework.py:BitcoinTestFramework.main`.
@@ -108,6 +106,7 @@ BASE_SCRIPTS = [
'interface_bitcoin_cli.py',
'mempool_resurrect.py',
'wallet_txn_doublespend.py --mineblock',
+ 'tool_wallet.py',
'wallet_txn_clone.py',
'wallet_txn_clone.py --segwit',
'rpc_getchaintips.py',
@@ -117,8 +116,8 @@ BASE_SCRIPTS = [
'mempool_persist.py',
'wallet_multiwallet.py',
'wallet_multiwallet.py --usecli',
- 'wallet_disableprivatekeys.py',
- 'wallet_disableprivatekeys.py --usecli',
+ 'wallet_createwallet.py',
+ 'wallet_createwallet.py --usecli',
'interface_http.py',
'interface_rpc.py',
'rpc_psbt.py',
@@ -181,6 +180,8 @@ BASE_SCRIPTS = [
'feature_filelock.py',
'p2p_unrequested_blocks.py',
'feature_includeconf.py',
+ 'rpc_deriveaddresses.py',
+ 'rpc_deriveaddresses.py --usecli',
'rpc_scantxoutset.py',
'feature_logging.py',
'p2p_node_network_limited.py',
@@ -223,7 +224,6 @@ def main():
parser.add_argument('--ci', action='store_true', help='Run checks and code that are usually only enabled in a continuous integration environment')
parser.add_argument('--exclude', '-x', help='specify a comma-separated-list of scripts to exclude.')
parser.add_argument('--extended', action='store_true', help='run the extended test suite in addition to the basic tests')
- parser.add_argument('--force', '-f', action='store_true', help='run tests even on platforms where they are disabled by default (e.g. windows).')
parser.add_argument('--help', '-h', '-?', action='store_true', help='print help text and exit')
parser.add_argument('--jobs', '-j', type=int, default=4, help='how many test scripts to run in parallel. Default=4.')
parser.add_argument('--keepcache', '-k', action='store_true', help='the default behavior is to flush the cache directory on startup. --keepcache retains the cache from the previous testrun.')
@@ -250,22 +250,12 @@ def main():
# Create base test directory
tmpdir = "%s/test_runner_₿_🏃_%s" % (args.tmpdirprefix, datetime.datetime.now().strftime("%Y%m%d_%H%M%S"))
- # If we fixed the command-line and filename encoding issue on Windows, these two lines could be removed
- if config["environment"]["EXEEXT"] == ".exe":
- tmpdir = "%s/test_runner_%s" % (args.tmpdirprefix, datetime.datetime.now().strftime("%Y%m%d_%H%M%S"))
-
os.makedirs(tmpdir)
logging.debug("Temporary test directory at %s" % tmpdir)
enable_bitcoind = config["components"].getboolean("ENABLE_BITCOIND")
- if config["environment"]["EXEEXT"] == ".exe" and not args.force:
- # https://github.com/bitcoin/bitcoin/commit/d52802551752140cf41f0d9a225a43e84404d3e9
- # https://github.com/bitcoin/bitcoin/pull/5677#issuecomment-136646964
- print("Tests currently disabled on Windows by default. Use --force option to enable")
- sys.exit(0)
-
if not enable_bitcoind:
print("No functional tests to run.")
print("Rerun ./configure with --with-daemon and then make")
@@ -562,7 +552,7 @@ class TestResult():
def check_script_prefixes():
"""Check that test scripts start with one of the allowed name prefixes."""
- good_prefixes_re = re.compile("(example|feature|interface|mempool|mining|p2p|rpc|wallet)_")
+ good_prefixes_re = re.compile("(example|feature|interface|mempool|mining|p2p|rpc|wallet|tool)_")
bad_script_names = [script for script in ALL_SCRIPTS if good_prefixes_re.match(script) is None]
if bad_script_names:
diff --git a/test/functional/tool_wallet.py b/test/functional/tool_wallet.py
new file mode 100755
index 0000000000..fbcf21e729
--- /dev/null
+++ b/test/functional/tool_wallet.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python3
+# 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.
+"""Test bitcoin-wallet."""
+import subprocess
+import textwrap
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+
+class ToolWalletTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+ self.setup_clean_chain = True
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def bitcoin_wallet_process(self, *args):
+ binary = self.config["environment"]["BUILDDIR"] + '/src/bitcoin-wallet' + self.config["environment"]["EXEEXT"]
+ args = ['-datadir={}'.format(self.nodes[0].datadir), '-regtest'] + list(args)
+ return subprocess.Popen([binary] + args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
+
+ def assert_raises_tool_error(self, error, *args):
+ p = self.bitcoin_wallet_process(*args)
+ stdout, stderr = p.communicate()
+ assert_equal(p.poll(), 1)
+ assert_equal(stdout, '')
+ assert_equal(stderr.strip(), error)
+
+ def assert_tool_output(self, output, *args):
+ p = self.bitcoin_wallet_process(*args)
+ stdout, stderr = p.communicate()
+ assert_equal(p.poll(), 0)
+ assert_equal(stderr, '')
+ assert_equal(stdout, output)
+
+ def run_test(self):
+
+ self.assert_raises_tool_error('Invalid command: foo', 'foo')
+ # `bitcoin-wallet help` is an error. Use `bitcoin-wallet -help`
+ self.assert_raises_tool_error('Invalid command: help', 'help')
+ self.assert_raises_tool_error('Error: two methods provided (info and create). Only one method should be provided.', 'info', 'create')
+ self.assert_raises_tool_error('Error parsing command line arguments: Invalid parameter -foo', '-foo')
+ self.assert_raises_tool_error('Error loading wallet.dat. Is wallet being used by other process?', '-wallet=wallet.dat', 'info')
+ self.assert_raises_tool_error('Error: no wallet file at nonexistent.dat', '-wallet=nonexistent.dat', 'info')
+
+ # stop the node to close the wallet to call info command
+ self.stop_node(0)
+
+ out = textwrap.dedent('''\
+ Wallet info
+ ===========
+ Encrypted: no
+ HD (hd seed available): yes
+ Keypool Size: 2
+ Transactions: 0
+ Address Book: 3
+ ''')
+ self.assert_tool_output(out, '-wallet=wallet.dat', 'info')
+
+ # mutate the wallet to check the info command output changes accordingly
+ self.start_node(0)
+ self.nodes[0].generate(1)
+ self.stop_node(0)
+
+ out = textwrap.dedent('''\
+ Wallet info
+ ===========
+ Encrypted: no
+ HD (hd seed available): yes
+ Keypool Size: 2
+ Transactions: 1
+ Address Book: 3
+ ''')
+ self.assert_tool_output(out, '-wallet=wallet.dat', 'info')
+
+ out = textwrap.dedent('''\
+ Topping up keypool...
+ Wallet info
+ ===========
+ Encrypted: no
+ HD (hd seed available): yes
+ Keypool Size: 2000
+ Transactions: 0
+ Address Book: 0
+ ''')
+ self.assert_tool_output(out, '-wallet=foo', 'create')
+
+ self.start_node(0, ['-wallet=foo'])
+ out = self.nodes[0].getwalletinfo()
+ self.stop_node(0)
+
+ assert_equal(0, out['txcount'])
+ assert_equal(1000, out['keypoolsize'])
+ assert_equal(1000, out['keypoolsize_hd_internal'])
+ assert_equal(True, 'hdseedid' in out)
+
+if __name__ == '__main__':
+ ToolWalletTest().main()
diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py
index e5ac2c8bd4..0c3c247694 100755
--- a/test/functional/wallet_abandonconflict.py
+++ b/test/functional/wallet_abandonconflict.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-2019 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the abandontransaction RPC.
@@ -13,12 +13,21 @@
from decimal import Decimal
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, assert_raises_rpc_error, connect_nodes, disconnect_nodes, sync_blocks, sync_mempools
+from test_framework.util import (
+ assert_equal,
+ assert_raises_rpc_error,
+ connect_nodes,
+ disconnect_nodes,
+ sync_blocks,
+ sync_mempools,
+)
+
class AbandonConflictTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
- self.extra_args = [["-minrelaytxfee=0.00001"], []]
+ # TODO: remove -txindex. Currently required for getrawtransaction call.
+ self.extra_args = [["-minrelaytxfee=0.00001", "-txindex"], []]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
@@ -40,21 +49,21 @@ class AbandonConflictTest(BitcoinTestFramework):
sync_blocks(self.nodes)
newbalance = self.nodes[0].getbalance()
- assert(balance - newbalance < Decimal("0.001")) #no more than fees lost
+ assert balance - newbalance < Decimal("0.001") #no more than fees lost
balance = newbalance
# Disconnect nodes so node0's transactions don't get into node1's mempool
disconnect_nodes(self.nodes[0], 1)
# Identify the 10btc outputs
- nA = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txA, 1)["vout"]) if vout["value"] == Decimal("10"))
- nB = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txB, 1)["vout"]) if vout["value"] == Decimal("10"))
- nC = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txC, 1)["vout"]) if vout["value"] == Decimal("10"))
+ nA = next(tx_out["vout"] for tx_out in self.nodes[0].gettransaction(txA)["details"] if tx_out["amount"] == Decimal("10"))
+ nB = next(tx_out["vout"] for tx_out in self.nodes[0].gettransaction(txB)["details"] if tx_out["amount"] == Decimal("10"))
+ nC = next(tx_out["vout"] for tx_out in self.nodes[0].gettransaction(txC)["details"] if tx_out["amount"] == Decimal("10"))
- inputs =[]
+ inputs = []
# spend 10btc outputs from txA and txB
- inputs.append({"txid":txA, "vout":nA})
- inputs.append({"txid":txB, "vout":nB})
+ inputs.append({"txid": txA, "vout": nA})
+ inputs.append({"txid": txB, "vout": nB})
outputs = {}
outputs[self.nodes[0].getnewaddress()] = Decimal("14.99998")
@@ -63,12 +72,12 @@ class AbandonConflictTest(BitcoinTestFramework):
txAB1 = self.nodes[0].sendrawtransaction(signed["hex"])
# Identify the 14.99998btc output
- nAB = next(i for i, vout in enumerate(self.nodes[0].getrawtransaction(txAB1, 1)["vout"]) if vout["value"] == Decimal("14.99998"))
+ nAB = next(tx_out["vout"] for tx_out in self.nodes[0].gettransaction(txAB1)["details"] if tx_out["amount"] == Decimal("14.99998"))
#Create a child tx spending AB1 and C
inputs = []
- inputs.append({"txid":txAB1, "vout":nAB})
- inputs.append({"txid":txC, "vout":nC})
+ inputs.append({"txid": txAB1, "vout": nAB})
+ inputs.append({"txid": txC, "vout": nC})
outputs = {}
outputs[self.nodes[0].getnewaddress()] = Decimal("24.9996")
signed2 = self.nodes[0].signrawtransactionwithwallet(self.nodes[0].createrawtransaction(inputs, outputs))
@@ -76,8 +85,8 @@ class AbandonConflictTest(BitcoinTestFramework):
# Create a child tx spending ABC2
signed3_change = Decimal("24.999")
- inputs = [ {"txid":txABC2, "vout":0} ]
- outputs = { self.nodes[0].getnewaddress(): signed3_change }
+ inputs = [{"txid": txABC2, "vout": 0}]
+ outputs = {self.nodes[0].getnewaddress(): signed3_change}
signed3 = self.nodes[0].signrawtransactionwithwallet(self.nodes[0].createrawtransaction(inputs, outputs))
# note tx is never directly referenced, only abandoned as a child of the above
self.nodes[0].sendrawtransaction(signed3["hex"])
@@ -105,7 +114,7 @@ class AbandonConflictTest(BitcoinTestFramework):
unconfbalance = self.nodes[0].getunconfirmedbalance() + self.nodes[0].getbalance()
assert_equal(unconfbalance, newbalance)
# Also shouldn't show up in listunspent
- assert(not txABC2 in [utxo["txid"] for utxo in self.nodes[0].listunspent(0)])
+ assert not txABC2 in [utxo["txid"] for utxo in self.nodes[0].listunspent(0)]
balance = newbalance
# Abandon original transaction and verify inputs are available again
@@ -145,8 +154,8 @@ class AbandonConflictTest(BitcoinTestFramework):
# Create a double spend of AB1 by spending again from only A's 10 output
# Mine double spend from node 1
- inputs =[]
- inputs.append({"txid":txA, "vout":nA})
+ inputs = []
+ inputs.append({"txid": txA, "vout": nA})
outputs = {}
outputs[self.nodes[1].getnewaddress()] = Decimal("9.9999")
tx = self.nodes[0].createrawtransaction(inputs, outputs)
@@ -172,5 +181,6 @@ class AbandonConflictTest(BitcoinTestFramework):
self.log.info("conflicted has not resumed causing its inputs to be seen as spent. See Issue #7315")
self.log.info(str(balance) + " -> " + str(newbalance) + " ?")
+
if __name__ == '__main__':
AbandonConflictTest().main()
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index 7184bb8cb6..fe1a614700 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-2019 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the wallet."""
@@ -19,10 +19,13 @@ from test_framework.util import (
wait_until,
)
+
class WalletTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 4
self.setup_clean_chain = True
+ # TODO: remove -txindex. Currently required for getrawtransaction call.
+ self.extra_args = [[], [], ["-txindex"], []]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
@@ -194,7 +197,7 @@ class WalletTest(BitcoinTestFramework):
txid = self.nodes[2].sendtoaddress(address, 10, "", "", False)
self.nodes[2].generate(1)
self.sync_all([self.nodes[0:3]])
- node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), Decimal('84'), fee_per_byte, self.get_vsize(self.nodes[2].getrawtransaction(txid)))
+ node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), Decimal('84'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex']))
assert_equal(self.nodes[0].getbalance(), Decimal('10'))
# Send 10 BTC with subtract fee from amount
@@ -203,14 +206,14 @@ class WalletTest(BitcoinTestFramework):
self.sync_all([self.nodes[0:3]])
node_2_bal -= Decimal('10')
assert_equal(self.nodes[2].getbalance(), node_2_bal)
- node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), Decimal('20'), fee_per_byte, self.get_vsize(self.nodes[2].getrawtransaction(txid)))
+ node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), Decimal('20'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex']))
# Sendmany 10 BTC
txid = self.nodes[2].sendmany('', {address: 10}, 0, "", [])
self.nodes[2].generate(1)
self.sync_all([self.nodes[0:3]])
node_0_bal += Decimal('10')
- node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), node_2_bal - Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].getrawtransaction(txid)))
+ node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), node_2_bal - Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex']))
assert_equal(self.nodes[0].getbalance(), node_0_bal)
# Sendmany 10 BTC with subtract fee from amount
@@ -219,7 +222,7 @@ class WalletTest(BitcoinTestFramework):
self.sync_all([self.nodes[0:3]])
node_2_bal -= Decimal('10')
assert_equal(self.nodes[2].getbalance(), node_2_bal)
- node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].getrawtransaction(txid)))
+ node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex']))
# Test ResendWalletTransactions:
# Create a couple of transactions, then start up a fourth
@@ -237,7 +240,7 @@ class WalletTest(BitcoinTestFramework):
assert_equal(set(relayed), {txid1, txid2})
sync_mempools(self.nodes)
- assert(txid1 in self.nodes[3].getrawmempool())
+ assert txid1 in self.nodes[3].getrawmempool()
# check if we can list zero value tx as available coins
# 1. create raw_tx
@@ -264,7 +267,7 @@ class WalletTest(BitcoinTestFramework):
if uTx['txid'] == zero_value_txid:
found = True
assert_equal(uTx['amount'], Decimal('0'))
- assert(found)
+ assert found
# do some -walletbroadcast tests
self.stop_nodes()
@@ -324,12 +327,38 @@ class WalletTest(BitcoinTestFramework):
tx_obj = self.nodes[0].gettransaction(txid)
assert_equal(tx_obj['amount'], Decimal('-0.0001'))
+ # General checks for errors from incorrect inputs
# This will raise an exception because the amount type is wrong
assert_raises_rpc_error(-3, "Invalid amount", self.nodes[0].sendtoaddress, self.nodes[2].getnewaddress(), "1f-4")
# This will raise an exception since generate does not accept a string
assert_raises_rpc_error(-1, "not an integer", self.nodes[0].generate, "2")
+ # This will raise an exception for the invalid private key format
+ assert_raises_rpc_error(-5, "Invalid private key encoding", self.nodes[0].importprivkey, "invalid")
+
+ # This will raise an exception for importing an address with the PS2H flag
+ temp_address = self.nodes[1].getnewaddress()
+ assert_raises_rpc_error(-5, "Cannot use the p2sh flag with an address - use a script instead", self.nodes[0].importaddress, temp_address, "label", False, True)
+
+ # This will raise an exception for attempting to dump the private key of an address you do not own
+ assert_raises_rpc_error(-3, "Address does not refer to a key", self.nodes[0].dumpprivkey, temp_address)
+
+ # This will raise an exception for attempting to get the private key of an invalid Bitcoin address
+ assert_raises_rpc_error(-5, "Invalid Bitcoin address", self.nodes[0].dumpprivkey, "invalid")
+
+ # This will raise an exception for attempting to set a label for an invalid Bitcoin address
+ assert_raises_rpc_error(-5, "Invalid Bitcoin address", self.nodes[0].setlabel, "invalid address", "label")
+
+ # This will raise an exception for importing an invalid address
+ assert_raises_rpc_error(-5, "Invalid Bitcoin address or script", self.nodes[0].importaddress, "invalid")
+
+ # This will raise an exception for attempting to import a pubkey that isn't in hex
+ assert_raises_rpc_error(-5, "Pubkey must be a hex string", self.nodes[0].importpubkey, "not hex")
+
+ # This will raise an exception for importing an invalid pubkey
+ assert_raises_rpc_error(-5, "Pubkey is not a valid public key", self.nodes[0].importpubkey, "5361746f736869204e616b616d6f746f")
+
# Import address and private key to check correct behavior of spendable unspents
# 1. Send some coins to generate new UTXO
address_to_import = self.nodes[2].getnewaddress()
@@ -341,7 +370,7 @@ class WalletTest(BitcoinTestFramework):
self.nodes[1].importaddress(address_to_import)
# 3. Validate that the imported address is watch-only on node1
- assert(self.nodes[1].getaddressinfo(address_to_import)["iswatchonly"])
+ assert self.nodes[1].getaddressinfo(address_to_import)["iswatchonly"]
# 4. Check that the unspents after import are not spendable
assert_array_result(self.nodes[1].listunspent(),
@@ -383,7 +412,7 @@ class WalletTest(BitcoinTestFramework):
addr = self.nodes[0].getnewaddress()
self.nodes[0].setlabel(addr, label)
assert_equal(self.nodes[0].getaddressinfo(addr)['label'], label)
- assert(label in self.nodes[0].listlabels())
+ assert label in self.nodes[0].listlabels()
self.nodes[0].rpc.ensure_ascii = True # restore to default
# maintenance tests
@@ -442,8 +471,8 @@ class WalletTest(BitcoinTestFramework):
# Without walletrejectlongchains, we will still generate a txid
# The tx will be stored in the wallet but not accepted to the mempool
extra_txid = self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001'))
- assert(extra_txid not in self.nodes[0].getrawmempool())
- assert(extra_txid in [tx["txid"] for tx in self.nodes[0].listtransactions()])
+ assert extra_txid not in self.nodes[0].getrawmempool()
+ assert extra_txid in [tx["txid"] for tx in self.nodes[0].listtransactions()]
self.nodes[0].abandontransaction(extra_txid)
total_txs = len(self.nodes[0].listtransactions("*", 99999))
@@ -480,7 +509,7 @@ class WalletTest(BitcoinTestFramework):
self.nodes[0].generate(1)
destination = self.nodes[1].getnewaddress()
txid = self.nodes[0].sendtoaddress(destination, 0.123)
- tx = self.nodes[0].decoderawtransaction(self.nodes[0].getrawtransaction(txid))
+ tx = self.nodes[0].decoderawtransaction(self.nodes[0].gettransaction(txid)['hex'])
output_addresses = [vout['scriptPubKey']['addresses'][0] for vout in tx["vout"]]
assert len(output_addresses) > 1
for address in output_addresses:
@@ -491,5 +520,6 @@ class WalletTest(BitcoinTestFramework):
self.nodes[0].setlabel(change, 'foobar')
assert_equal(self.nodes[0].getaddressinfo(change)['ischange'], False)
+
if __name__ == '__main__':
WalletTest().main()
diff --git a/test/functional/wallet_createwallet.py b/test/functional/wallet_createwallet.py
new file mode 100755
index 0000000000..9fd2650d78
--- /dev/null
+++ b/test/functional/wallet_createwallet.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+# 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.
+"""Test createwallet arguments.
+"""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ assert_raises_rpc_error,
+)
+
+class CreateWalletTest(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]
+ node.generate(1) # Leave IBD for sethdseed
+
+ self.nodes[0].createwallet(wallet_name='w0')
+ w0 = node.get_wallet_rpc('w0')
+ address1 = w0.getnewaddress()
+
+ self.log.info("Test disableprivatekeys creation.")
+ self.nodes[0].createwallet(wallet_name='w1', disable_private_keys=True)
+ w1 = node.get_wallet_rpc('w1')
+ assert_raises_rpc_error(-4, "Error: Private keys are disabled for this wallet", w1.getnewaddress)
+ assert_raises_rpc_error(-4, "Error: Private keys are disabled for this wallet", w1.getrawchangeaddress)
+ w1.importpubkey(w0.getaddressinfo(address1)['pubkey'])
+
+ self.log.info('Test that private keys cannot be imported')
+ addr = w0.getnewaddress('', 'legacy')
+ privkey = w0.dumpprivkey(addr)
+ assert_raises_rpc_error(-4, 'Cannot import private keys to a wallet with private keys disabled', w1.importprivkey, privkey)
+ result = w1.importmulti([{'scriptPubKey': {'address': addr}, 'timestamp': 'now', 'keys': [privkey]}])
+ assert(not result[0]['success'])
+ assert('warning' not in result[0])
+ assert_equal(result[0]['error']['code'], -4)
+ assert_equal(result[0]['error']['message'], 'Cannot import private keys to a wallet with private keys disabled')
+
+ self.log.info("Test blank creation with private keys disabled.")
+ self.nodes[0].createwallet(wallet_name='w2', disable_private_keys=True, blank=True)
+ w2 = node.get_wallet_rpc('w2')
+ assert_raises_rpc_error(-4, "Error: Private keys are disabled for this wallet", w2.getnewaddress)
+ assert_raises_rpc_error(-4, "Error: Private keys are disabled for this wallet", w2.getrawchangeaddress)
+ w2.importpubkey(w0.getaddressinfo(address1)['pubkey'])
+
+ self.log.info("Test blank creation with private keys enabled.")
+ self.nodes[0].createwallet(wallet_name='w3', disable_private_keys=False, blank=True)
+ w3 = node.get_wallet_rpc('w3')
+ assert_equal(w3.getwalletinfo()['keypoolsize'], 0)
+ assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w3.getnewaddress)
+ assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w3.getrawchangeaddress)
+ # Import private key
+ w3.importprivkey(w0.dumpprivkey(address1))
+ # Imported private keys are currently ignored by the keypool
+ assert_equal(w3.getwalletinfo()['keypoolsize'], 0)
+ assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w3.getnewaddress)
+ # Set the seed
+ w3.sethdseed()
+ assert_equal(w3.getwalletinfo()['keypoolsize'], 1)
+ w3.getnewaddress()
+ w3.getrawchangeaddress()
+
+ self.log.info("Test blank creation with privkeys enabled and then encryption")
+ self.nodes[0].createwallet(wallet_name='w4', disable_private_keys=False, blank=True)
+ w4 = node.get_wallet_rpc('w4')
+ assert_equal(w4.getwalletinfo()['keypoolsize'], 0)
+ assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w4.getnewaddress)
+ assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w4.getrawchangeaddress)
+ # Encrypt the wallet. Nothing should change about the keypool
+ w4.encryptwallet('pass')
+ assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w4.getnewaddress)
+ assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w4.getrawchangeaddress)
+ # Now set a seed and it should work. Wallet should also be encrypted
+ w4.walletpassphrase('pass', 2)
+ w4.sethdseed()
+ w4.getnewaddress()
+ w4.getrawchangeaddress()
+
+ self.log.info("Test blank creation with privkeys disabled and then encryption")
+ self.nodes[0].createwallet(wallet_name='w5', disable_private_keys=True, blank=True)
+ w5 = node.get_wallet_rpc('w5')
+ assert_equal(w5.getwalletinfo()['keypoolsize'], 0)
+ assert_raises_rpc_error(-4, "Error: Private keys are disabled for this wallet", w5.getnewaddress)
+ assert_raises_rpc_error(-4, "Error: Private keys are disabled for this wallet", w5.getrawchangeaddress)
+ # Encrypt the wallet
+ w5.encryptwallet('pass')
+ assert_raises_rpc_error(-4, "Error: Private keys are disabled for this wallet", w5.getnewaddress)
+ assert_raises_rpc_error(-4, "Error: Private keys are disabled for this wallet", w5.getrawchangeaddress)
+
+if __name__ == '__main__':
+ CreateWalletTest().main()
diff --git a/test/functional/wallet_disableprivatekeys.py b/test/functional/wallet_disableprivatekeys.py
deleted file mode 100755
index 34ff525255..0000000000
--- a/test/functional/wallet_disableprivatekeys.py
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/env python3
-# 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.
-"""Test disable-privatekeys mode.
-"""
-
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import (
- assert_raises_rpc_error,
-)
-
-
-class DisablePrivateKeysTest(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.log.info("Test disableprivatekeys creation.")
- self.nodes[0].createwallet('w1', True)
- self.nodes[0].createwallet('w2')
- w1 = node.get_wallet_rpc('w1')
- w2 = node.get_wallet_rpc('w2')
- assert_raises_rpc_error(-4,"Error: Private keys are disabled for this wallet", w1.getnewaddress)
- assert_raises_rpc_error(-4,"Error: Private keys are disabled for this wallet", w1.getrawchangeaddress)
- w1.importpubkey(w2.getaddressinfo(w2.getnewaddress())['pubkey'])
-
-if __name__ == '__main__':
- DisablePrivateKeysTest().main()
diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py
index f122f19e3a..7cce72b39f 100755
--- a/test/functional/wallet_importmulti.py
+++ b/test/functional/wallet_importmulti.py
@@ -203,7 +203,7 @@ class ImportMultiTest(BitcoinTestFramework):
"keys": [key.privkey]},
success=False,
error_code=-4,
- error_message='The wallet already contains the private key for this address or script')
+ error_message='The wallet already contains the private key for this address or script ("' + key.p2pkh_script + '")')
# Address + Private key + watchonly
self.log.info("Should import an address with private key and with watchonly")
@@ -543,5 +543,88 @@ class ImportMultiTest(BitcoinTestFramework):
solvable=True,
ismine=False)
+ # Test importing of a P2SH-P2WPKH address via descriptor + private key
+ key = get_key(self.nodes[0])
+ self.log.info("Should import a p2sh-p2wpkh address from descriptor and private key")
+ self.test_importmulti({"desc": "sh(wpkh(" + key.pubkey + "))",
+ "timestamp": "now",
+ "label": "Descriptor import test",
+ "keys": [key.privkey]},
+ success=True)
+ test_address(self.nodes[1],
+ key.p2sh_p2wpkh_addr,
+ solvable=True,
+ ismine=True,
+ label="Descriptor import test")
+
+ # Test ranged descriptor fails if range is not specified
+ xpriv = "tprv8ZgxMBicQKsPeuVhWwi6wuMQGfPKi9Li5GtX35jVNknACgqe3CY4g5xgkfDDJcmtF7o1QnxWDRYw4H5P26PXq7sbcUkEqeR4fg3Kxp2tigg"
+ addresses = ["2N7yv4p8G8yEaPddJxY41kPihnWvs39qCMf", "2MsHxyb2JS3pAySeNUsJ7mNnurtpeenDzLA"] # hdkeypath=m/0'/0'/0' and 1'
+ desc = "sh(wpkh(" + xpriv + "/0'/0'/*'" + "))"
+ self.log.info("Ranged descriptor import should fail without a specified range")
+ self.test_importmulti({"desc": desc,
+ "timestamp": "now"},
+ success=False,
+ error_code=-8,
+ error_message='Descriptor is ranged, please specify the range')
+
+ # Test importing of a ranged descriptor without keys
+ self.log.info("Should import the ranged descriptor with specified range as solvable")
+ self.test_importmulti({"desc": desc,
+ "timestamp": "now",
+ "range": {"end": 1}},
+ success=True,
+ warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
+ for address in addresses:
+ test_address(self.nodes[1],
+ key.p2sh_p2wpkh_addr,
+ solvable=True)
+
+ # Test importing of a P2PKH address via descriptor
+ key = get_key(self.nodes[0])
+ self.log.info("Should import a p2pkh address from descriptor")
+ self.test_importmulti({"desc": "pkh(" + key.pubkey + ")",
+ "timestamp": "now",
+ "label": "Descriptor import test"},
+ True,
+ warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
+ test_address(self.nodes[1],
+ key.p2pkh_addr,
+ solvable=True,
+ ismine=False,
+ label="Descriptor import test")
+
+ # Test import fails if both desc and scriptPubKey are provided
+ key = get_key(self.nodes[0])
+ self.log.info("Import should fail if both scriptPubKey and desc are provided")
+ self.test_importmulti({"desc": "pkh(" + key.pubkey + ")",
+ "scriptPubKey": {"address": key.p2pkh_addr},
+ "timestamp": "now"},
+ success=False,
+ error_code=-8,
+ error_message='Both a descriptor and a scriptPubKey should not be provided.')
+
+ # Test import fails if neither desc nor scriptPubKey are present
+ key = get_key(self.nodes[0])
+ self.log.info("Import should fail if neither a descriptor nor a scriptPubKey are provided")
+ self.test_importmulti({"timestamp": "now"},
+ success=False,
+ error_code=-8,
+ error_message='Either a descriptor or scriptPubKey must be provided.')
+
+ # Test importing of a multisig via descriptor
+ key1 = get_key(self.nodes[0])
+ key2 = get_key(self.nodes[0])
+ self.log.info("Should import a 1-of-2 bare multisig from descriptor")
+ self.test_importmulti({"desc": "multi(1," + key1.pubkey + "," + key2.pubkey + ")",
+ "timestamp": "now"},
+ success=True)
+ self.log.info("Should not treat individual keys from the imported bare multisig as watchonly")
+ test_address(self.nodes[1],
+ key1.p2pkh_addr,
+ ismine=False,
+ iswatchonly=False)
+
+
if __name__ == '__main__':
ImportMultiTest().main()
diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py
index 8ab569a3c3..df778f57df 100755
--- a/test/functional/wallet_multiwallet.py
+++ b/test/functional/wallet_multiwallet.py
@@ -315,6 +315,14 @@ class MultiWalletTest(BitcoinTestFramework):
self.nodes[0].loadwallet(wallet_name)
assert_equal(rpc.getaddressinfo(addr)['ismine'], True)
+ # Test .walletlock file is closed
+ self.start_node(1)
+ wallet = os.path.join(self.options.tmpdir, 'my_wallet')
+ self.nodes[0].createwallet(wallet)
+ assert_raises_rpc_error(-4, "Error initializing wallet database environment", self.nodes[1].loadwallet, wallet)
+ self.nodes[0].unloadwallet(wallet)
+ self.nodes[1].loadwallet(wallet)
+
if __name__ == '__main__':
MultiWalletTest().main()
diff --git a/test/lint/check-doc.py b/test/lint/check-doc.py
index 4facd6c334..c370ce0c04 100755
--- a/test/lint/check-doc.py
+++ b/test/lint/check-doc.py
@@ -30,8 +30,8 @@ def main():
used = check_output(CMD_GREP_ARGS, shell=True, universal_newlines=True, encoding='utf8')
docd = check_output(CMD_GREP_DOCS, shell=True, universal_newlines=True, encoding='utf8')
else:
- used = check_output(CMD_GREP_ARGS, shell=True, universal_newlines=True) # encoding='utf8'
- docd = check_output(CMD_GREP_DOCS, shell=True, universal_newlines=True) # encoding='utf8'
+ used = check_output(CMD_GREP_ARGS, shell=True).decode('utf8').strip()
+ docd = check_output(CMD_GREP_DOCS, shell=True).decode('utf8').strip()
args_used = set(re.findall(re.compile(REGEX_ARG), used))
args_docd = set(re.findall(re.compile(REGEX_DOC), docd)).union(SET_DOC_OPTIONAL)
diff --git a/test/lint/lint-python-dead-code.sh b/test/lint/lint-python-dead-code.sh
index 1b897cd131..863caa9d5c 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,get_ecdh_key,get_privkey,is_compressed,is_fullyvalid,msg_generic,on_*,optionxform,restype,set_privkey" \
+ --ignore-names "argtypes,connection_lost,connection_made,converter,data_received,daemon,errcheck,get_ecdh_key,get_privkey,is_compressed,is_fullyvalid,msg_generic,on_*,optionxform,restype,set_privkey,profile_with_perf" \
$(git ls-files -- "*.py" ":(exclude)contrib/" ":(exclude)test/functional/data/invalid_txs.py")
diff --git a/test/lint/lint-python.sh b/test/lint/lint-python.sh
index 3dbb9fff28..f5b851aeab 100755
--- a/test/lint/lint-python.sh
+++ b/test/lint/lint-python.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/usr/bin/env bash
#
# Copyright (c) 2017 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
@@ -8,77 +8,79 @@
export LC_ALL=C
-# E101 indentation contains mixed spaces and tabs
-# E112 expected an indented block
-# E113 unexpected indentation
-# E115 expected an indented block (comment)
-# E116 unexpected indentation (comment)
-# E125 continuation line with same indent as next logical line
-# E129 visually indented line with same indent as next logical line
-# E131 continuation line unaligned for hanging indent
-# E133 closing bracket is missing indentation
-# E223 tab before operator
-# E224 tab after operator
-# E242 tab after ','
-# E266 too many leading '#' for block comment
-# E271 multiple spaces after keyword
-# E272 multiple spaces before keyword
-# E273 tab after keyword
-# E274 tab before keyword
-# E275 missing whitespace after keyword
-# E304 blank lines found after function decorator
-# E306 expected 1 blank line before a nested definition
-# E401 multiple imports on one line
-# E402 module level import not at top of file
-# F403 'from foo_module import *' used; unable to detect undefined names
-# F405 foo_function may be undefined, or defined from star imports: bar_module
-# E502 the backslash is redundant between brackets
-# E701 multiple statements on one line (colon)
-# E702 multiple statements on one line (semicolon)
-# E703 statement ends with a semicolon
-# E711 comparison to None should be 'if cond is None:'
-# E714 test for object identity should be "is not"
-# E721 do not compare types, use "isinstance()"
-# E741 do not use variables named "l", "O", or "I"
-# E742 do not define classes named "l", "O", or "I"
-# E743 do not define functions named "l", "O", or "I"
-# E901 SyntaxError: invalid syntax
-# E902 TokenError: EOF in multi-line string
-# F401 module imported but unused
-# F402 import module from line N shadowed by loop variable
-# F404 future import(s) name after other statements
-# F406 "from module import *" only allowed at module level
-# F407 an undefined __future__ feature name was imported
-# F601 dictionary key name repeated with different values
-# F602 dictionary key variable name repeated with different values
-# F621 too many expressions in an assignment with star-unpacking
-# F622 two or more starred expressions in an assignment (a, *b, *c = d)
-# F631 assertion test is a tuple, which are always True
-# F701 a break statement outside of a while or for loop
-# F702 a continue statement outside of a while or for loop
-# F703 a continue statement in a finally block in a loop
-# F704 a yield or yield from statement outside of a function
-# F705 a return statement with arguments inside a generator
-# F706 a return statement outside of a function/method
-# F707 an except: block as not the last exception handler
-# F811 redefinition of unused name from line N
-# F812 list comprehension redefines 'foo' from line N
-# F821 undefined name 'Foo'
-# F822 undefined name name in __all__
-# F823 local variable name … referenced before assignment
-# F831 duplicate argument name in function definition
-# F841 local variable 'foo' is assigned to but never used
-# W191 indentation contains tabs
-# W291 trailing whitespace
-# W292 no newline at end of file
-# W293 blank line contains whitespace
-# W504 line break after binary operator
-# W601 .has_key() is deprecated, use "in"
-# W602 deprecated form of raising exception
-# W603 "<>" is deprecated, use "!="
-# W604 backticks are deprecated, use "repr()"
-# W605 invalid escape sequence "x"
-# W606 'async' and 'await' are reserved keywords starting with Python 3.7
+enabled=(
+ E101 # indentation contains mixed spaces and tabs
+ E112 # expected an indented block
+ E113 # unexpected indentation
+ E115 # expected an indented block (comment)
+ E116 # unexpected indentation (comment)
+ E125 # continuation line with same indent as next logical line
+ E129 # visually indented line with same indent as next logical line
+ E131 # continuation line unaligned for hanging indent
+ E133 # closing bracket is missing indentation
+ E223 # tab before operator
+ E224 # tab after operator
+ E242 # tab after ','
+ E266 # too many leading '#' for block comment
+ E271 # multiple spaces after keyword
+ E272 # multiple spaces before keyword
+ E273 # tab after keyword
+ E274 # tab before keyword
+ E275 # missing whitespace after keyword
+ E304 # blank lines found after function decorator
+ E306 # expected 1 blank line before a nested definition
+ E401 # multiple imports on one line
+ E402 # module level import not at top of file
+ E502 # the backslash is redundant between brackets
+ E701 # multiple statements on one line (colon)
+ E702 # multiple statements on one line (semicolon)
+ E703 # statement ends with a semicolon
+ E711 # comparison to None should be 'if cond is None:'
+ E714 # test for object identity should be "is not"
+ E721 # do not compare types, use "isinstance()"
+ E741 # do not use variables named "l", "O", or "I"
+ E742 # do not define classes named "l", "O", or "I"
+ E743 # do not define functions named "l", "O", or "I"
+ E901 # SyntaxError: invalid syntax
+ E902 # TokenError: EOF in multi-line string
+ F401 # module imported but unused
+ F402 # import module from line N shadowed by loop variable
+ F403 # 'from foo_module import *' used; unable to detect undefined names
+ F404 # future import(s) name after other statements
+ F405 # foo_function may be undefined, or defined from star imports: bar_module
+ F406 # "from module import *" only allowed at module level
+ F407 # an undefined __future__ feature name was imported
+ F601 # dictionary key name repeated with different values
+ F602 # dictionary key variable name repeated with different values
+ F621 # too many expressions in an assignment with star-unpacking
+ F622 # two or more starred expressions in an assignment (a, *b, *c = d)
+ F631 # assertion test is a tuple, which are always True
+ F701 # a break statement outside of a while or for loop
+ F702 # a continue statement outside of a while or for loop
+ F703 # a continue statement in a finally block in a loop
+ F704 # a yield or yield from statement outside of a function
+ F705 # a return statement with arguments inside a generator
+ F706 # a return statement outside of a function/method
+ F707 # an except: block as not the last exception handler
+ F811 # redefinition of unused name from line N
+ F812 # list comprehension redefines 'foo' from line N
+ F821 # undefined name 'Foo'
+ F822 # undefined name name in __all__
+ F823 # local variable name … referenced before assignment
+ F831 # duplicate argument name in function definition
+ F841 # local variable 'foo' is assigned to but never used
+ W191 # indentation contains tabs
+ W291 # trailing whitespace
+ W292 # no newline at end of file
+ W293 # blank line contains whitespace
+ W504 # line break after binary operator
+ W601 # .has_key() is deprecated, use "in"
+ W602 # deprecated form of raising exception
+ W603 # "<>" is deprecated, use "!="
+ W604 # backticks are deprecated, use "repr()"
+ W605 # invalid escape sequence "x"
+ W606 # 'async' and 'await' are reserved keywords starting with Python 3.7
+)
if ! command -v flake8 > /dev/null; then
echo "Skipping Python linting since flake8 is not installed. Install by running \"pip3 install flake8\""
@@ -88,4 +90,4 @@ elif PYTHONWARNINGS="ignore" flake8 --version | grep -q "Python 2"; then
exit 0
fi
-PYTHONWARNINGS="ignore" flake8 --ignore=B,C,E,F,I,N,W --select=E101,E112,E113,E115,E116,E125,E129,E131,E133,E223,E224,E242,E266,E271,E272,E273,E274,E275,E304,E306,E401,E402,E502,E701,E702,E703,E711,E714,E721,E741,E742,E743,E901,E902,F401,F402,F403,F404,F405,F406,F407,F601,F602,F621,F622,F631,F701,F702,F703,F704,F705,F706,F707,F811,F812,F821,F822,F823,F831,F841,W191,W291,W292,W293,W504,W601,W602,W603,W604,W605,W606 "${@:-.}"
+PYTHONWARNINGS="ignore" flake8 --ignore=B,C,E,F,I,N,W --select=$(IFS=","; echo "${enabled[*]}") "${@:-.}"
diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan
index f0107f1361..d55119b266 100644
--- a/test/sanitizer_suppressions/ubsan
+++ b/test/sanitizer_suppressions/ubsan
@@ -4,7 +4,6 @@ bool:wallet/wallet.cpp
float-divide-by-zero:policy/fees.cpp
float-divide-by-zero:validation.cpp
float-divide-by-zero:wallet/wallet.cpp
-nonnull-attribute:support/cleanse.cpp
unsigned-integer-overflow:arith_uint256.h
unsigned-integer-overflow:basic_string.h
unsigned-integer-overflow:bench/bench.h